배경: E-commerce 프로젝트를 만들면서 seller와 client 프로젝트를 분리하여 모듈프로젝트를 만드는 상황에서
인증토큰은 같이 사용하게 만들고 싶었다! 각각의 프로젝트에 인증토큰 서비스를 다 만드는건 비효율적이니까!
1. 인증토큰을 공통으로 사용하게 될 모듈 프로젝트를 생성한다.
아래 포스팅을 참고해주세요!
https://seultories.tistory.com/30
[spring boot]멀티 모듈 프로젝트 생성하는 방법
[참고] https://techblog.woowahan.com/2637/ 내가 생성하려고 하는 건 이커머스라는 상위 프로젝트(루트) 내에 1. user api 프로젝트 2. seller api 프로젝트 로 총 3가지의 스프링 부트 프로젝트를 생성하여 멀티
seultories.tistory.com
2. 모듈 프로젝트 build.gradle 내에 jwt와 룸복 의존성을 추가해준다.
dependencies {
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
implementation 'io.jsonwebtoken:jjwt:0.9.1'
}
***추가된 의존성 코드가 있습니다.(2023년 9월 12일 기준)
아래의 포스팅 확인해주세요!
https://seultories.tistory.com/34
[JWT 오류]java.lang.ClassNotFoundException: javax.xml.bind.DatatypeConverter
java.lang.ClassNotFoundException: javax.xml.bind.DatatypeConverter !오류발생! -> 로그인 하고 토큰을 만들기 위해 사용한 JWT(JSON Web Token)에 의존성 코드의 몇몇 부재로 일어난 오류입니다! 아마 Dependencies에 하기
seultories.tistory.com
3. 암호화와 복호화를 위해 AES 알고리즘을 이용한 Util 클래스를 생성한다.
import org.apache.tomcat.util.codec.binary.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
public class Aes256Util {
public static String alg = "AES/CBC/PKCS5Padding";
private static String KEY = "ecommerceKeyIsKeyJustKey";
private static String IV = KEY.substring(0,16);
/* 암호화 */
public static String encrypt(String text){
try{
Cipher cipher = Cipher.getInstance(alg);
SecretKeySpec secretKeySpec = new SecretKeySpec(KEY.getBytes(),"AES");
IvParameterSpec ivParameterSpec = new IvParameterSpec(IV.getBytes());
cipher.init(Cipher.ENCRYPT_MODE,secretKeySpec,ivParameterSpec);
byte[] encrypted = cipher.doFinal(text.getBytes(StandardCharsets.UTF_8));
return Base64.encodeBase64String(encrypted);
}catch (Exception e){
return null;
}
}
/* 복호화 */
public static String decrypt(String text){
try{
Cipher cipher = Cipher.getInstance(alg);
SecretKeySpec secretKeySpec = new SecretKeySpec(KEY.getBytes(),"AES");
IvParameterSpec ivParameterSpec = new IvParameterSpec(IV.getBytes(StandardCharsets.UTF_8));
cipher.init(Cipher.DECRYPT_MODE,secretKeySpec,ivParameterSpec);
byte[] decryptedByte = Base64.decodeBase64(text);
byte[] decrypted = cipher.doFinal(decryptedByte);
return new String(decrypted,StandardCharsets.UTF_8);
}catch (Exception e){
return null;
}
}
}
3. Json Web Token을 이용한 인증provider 클래스를 생성한다.
import com.ecommerce.domain.util.Aes256Util;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
public class JwtAuthenticationProvider {
private String secretKey = "secretKey";
private long tokenValidTime = 1000L * 60 * 60 * 24;
/**
* 토큰 생성하기
* @param userPk - 입력받은 EMAIL
* @param id - 사용자 TABLE 부여받은 PK번호
* @param userType - CUSTOMER 혹은 SELLER
* @return 생성된 TOKEN
*/
public String createToken(String userPk, Long id, UserType userType){
Claims claims = Jwts.claims().setSubject(Aes256Util.encrypt(userPk)).setId(Aes256Util.encrypt(id.toString()));
Date now = new Date();
return Jwts.builder()
.setClaims(claims)
.setIssuedAt(now)
.setExpiration(new Date(now.getTime()+tokenValidTime))
.signWith(SignatureAlgorithm.HS256,secretKey)
.compact();
}
/**
* 유효한 시간 내에 토큰인지 확인
* @param jwtToken - String
* @return boolean
*/
public boolean checkValidToken(String jwtToken){
try{
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(jwtToken);
return !claimsJws.getBody().getExpiration().before(new Date());
}catch (Exception e){
return false;
}
}
/**
* 발행된 토큰으로 유저 정보 가져오기
* @param token - String
* @return - UserVo
*/
public UserVo getUserVo(String token){
Claims claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody();
return new UserVo(
Long.valueOf(Aes256Util.decrypt(claims.getId())), //USER'S ID
Aes256Util.decrypt(claims.getSubject()) //USER'S EMAIL
);
}
}
설명--
1. 토큰을 생성할 때
이렇게 인증토큰을 생성하고 확인하는 코드는 모두 작성되었으니,
Json Web Token을 사용하기 위해 만든 모듈 프로젝트를 다른 프로젝트에서 연동하여 사용하도록 하겠습니다!