简体   繁体   English

如何为整个Spring Boot应用程序生成令牌

[英]How generate token for entire spring boot application

I have a REST API which consumes an external API. 我有一个使用外部API的REST API。 I am using WebClient, but I have to pass a token with each request to the external API. 我正在使用WebClient,但必须将每个请求的令牌传递给外部API。 The token is generated through an addAuthentication POST call. 令牌是通过addAuthentication POST调用生成的。 I want to use the same token within the entire application, until it gets expired as; 我想在整个应用程序中使用相同的令牌,直到它过期为止; this is an application specific token. 这是一个特定于应用程序的令牌。 But I am not sure how to generate the token to be available in my entire application, for use in all http requests. 但是我不确定如何生成在我的整个应用程序中可用的令牌,以用于所有http请求。

I tried to instantiate a connector class and used in @PostConstruct in my spring boot application class; 我试图实例化一个连接器类,并在我的Spring Boot应用程序类的@PostConstruct中使用了它; but I am not sure how to access this instance within all the application. 但我不确定如何在所有应用程序中访问此实例。

   @Component
   public class AppConnector {
     @Value("${some.dev.url}")
     private String baseUrl;
     @Value("${some.dev.appid}")
     private String appId;
     @Value("${some.dev.username}")
     private String username;
     @Value("${some.dev.password}")
     private String password;   
     private String token;  
     private boolean isConnected;   
     private final WebClient webClient;


  @Autowired
  public AppConnector(WebClient webClient) {
      this.webClient = WebClient.builder()
              .baseUrl("http://localhost:8080/api")
              .defaultHeader("application-id", "client-01")
              .defaultHeader("username", username)
              .defaultHeader("password", password)
              .build();
  }

/***
 * Method to add Authentication
 * @return Session_Token: String
 */
public String addAuthentication() {

    AddAuthenticationOutputVO response = null;
    response = this.webClient.post()
            .uri("/authentication?version=1.0")
            .retrieve()
            .bodyToMono(AddAuthenticationOutputVO.class).block();

    this.token = response.getSession_token();
    return response.getSession_token();
}

}

One solution is to use JWT signed and issued by the main application, and both system must have the main key secret. 一种解决方案是使用由主应用程序签名和发布的JWT,并且两个系统都必须具有主密钥机密。 The verification can be a simple token verification, and you can find the userId or userName inside the JWT. 验证可以是简单的令牌验证,您可以在JWT中找到userId或userName。 The expiration is inside the JWT so every time the token is verified the system can know if the token has expired or not and you can answer to the client as expired token. 到期时间在JWT内部,因此每次验证令牌后,系统都可以知道令牌是否已过期,并且您可以作为过期令牌来答复客户端。

This solution with Spring is implement two filters, Authentication to generate the token, and Authorization to verify the token. 使用Spring的此解决方案实现了两个过滤器:用于生成令牌的身份验证和用于验证令牌的授权。

Here is the sample code. 这是示例代码。

Authentication: 认证方式:

