Spring

Spring 보안에서 토큰을 새로 고치는 방법

기록만이살길 2022. 11. 7. 19:13
반응형

Spring Security에서 토큰을 새로 고치는 방법 물어보다

1. 질문(문제점):

이 줄:

Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody();

내 jwt 토큰이 만료되면 다음과 같은 오류가 발생합니다.

JWT는 2020-05-13T07:50:39Z에 만료되었습니다. 현재 시간: 2020-05-16T21:29:41Z.

보다 구체적으로, "ExpiredJwtException" 예외를 발생시키는 것은 이 함수입니다. parseClaimsJws() 함수

이러한 예외를 처리하려면 어떻게 해야 합니까? 그들을 잡아서 클라이언트에 다시 오류 메시지를 보내고 강제로 다시 로그인해야 합니까?

새로 고침 토큰 기능을 구현하려면 어떻게 해야 합니까? 저는 백엔드에서 Spring과 mysql을, 프론트엔드에서 vuejs를 사용하고 있습니다.

다음과 같이 초기 토큰을 생성합니다.

   @Override
        public JSONObject login(AuthenticationRequest authreq) {
            JSONObject json = new JSONObject();
    
            try {
                Authentication authentication = authenticationManager.authenticate(
                        new UsernamePasswordAuthenticationToken(authreq.getUsername(), authreq.getPassword()));
    
                UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal();
                List<String> roles = userDetails.getAuthorities().stream().map(item -> item.getAuthority())
                        .collect(Collectors.toList());
    
                if (userDetails != null) {
    
                    final String jwt = jwtTokenUtil.generateToken(userDetails);
    
    
                    JwtResponse jwtres = new JwtResponse(jwt, userDetails.getId(), userDetails.getUsername(),
                            userDetails.getEmail(), roles, jwtTokenUtil.extractExpiration(jwt).toString());
    
                    return json.put("jwtresponse", jwtres);
                }
            } catch (BadCredentialsException ex) {
                json.put("status", "badcredentials");
            } catch (LockedException ex) {
                json.put("status", "LockedException");
            } catch (DisabledException ex) {
                json.put("status", "DisabledException");
            }
    
            return json;
        }

그런 다음 JwtUtil 클래스에서:

   public String generateToken(UserDetails userDetails) {
            Map<String, Object> claims = new HashMap<>();
            return createToken(claims, userDetails.getUsername());
        }
    
   private String createToken(Map<String, Object> claims, String subject) {
            return Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(new Date(System.currentTimeMillis()))
                    .setExpiration(new Date(System.currentTimeMillis() + EXPIRESIN))
                    .signWith(SignatureAlgorithm.HS256, SECRET_KEY).compact();
        }

자세한 내용은 모든 요청을 필터링하는 doFilterInternal 함수입니다.

   @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException, ExpiredJwtException, MalformedJwtException {

        try {

            final String authorizationHeader = request.getHeader("Authorization");

            String username = null;
            String jwt = null;

            if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
                jwt = authorizationHeader.substring(7);
                username = jwtUtil.extractUsername(jwt);
            }

            if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
                UserDetails userDetails = userService.loadUserByUsername(username);

                boolean correct = jwtUtil.validateToken(jwt, userDetails);

                if (correct) {
                    UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
                            userDetails, null, userDetails.getAuthorities());

                    usernamePasswordAuthenticationToken
                            .setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                    SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);

                }
            }

            chain.doFilter(request, response);
        } catch (ExpiredJwtException ex) {
            resolver.resolveException(request, response, null, ex);
        }
    } 

2. 해결방안:

다음과 같이 새로 고침 토큰을 가져오는 API를 호출할 수 있습니다.

POST https://yourdomain.com/oauth/token 

Header
  "Authorization": "Basic [base64encode(clientId:clientSecret)]" 

Parameters
  "grant_type": "refresh_token"
  "refresh_token": "[yourRefreshToken]"

유의하시기 바랍니다,

  • base64encode 는 클라이언트 인증을 암호화하는 방법입니다. https://www.base64encode.org/ 에서 온라인으로 사용할 수 있습니다.
  • refresh_tokengrant_type 의 문자열 값입니다.
  • yourRefreshTokenJWT 액세스 토큰 과 함께 수신 된 새로 고침 토큰 입니다.

결과는 다음과 같이 볼 수 있습니다.

{
    "token_type":"bearer",
    "access_token":"eyJ0eXAiOiJK.iLCJpYXQiO.Dww7TC9xu_2s",
    "expires_in":20,
    "refresh_token":"7fd15938c823cf58e78019bea2af142f9449696a"
}

행운을 빕니다.

63426347
반응형