@RequiredArgsConstructor
@Service
public class TokenProvider {
@Value("${jwt.issuer}")
private String issuer;
@Value("${jwt.secret_key}")
private String secretKey;
public String generateToken(User user, Duration expiredAt){
Date now = new Date();
return makeToken(new Date(now.getTime()+expiredAt.toMillis()), user);
}
// 1.JWT 토큰 생성
private String makeToken(Date expiry, User user){
Date now = new Date();
return Jwts.builder()
.setHeaderParam(Header.TYPE, Header.JWT_TYPE) // 헤더 typ : JWT .setIssuer(issuer) // 내용 iss : mail .setIssuedAt(now) // 내용 iat : 현재 시간
.setExpiration(expiry) // 내용 exp : expiry 멤버 변숫값
.setSubject(user.getEmail()) // 내용 sub : 유저 이메일
.claim("id", user.getId()) // 클레임 id : 유저 ID
.signWith(SignatureAlgorithm.HS256, secretKey) // 서명 : 비밀값과 해시값을 HS256 방식으로 암호화
.compact();
}
// 2. JWT 토큰 유효성 검증 메서드
public boolean validToken(String token){
try{
Jwts.parser()
.setSigningKey(secretKey) // 비밃값으로 복호화
.parseClaimsJws(token);
return true;
}catch (Exception e) { // 복호화 과정에서 에러 나면 유효하지 않은 토큰
return false;
}
}
// 3. 토큰 기반 인증 정보 가져오는 메서드
public Authentication getAuthentication(String token){
Claims claims = getClaims(token);
Set<SimpleGrantedAuthority> authorities = Collections.singleton(new SimpleGrantedAuthority("ROLE_USER"));
return new UsernamePasswordAuthenticationToken(new org.springframework.security.core.userdetails.User(claims.getSubject(),
"", authorities),token, authorities);
}
// 4. 토큰 기반으로 유저ID 가져오는 메서드
public Long getUserId(String token){
Claims claims = getClaims(token);
return claims.get("id", Long.class);
}
private Claims getClaims(String token) {
return Jwts.parser()
.setSigningKey(secretKey)
.parseClaimsJws(token)
.getBody();
}
@RequiredArgsConstructor
@Service
public class TokenProvider{
private final 토큰 제공자
public String 토큰발급(User user, Duration expiredAt){
Date now = new Date(); // 유효 기간 설정 목적
return 토큰생성(new Date(now.getTime() + expiredAt.toMillis()), user);
}
public String 토큰생성(Date expiry, User user){
Date now = new Date();
return Jwts.builder() // 필요한 정보 설정
...
.compact();
}
public boolean 유효성 검증(String token){
try{
Jwts.parser()
.비밀키 복호화
.토큰 jws로 파싱
return true
}catch (Exception e){
return false
}
}
public Authentication 인증정보(String token){
클레임 = 클레임가져오기(token);
인증정보
return 이메일, 토큰, 인증정보
}
public Long 유저Id(String token){
클레임 = 클레임가져오기(token);
return 클레임.get("id", Long.class);
}
public Claims 클레임가져오기(String){
return Jwts.parser()
.setSigningKey(토큰제공자.getSecretKey())
.parserClaimsJws(token)
.getBody();
}
}
package com.example.api.security.util;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.impl.DefaultClaims;
import io.jsonwebtoken.impl.DefaultJws;
import lombok.extern.log4j.Log4j2;
import java.time.ZonedDateTime;
import java.util.Date;
@Log4j2
public class JWTUtil {
private String secretKey = "test1234";
// 1Month
private long expire = 60*24*30;
// JWT 토큰 생성
public String generateToken(String content) throws Exception{
return Jwts.builder()
.setIssuedAt(new Date())
// .setExpiration(Date.from(ZonedDateTime.now().plusSeconds(1).toInstant())) // Exception 발생
.setExpiration(Date.from(ZonedDateTime.now().plusMinutes(expire).toInstant()))
.claim("sub", content)
.signWith(SignatureAlgorithm.HS256, secretKey.getBytes("UTF-8"))
.compact();
}
// JWT 문자열 검증 (인코딩된 문자열에서 원하는 값 추출)
public String validateAndExtract(String tokenStr) throws Exception{
String contentValue = null;
try{
DefaultJws defaultJws = (DefaultJws) Jwts.parser().setSigningKey(secretKey.getBytes("UTF-8")).parseClaimsJws(tokenStr);
log.info(defaultJws);
log.info(defaultJws.getBody().getClass());
DefaultClaims claims = (DefaultClaims) defaultJws.getBody();
log.info("=".repeat(30));
contentValue = claims.getSubject();
}catch(Exception e){
e.printStackTrace();
log.error(e.getMessage());
contentValue=null;
}
return contentValue;
}
}
@Value("${jwt.issuer}")
private String issuer;
@Value("${jwt.secret_key}")
private String secretKey;
// JWT 생성
public String generateToken(User user, Duration expiredAt){
Date date = new Date();
return makeToken(new Date(now.getTime() + expiredAt.toMillis()), user);
}
public String makeToken(Date expiry, User user){
Date now = new Date();
return Jwts.builder()
.setHeaderParam(Header.TYPE, Header.JWT_TYPE)
.setIssuer(issuer)
.setIssuedAt(now)
.setExpiration(expiry)
.setSubject(user.getEmail())
.clain("id", user.getId())
.signWith(SignatureAlgorithm.HS256, secretKey)
.compact();
}
private String secretKey = "test123";
// 1Month
Private Long expire = 60*24*30;
// JWT 생성
public String generateToken(String content) throws Exception{
return Jwts.builder()
.setIssuedAt(new Date)
.setExpiration(Date.from(ZoneDateTime.now().plusMinutes(expire).toInstant()))
.calim("sub", content) // content == user.getEmail
.signWith(SignatureAlgorithm.HS256, secretKey.getBytes("UTF-8"))
.compact();
}
- 개발자 되기 :
makeToken
통해 토큰 생성한 뒤generateToken
으로 만료 기간 지정하는 방법- 코드로 배우는 ~ :
generateToken
통해 사용할 만료 기간까지 한 번에 설정하는 방법객체 분리를 위해서는 전자의 방법이 좋지만, 실제 사용시 후자의 방법이 조금 더 간편하지 않을까 생각된다.
public boolean validToken(String token){
try{
Jwts.parser()
.setSigningKey(secretKey) // 비밀값으로 복호화
.parseClaimsJws(token);
return true;
}catch (Exception e){ // 위 과정에서 오류 발생시 유효하지 않은 토큰
return false;
}
}
// 토큰 기반 인증 정보 가져오는 메서드
public Authentication getAuthentication(String token){
Claims claims = getClaims(token);
Set<SimpleGrantedAuthority> authorities = Collections.singleton(new SimpleGrantedAuthority("ROLE_USER"));
Return new UsernamePasswordAuthenticationToken(new User(claims.getSubject(), "", authorities), token, authorities); // 유저 이메일(sub), 패스워드, 인가정보 등을 기반으로 인증 정보 생성
}
// 토큰 기반 유저ID 가져오는 메서드
public Long userId(String token){
Claims claims = getClaims(token);
return claims.get("id", Long.class);
}
private Claims getClaims(String token){
return Jwts.parser()
.setSigningKey(secretKey)
.parserClaimsJws(token)
.getBody();
}
public String validateAndExtract(String tokenStr) throws Exceptions{
String contentValue = null;
try{
DefaultJws defaultJws = (DefaultJws) Jwts.parser()
.setSigningKey(secretKeys.getBytes("UTF-8"))
.parseClaimsJws(tokenStr);
log.info(defaultJws);
log.info(defaultJws.getBody().getClass());
DefaultClaims claims = (DefaultClaims) defaultJws.getBody();
contentValue = claims.getSubject(); // 사용자 이메일(unique)
}catch (Exception e){
e.printStackTrace();
log.error(e.getMessage());
contentValue=null
}
return contentValue;
}
public class DefaultJws<B> implements Jws<B> {
private final JwsHeader header;
private final B body;
private final String signature;
public DefaultJws(JwsHeader header, B body, String signature) {
this.header = header;
this.body = body;
this.signature = signature;
}
@Override
public JwsHeader getHeader() {
return this.header;
}
@Override
public B getBody() {
return this.body;
}
@Override
public String getSignature() {
return this.signature;
}
@Override
public String toString() {
return "header=" + header + ",body=" + body + ",signature=" + signature;
}
}
- DefaultJws는
header
,body
,signature
로 구성된 클래스
// 토큰 기반 인증 정보 가져오는 메서드
public Authentication getAuthentication(String token){
Claims claims = getClaims(token);
Set<SimpleGrantedAuthority> authroires = Collections.singleton(new SimpleGratnedAuthority("ROLE_USER"));
return new UsernamePasswordAuthenticationToken(new User(claims.getSubject,"",authroities), token, authorities);
}
// 유저 ID
public Long getUserId(String token){
Claims claims = getClaims(token);
return claims.get("id", Long.class);
}
private Claims getClaims(String token){
return Jwts.parser()
.setSigningKey(secretKey)
.parseClaimsJws(token)
.getBody();
}
public String validtedAndExtract(String token) throws Exception{
try{
DefaultJws defaultJws = (DefaultJws) Jwts.parser()
.setSigningKey(secretKey.getBytes("UTF-8"))
.parseClaimsJws(tokenStr);
DefaultClaims claims = (DefaultClaims) defaultJws.getBody();
contentValue = claims.getSubject();
}catch(Exception e){
...
}
return contentValue
}
2번째 방법은 검증 및 값 추출이 동시에 가능하므로 더 효율적으로 보임.