jwt 토큰 - java로 생성하기 예제
1.스프링 프로젝트 생성
2.jwt 라이브러리 추가
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
3.Utils 클래스 추가
JsonUtil.java
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import com.fasterxml.jackson.databind.ObjectMapper;
@Component
public class JsonUtil {
@Bean
public ObjectMapper objectMapper() {
return new ObjectMapper();
}
}
JWTException.java
public class JWTException extends RuntimeException {
/**
*
*/
private static final long serialVersionUID = 1L;
public JWTException() {
super();
}
public JWTException(String message, Throwable cause) {
super(message, cause);
}
public JWTException(String message) {
super(message);
}
public JWTException(Throwable cause) {
super(cause);
}
}
4.VO 객체 추가
import java.io.Serializable;
import java.util.List;
public class User implements Serializable{
private static final long serialVersionUID = 1L;
//아이디
private String userId;
//비번
private String password;
//권한
private List<String> authority;
//사용여부
private boolean enabled;
//이름
private String name;
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public List<String> getAuthority() {
return authority;
}
public void setAuthority(List<String> authority) {
this.authority = authority;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User [userId=" + userId + ", password=" + password + ", authority=" + authority + ", enabled=" + enabled
+ ", name=" + name + "]";
}
}
5.JWT 토큰 생성 검증 클래스 추가
JwtService.java
import java.io.UnsupportedEncodingException;
import java.util.Date;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sujin.app.dto.User;
import com.sujin.app.exception.JWTException;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
@Service
public class JwtService{
//비밀키
private static final String ENCRYPT_STRING = "pretty";
//로그
private static final Logger LOGGER = LoggerFactory.getLogger(JwtService.class);
// key
private static final String DATA_KEY = "user";
//매퍼
@Autowired
private ObjectMapper objectMapper;
//[0] User 정보를 이용해서 - JWT 생성
public String createLoginToken(User user) {
//현재시간
long curTime = System.currentTimeMillis();
//[1] Jwts 라이브러리로부터 jwt 생성 - builder 패턴
return Jwts.builder()
.setSubject("Test JWT")
//[2]
//setHeaderParam 메소드를 통해 JWT 헤더가 지닐 정보들을 담는다.
//alg 의 경우는 default 값이 SHA256이므로 따로 설정할 필요는 없다.
//typ 를 셋팅 안해주면 오류 발생한다.
.setHeaderParam("typ", "JWT")
//[3] 만료 시간
.setExpiration(new Date(curTime + 3600000))
//[4] 발급 시간
.setIssuedAt(new Date(curTime))
//[5] Payload 에 Private Claims 를 담기 위해 claim 메소드를 이용한다.
// private claim으로 VO객체를 추가할 수 있음
.claim(DATA_KEY, user)
//[6] 복호화 할때 사용하는 시그니처 설정.
// header의 인코딩값 + payload의 인코딩값 + 비밀키 = 시그니처
// signWith api는 해싱알고리즘과 비밀키가 필요하다.
.signWith(SignatureAlgorithm.HS256, this.generateKey())
//생성
.compact();
//"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2MTQ5MzMwMzcsImlhdCI6MTYxNDkyOTQzNywidXNlciI6eyJ1c2VySWQiOiJzdWppbiIsInBhc3N3b3JkIjpudWxsLCJhdXRob3JpdHkiOlsiVVNFUiJdLCJlbmFibGVkIjpmYWxzZSwibmFtZSI6IuydtOyImOynhCJ9fQ.FsP6XGQ2tLJ9kO8NZMOP3OtZu69YK1vxWhNK4XGyEmU";
}
//비밀키 생성 메소드
private byte[] generateKey(){
byte[] key = null;
try {
//ENCRYPT_STRING = pretty
key = ENCRYPT_STRING.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
LOGGER.error("Making secret Key Error :: ", e);
}
System.out.println("비밀 key : " + key); //[B@59252cb6
return key;
}
//JWT 복호화
public User getUser(String jwt) {
//결과값 = Claims
Jws<Claims> claims = null;
try {
//비밀키를 이용해서 복호화 하는 작업
//jwt가 유효한지, 위변조 되지 않았는지 판단한다.
//이 비밀키는 서버에만 존재해야되고, 유출되어서는 안된다.
claims = Jwts.parser()
.setSigningKey(this.generateKey())
.parseClaimsJws(jwt);
} catch (Exception e) {
LOGGER.debug(e.getMessage(), e);
throw new JWTException("decodeing failed");
}
//반환 타입은 LinkedHashMap 이다. 이를 User 타입으로 변환하기 위해 ObjectMapper 사용
return objectMapper.convertValue(claims.getBody().get(DATA_KEY), User.class);
}
}
6.호출
import java.util.Arrays;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import com.sujin.app.dto.User;
import com.sujin.app.service.JwtService;
@SpringBootApplication
public class SpringbootJwtExampleApplication implements CommandLineRunner{
@Autowired
private JwtService jwtService;
private static final Logger LOGGER = LoggerFactory.getLogger(SpringbootJwtExampleApplication.class);
public static void main(String[] args) {
SpringApplication.run(SpringbootJwtExampleApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
// User u = new User();
// u.setUserId("sujin");
// u.setName("kimdongyuel");
// u.setAuthority(Arrays.asList("USER"));
//
//
// LOGGER.debug("creating jwt...");
//
// String token = jwtService.createLoginToken(u);
// LOGGER.debug("jwt 생성 :" + token);
// // jwt 생성 :eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2MTQ5MzMwMzcsImlhdCI6MTYxNDkyOTQzNywidXNlciI6eyJ1c2VySWQiOiJzdWppbiIsInBhc3N3b3JkIjpudWxsLCJhdXRob3JpdHkiOlsiVVNFUiJdLCJlbmFibGVkIjpmYWxzZSwibmFtZSI6IuydtOyImOynhCJ9fQ.FsP6XGQ2tLJ9kO8NZMOP3OtZu69YK1vxWhNK4XGyEmU
//
String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2MTQ5MzMwMzcsImlhdCI6MTYxNDkyOTQzNywidXNlciI6eyJ1c2VySWQiOiJzdWppbiIsInBhc3N3b3JkIjpudWxsLCJhdXRob3JpdHkiOlsiVVNFUiJdLCJlbmFibGVkIjpmYWxzZSwibmFtZSI6IuydtOyImOynhCJ9fQ.FsP6XGQ2tLJ9kO8NZMOP3OtZu69YK1vxWhNK4XGyEmU";
LOGGER.debug("jwt decoding... ");
User user = jwtService.getUser(token);
LOGGER.debug("디코드된 jwt : " + user);
}
}
참고
- JWT를 생성할 때와 복호화할 때의 비밀키를 다르게 설정: SignatureException 발생
- 위조한 JWT에 대해 복호화를 시도: MalformedJwtException 발생
- 만료기간이 지난 JWT에 대해 복호화를 시도: ExpiredJwtException 발생
참고 블로그
https://bamdule.tistory.com/123
https://medium.com/@OutOfBedlam/jwt-%EC%9E%90%EB%B0%94-%EA%B0%80%EC%9D%B4%EB%93%9C-53ccd7b2ba10
Refresh token은 필요한가? : https://zzossig.io/posts/etc/what_is_the_point_of_refresh_token
[Spring Security] OAuth2 방식으로 JWT사용해보기(accesstoken, refreshtoken) : https://fenderist.tistory.com/353
'웹개발 > 보안' 카테고리의 다른 글
JWT - JSON Web Token 이란 - 개념 (0) | 2021.03.05 |
---|---|
카카오 로그인 OAuth2.0 - 사용자 정보 조회 (0) | 2020.12.08 |
카카오 로그인 OAuth2.0 (0) | 2020.12.08 |
OAuth2 인증 - 인가 코드 그랜트 (0) | 2020.12.05 |
OAuth2 인증 - 암시적 코드 그랜트 (0) | 2020.12.05 |