public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

    private final AuthenticationManager authenticationManager;
    private final String maxSizeToUpload;

    public JWTAuthenticationFilter(AuthenticationManager authenticationManger, String maxSizeToUpload) {
        this.authenticationManager = authenticationManger;
        this.maxSizeToUpload = maxSizeToUpload;
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, 
            HttpServletResponse response) throws AuthenticationException {
        try {
            AuthenticationRequest authRequest = new ObjectMapper().readValue(request.getInputStream(), 
                    AuthenticationRequest.class);
            return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(
                    authRequest.getUsername(), authRequest.getPassword(), new ArrayList<>()));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response,
            FilterChain chain, Authentication auth) throws IOException, ServletException {
        // Los tokens son generados hasta el final del día.
        Date expirationDate = DateUtil.setZeroHour(DateUtil.getDateAddDays(new Date(), 1));

        String token = Jwts.builder().setIssuedAt(new Date()).setIssuer(WebSecurity.ISSUER)
                .setSubject(((BuserDetails)auth.getPrincipal()).getUsername())
                .setExpiration(expirationDate)
                .signWith(SignatureAlgorithm.HS512, HardCodeUtil.JWT_KEY).compact();
        response.addHeader(WebSecurity.HEADER_AUTHORIZATION, WebSecurity.PREFIX_JWT + token);
        response.addHeader(WebSecurity.HEADER_JWT_EXPIRATION_DATE, String.valueOf(expirationDate.getTime()));
        ObjectMapper mapper = new ObjectMapper();
        ExtraParams extraParams = new ExtraParams(
                ((BuserDetails)auth.getPrincipal()).getBuser().getBusiness().getCurrency(),
                Byte.parseByte(maxSizeToUpload.replace("MB", "")));
        String body = mapper.writeValueAsString(new LoginResponse(((BuserDetails)auth.getPrincipal()).getBuser(),
                extraParams));
        response.setContentType("application/json");
        response.getWriter().write(body);
        response.getWriter().flush();
        response.getWriter().close();
    }

}

Authorization: 授权:

This must be used in both system and you can find the JWT_KEY as I used, you need to share that value in both systems. 这必须在两个系统中都使用,并且您可以找到我所使用的JWT_KEY,因此需要在两个系统中共享该值。

public class JWTAuthorizationFilter extends BasicAuthenticationFilter {

    private static final Logger log = Logger.getLogger(JWTAuthorizationFilter.class.getName());

    public JWTAuthorizationFilter(AuthenticationManager authManager) {
        super(authManager);
    }

    @Override
    protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain)
            throws IOException, ServletException {
        String header = req.getHeader(WebSecurity.HEADER_AUTHORIZATION);
        if (header == null || !header.startsWith(WebSecurity.PREFIX_JWT)) {
            chain.doFilter(req, res);
            return;
        }
        try {
            UsernamePasswordAuthenticationToken authentication = getAuthentication(req);
            SecurityContextHolder.getContext().setAuthentication(authentication);
            chain.doFilter(req, res);
        }catch (SignatureException ex) {
            log.log(Level.SEVERE, "FIRMA INVALIDA DEL JWT ENVIADO");
        }catch (MalformedJwtException ex) {
            log.log(Level.SEVERE, "ESTRUCTURA INVALIDA DEL JWT ENVIADO");
        }catch (ExpiredJwtException ex) {
            GeneralResponse jwtInvalidResponse = new GeneralResponse(ErrorsEnum.JWT_EXPIRED);
            ObjectMapper mapper = new ObjectMapper();
            String body = mapper.writeValueAsString(jwtInvalidResponse);
            res.setContentType("application/json");
            res.getWriter().write(body);
            res.getWriter().flush();
            res.getWriter().close();
        }catch (UnsupportedJwtException ex) {
            log.log(Level.SEVERE, "NO SOPORTADO JWT ENVIADO");
        }catch (IllegalArgumentException ex) {
            log.log(Level.SEVERE, "ILLEGAL ARGUMENT JWT ENVIADO");
        }
    }

    private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
        String token = request.getHeader(WebSecurity.HEADER_AUTHORIZATION);
        if (token != null) {
            String user = Jwts.parser()
                    .setSigningKey(HardCodeUtil.JWT_KEY)
                    .parseClaimsJws(token.replace(WebSecurity.PREFIX_JWT, ""))
                    .getBody()
                    .getSubject();
            if (user != null) {
                return new UsernamePasswordAuthenticationToken(user, null, new ArrayList<>());
            }
        }
        return null;
    }

}

In the example I have implemented with this library: 在示例中,我已使用此库实现了:

<dependency>
     <groupId>io.jsonwebtoken</groupId>
     <artifactId>jjwt</artifactId>
     <version>0.9.1</version>
</dependency>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM