반응형
gradle 설정
implementation 'io.jsonwebtoken:jjwt-api:0.11.5'
implementation 'io.jsonwebtoken:jjwt-impl:0.11.5'
implementation 'io.jsonwebtoken:jjwt-jackson:0.11.5'
JwtTokenProvider 생성
import java.security.Key;
import java.util.Base64;
import java.util.Date;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.UnsupportedJwtException;
import io.jsonwebtoken.security.Keys;
import lombok.extern.log4j.Log4j2;
@Log4j2
@Component
public class JwtTokenProvider implements InitializingBean{
private final String secret;
private final long tokenValidmils;
private Key key;
public JwtTokenProvider(@Value("${jwt.secret}") String secret, @Value("${jwt.validSeconds}") Long validSeconds) {
this.secret = secret;
this.tokenValidmils = validSeconds * 1000;
}
/*
* token 생성에 사용될 key 생성
*/
@Override
public void afterPropertiesSet() throws Exception {
byte[] keyBytes = Base64.getDecoder().decode(secret);
this.key = Keys.hmacShaKeyFor(keyBytes);
}
/*
* token 생성
*/
public String generateTokenString(String id) {
Date now = new Date();
Date expDate = new Date(now.getTime() + tokenValidmils);
return Jwts.builder()
.setSubject(id)
.setIssuedAt(new Date())
.setExpiration(expDate)
.signWith(key, SignatureAlgorithm.HS512)
// .signWith( SignatureAlgorithm.HS512, key) //Deprecated
.compact();
}
public boolean validateToken(String token) {
try {
Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token);
// Jwts.parser().setSigningKey(key).parseClaimsJws(token); //Deprecated
return true;
} catch (io.jsonwebtoken.security.SecurityException | MalformedJwtException e) {
log.info("잘못된 JWT 서명입니다.");
} catch (ExpiredJwtException e) {
log.info("만료된 JWT 토큰입니다.");
} catch (UnsupportedJwtException e) {
log.info("지원되지 않는 JWT 토큰입니다.");
} catch (IllegalArgumentException e) {
log.info("JWT 토큰이 잘못되었습니다.");
}
return false;
}
/*
* token에서 id 추출
*/
public Authentication getAuthenticateAction(String token) {
Claims claims = (Claims) Jwts.parserBuilder()
.setSigningKey(key)
.build()
.parse(token)
.getBody();
log.info("get authentication from token : " + claims);
// Jwts.parser().setSigningKey(key).parseClaimsJws(token).getBody(); //Deprecated
return new UsernamePasswordAuthenticationToken(claims.getSubject(), token, null);
}
}
JwtFilter 생성
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.GenericFilter;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.StringUtils;
import lombok.extern.log4j.Log4j2;
@Log4j2
public class JwtAuthenticationFilter extends GenericFilter{
public static final String AUTHORIZATION_HEADER = "Authorization";
private JwtTokenProvider tokenProvider;
public JwtAuthenticationFilter(JwtTokenProvider tokenProvider) {
this.tokenProvider = tokenProvider;
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
String jwt = resolveToken(httpServletRequest);
String requestURI = httpServletRequest.getRequestURI();
if (StringUtils.hasText(jwt) && tokenProvider.validateToken(jwt)) {
Authentication authentication = tokenProvider.getAuthenticateAction(jwt);
SecurityContextHolder.getContext().setAuthentication(authentication);
} else {
log.debug("유효한 JWT 토큰이 없습니다, uri: {}", requestURI);
}
chain.doFilter(request, response);
}
private String resolveToken(HttpServletRequest request) {
String bearerToken = request.getHeader(AUTHORIZATION_HEADER);
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
return bearerToken.substring(7);
}
return null;
}
}
Security에 Filter 적용
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.cors().and()
.csrf().disable()
.addFilterBefore(new JwtAuthenticationFilter(tokenProvider), UsernamePasswordAuthenticationFilter.class)
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.
.
.
.
.
.
.
Controller에서 사용자 인증 후 토큰 생성
// id로 jwt token 생성
String jwtToken = jwtTokenProvider.generateTokenString(id);
토큰 체크 후에는 Principal 객체 통해 사용자 정보 get
반응형
'개발 > java_spring' 카테고리의 다른 글
[JPA] native query 에서 @변수 사용 시 오류 (0) | 2023.01.10 |
---|---|
[Spring Boot] JPA native query to dto throw error (0) | 2022.12.19 |
[Spring boot] JPA hibernate second level cache with redisson (0) | 2022.12.01 |
[Spring Boot] log4j2, hibernate 설정 (0) | 2022.10.25 |
[Spring Boot]JPA @query null Parameter (0) | 2022.10.18 |