refreshToken을 왜 생성하는지 모르시는 분은 이전글을 꼭 읽어주세요
RefreshToken 토큰은 처음 로그인 하는 시점에 DB에 저장되고, accessToken이 만료되면 서버에 요청을 해서 refreshToken을 확인하고 그것도 만료면 다시 login요청을 보내 refreshToken 을 갱신하고 accessToken 을 생성하는 방식이다
public String createRefreshToken(Long userId){
try {
return Jwts.builder()
.setHeaderParam("typ","JWT")
.setSubject(userId.toString())
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis()*1000*60*60*24*7))
.signWith(getSecretKey(),SignatureAlgorithm.HS256)
.compact();
}catch (Exception e){
throw new CustomException(ErrorCode.INVALID_TOKEN);
}
}
refreshToken은 사용자를 편의를 위해 로그인을 계속해야하는 번거러움을 줄이기 위해 식별자는 userId를 넣고 로그인을 하는 시점이 생기고 그럼으로 new Date() 으로 발행시간 expiratation 으로 7일간으로 만료 날짜를 주었습니다.
public boolean validateRefreshToken(String token){
Claims claims = (Claims) Jwts.parserBuilder()
.setSigningKey(getSecretKey())
.build().parseClaimsJws(token);
return !claims.getExpiration().before(new Date());
}
refreshToken 검증 코드 true fasle 로 refreshToken 만료를 확인한다!
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {
private final JwtAuthenticationFilter jwtAuthenticationFilter;
//password 인코더 하기 위해
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable())
.cors(cors-> cors.disable())
.authorizeHttpRequests(auth-> auth
.requestMatchers("/admin/**").hasRole("ADMIN") // 관리자 즉 어드민만 가능함
.requestMatchers("/user/**").hasRole("USER") // user만 가능 admin도 접속 가능할려면 hasanyroles 로 써야함
.requestMatchers("/api/login","/api/signup","/").permitAll() // 모든 사용자가 접속 가능해야함
.anyRequest().authenticated()) //인증 된사용자
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
}
@Component
@RequiredArgsConstructor
public class JwtAuthenticationFilter extends OncePerRequestFilter {
private final JwtUtil jwtUtil;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String authorization = request.getHeader("Authorization");
if(authorization == null || !authorization.startsWith("Bearer ")) {
filterChain.doFilter(request, response);
return;
}
String token = authorization.split(" ")[1];
if(!jwtUtil.validateToken(token)) {
filterChain.doFilter(request,response);
return;
}
String username = jwtUtil.getUserId(token);
ArrayList<GrantedAuthority> authorities = new ArrayList<>();
authorities.add(new SimpleGrantedAuthority("ROLE_" + jwtUtil.getRole(token)));
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(username, null, authorities);
SecurityContextHolder.getContext().setAuthentication(authentication);
filterChain.doFilter(request,response);
}
}
addFilterBefore() 를 사용하면 spring security가 검증내부적으로 검증하기전에 내가 커스텀한 JwtAuthenticationFilter을 검증기반으로 검증을 한다.
github 주소: https://github.com/goForItkang/jwt_login
글 읽어 주셔서감사합니다