簡體   English   中英

如何為整個Spring Boot應用程序生成令牌

[英]How generate token for entire spring boot application

我有一個使用外部API的REST API。 我正在使用WebClient,但必須將每個請求的令牌傳遞給外部API。 令牌是通過addAuthentication POST調用生成的。 我想在整個應用程序中使用相同的令牌,直到它過期為止; 這是一個特定於應用程序的令牌。 但是我不確定如何生成在我的整個應用程序中可用的令牌,以用於所有http請求。

我試圖實例化一個連接器類,並在我的Spring Boot應用程序類的@PostConstruct中使用了它; 但我不確定如何在所有應用程序中訪問此實例。

   @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();
}

}

一種解決方案是使用由主應用程序簽名和發布的JWT,並且兩個系統都必須具有主密鑰機密。 驗證可以是簡單的令牌驗證,您可以在JWT中找到userId或userName。 到期時間在JWT內部,因此每次驗證令牌后,系統都可以知道令牌是否已過期,並且您可以作為過期令牌來答復客戶端。

使用Spring的此解決方案實現了兩個過濾器:用於生成令牌的身份驗證和用於驗證令牌的授權。

這是示例代碼。

認證方式:

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();
    }

}

授權:

這必須在兩個系統中都使用,並且您可以找到我所使用的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;
    }

}

在示例中,我已使用此庫實現了:

<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