public class JwtTokenProvider {
// ** JWT 토큰의 만료 시간을 1시간으로 설정.
private static final Long EXP = 1000L * 60 * 60;
// ** 인증 헤더에 사용될 토큰의 접두어 ("Bearer ")
public static final String TOKEN_PREFIX = "Bearer ";
// ** 인증 헤더의 이름을 "Authorization"으로 설정.
public static final String HEADER = "Authorization";
// ** 토큰의 서명을 생성하고 검증할 때 사용하는 비밀 키
private static final String SECRET = "SECRET_KEY";
// ** User 객체의 정보를 사용해 JWT 토큰을 생성하고 반환.
public static String create(User user) {
// ** StringArrayConverter 객체 생성
StringArrayConverter stringArrayConverter = new StringArrayConverter();
// ** User의 권한 정보를 String 로 변경
String roles = stringArrayConverter.convertToDatabaseColumn(
user.getRoles()
);
String jwt = JWT.create()
.withSubject(user.getEmail()) // ** 토큰의 대상정보 셋팅
.withExpiresAt(new Date(System.currentTimeMillis() + EXP)) // ** 시간 설정
.withClaim("id", user.getId()) // ** id설정
.withClaim("roles", roles) // ** 권한정보 설정
.sign(Algorithm.HMAC512(SECRET)); // ** jwt 생성 알고리즘 설정
return TOKEN_PREFIX + jwt;
}
// ** JWT 토큰 문자열을 검증하고, 유효하다면 디코딩된 DecodedJWT 객체를 반환.
public static DecodedJWT verify(String jwt) throws SignatureVerificationException, TokenExpiredException {
// ** 토큰 검증을 시작.
DecodedJWT decodedJWT = JWT.require(Algorithm.HMAC512(SECRET))
.build()
.verify(jwt);
return decodedJWT;
}
}
참고
DecodedJWT decodedJWT = JwtTokenProvider.verify(jwt); String userEmail = decodedJWT.getSubject(); // 사용자 이메일 String userRoles = decodedJWT.getClaim("roles").asString(); // 사용자 권한
해당 방법으로 사용자 이메일과 사용자 권한을 읽어올수 있다.
@Slf4j
public class JwtAuthenticationFilter extends BasicAuthenticationFilter {
public JwtAuthenticationFilter(AuthenticationManager authenticationManager) {
super(authenticationManager);
}
// ** Http 요청이 발생할 때마다 호출되는 메서드.
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws IOException, ServletException {
String prefixJwt = request.getHeader(JwtTokenProvider.HEADER);
// ** 헤더가 없다면 더이상 이 메서드에서 할 일은 없음. 다음으로 넘김.
if(prefixJwt == null) {
chain.doFilter(request, response);
return;
}
// ** Bearer 제거.
String jwt = prefixJwt.replace(JwtTokenProvider.TOKEN_PREFIX, "");
try {
log.debug("토근 있음.");
// ** 토큰 검증
DecodedJWT decodedJWT = JwtTokenProvider.verify(jwt);
// ** 사용자 정보 추출.
int id = decodedJWT.getClaim("id").asInt();
String roles = decodedJWT.getClaim("roles").asString();
// ** 권한 정보를 문자열 리스트로 변환.
StringArrayConverter stringArrayConverter = new StringArrayConverter();
List<String> rolesList = stringArrayConverter.convertToEntityAttribute(roles);
// ** 추출한 정보로 유저를 생성.
User user = User.builder().id(id).roles(rolesList).build();
CustomUserDetails customUserDetails = new CustomUserDetails(user);
// ** Spring Security 가 인증 정보를 관리하는데 사용.
Authentication authentication = new UsernamePasswordAuthenticationToken(
customUserDetails,
customUserDetails.getPassword(),
customUserDetails.getAuthorities()
);
// ** SecurityContext에 저장.
SecurityContextHolder.getContext().setAuthentication(authentication);
log.debug("인증 객체 생성");
}
catch (SignatureVerificationException sve) {
log.debug("토큰 검증 실패");
}
catch (TokenExpiredException tee) {
log.debug("토큰 사용 만료");
} finally {
// ** 필터로 응답을 넘긴다.
chain.doFilter(request, response);
}
}
}