Skip to content

Commit

Permalink
UMC-EWHA#31 Feat: Add JWT
Browse files Browse the repository at this point in the history
  • Loading branch information
JoongHyun-Kim committed Nov 26, 2022
1 parent aec97bf commit a85421e
Show file tree
Hide file tree
Showing 8 changed files with 128 additions and 3 deletions.
7 changes: 7 additions & 0 deletions src/main/java/umc/crud/config/secret/Secret.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package umc.crud.config.secret;

public class Secret {
// 터미널에 $ openssl rand -hex 64 명령어를 입력해 랜덤 문자열 생성해 secret key로 사용
public static String JWT_SECRET_KEY = "5fb7652d9ffd2098bcdd5434c9a9fbd5a84832a25b3897836fd50ba2f780588d4febfa3be27cd08bcd70d7ffffa8dca268a642a86a0dc838896d613fb52d3114";
public static String USER_PASSWORD_KEY = "";
}
2 changes: 1 addition & 1 deletion src/main/java/umc/crud/src/user/UserDao.java
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ public int modifyUserName(PatchUserReq patchUserReq) {

// 로그인: 해당 email에 해당되는 user의 암호화된 비밀번호 값을 가져온다.
public User getPwd(PostLoginReq postLoginReq) {
String getPwdQuery = "select userIdx, password,email,nickname from User where email = ?";
String getPwdQuery = "select userIdx, password, email, nickname from User where email = ?";
String getPwdParams = postLoginReq.getEmail(); // 주입될 email값을 클라이언트의 요청에서 가져온다.

return this.jdbcTemplate.queryForObject(getPwdQuery,
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/umc/crud/src/user/UserProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public PostLoginRes logIn(PostLoginReq postLoginReq) throws BaseException {
User user = userDao.getPwd(postLoginReq);
String password;
try {
password = new AES128(Secret.USER_INFO_PASSWORD_KEY).decrypt(user.getPassword()); // 암호화
password = new AES128(Secret.USER_PASSWORD_KEY).decrypt(user.getPassword()); // 복호화
// 회원가입할 때 비밀번호가 암호화되어 저장되었기 떄문에 로그인 시애도 암호화된 값끼리 비교
} catch (Exception ignored) {
throw new BaseException(PASSWORD_DECRYPTION_ERROR);
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/umc/crud/src/user/UserService.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public PostUserRes createUser(PostUserReq postUserReq) throws BaseException {
try {
// 암호화: postUserReq에서 제공받은 비밀번호를 암호화해 DB에 저장
// ex) password123 -> dfhsjfkjdsnj4@[email protected]
pwd = new AES128(Secret.USER_INFO_PASSWORD_KEY).encrypt(postUserReq.getPassword()); // 암호화
pwd = new AES128(Secret.USER_PASSWORD_KEY).encrypt(postUserReq.getPassword()); // 암호화
postUserReq.setPassword(pwd);
} catch (Exception ignored) { // 암호화에 실패할 경우 에러 발생
throw new BaseException(PASSWORD_ENCRYPTION_ERROR);
Expand Down
1 change: 1 addition & 0 deletions src/main/java/umc/crud/src/user/model/PostLoginRes.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@
@AllArgsConstructor
public class PostLoginRes {
private int userIdx;
private String jwt;
}
1 change: 1 addition & 0 deletions src/main/java/umc/crud/src/user/model/PostUserRes.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@
@AllArgsConstructor
public class PostUserRes {
private int userIdx;
private String jwt;
}
45 changes: 45 additions & 0 deletions src/main/java/umc/crud/utils/AES128.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package umc.crud.utils;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

import static java.nio.charset.StandardCharsets.UTF_8;

// 고급 암호화 표준
// 참고) https://sunghs.tistory.com/119
public class AES128 {
private final String ips;
private final Key keySpec;

public AES128(String key) {
byte[] keyBytes = new byte[16];
byte[] b = key.getBytes(UTF_8);
System.arraycopy(b, 0, keyBytes, 0, keyBytes.length);
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
this.ips = key.substring(0, 16);
this.keySpec = keySpec;
}
//암호화 관련 함수
public String encrypt(String value) throws NoSuchPaddingException, NoSuchAlgorithmException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException, InvalidKeyException {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, keySpec, new IvParameterSpec(ips.getBytes()));
byte[] encrypted = cipher.doFinal(value.getBytes(UTF_8));
return new String(Base64.getEncoder().encode(encrypted));
}
//복호화 관련함수
public String decrypt(String value) throws NoSuchPaddingException, NoSuchAlgorithmException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException, InvalidKeyException {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, keySpec, new IvParameterSpec(ips.getBytes(UTF_8)));
byte[] decrypted = Base64.getDecoder().decode(value.getBytes());
return new String(cipher.doFinal(decrypted), UTF_8);
}
}
71 changes: 71 additions & 0 deletions src/main/java/umc/crud/utils/JwtService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package umc.crud.utils;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import umc.crud.config.BaseException;
import umc.crud.config.secret.Secret;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;

import static umc.crud.config.BaseResponseStatus.*;

@Service
public class JwtService {

/**
* JWT 생성
* @param userIdx
* @return String
*/
public String createJwt(int userIdx){
Date now = new Date();
return Jwts.builder()
.setHeaderParam("type","jwt") // type=jwt로 설정
.claim("userIdx",userIdx) // payload에 담길 데이터(userIdx로 전달받은 값)
.setIssuedAt(now) // 발급 시간
.setExpiration(new Date(System.currentTimeMillis()+1*(1000*60*60*24*365))) // 해당 JWT 만료 시간(1년 뒤로 설정)
.signWith(SignatureAlgorithm.HS256, Secret.JWT_SECRET_KEY) // 서명 알고리즘(HS256), 비밀키
.compact(); // 토큰 생성
}

/**
* Header에서 X-ACCESS-TOKEN으로 JWT 값 추출
* @return String
*/
public String getJwt(){
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
return request.getHeader("X-ACCESS-TOKEN"); // 프론트에서 "X-ACCESS-TOKEN"라는 이름의 header에 담아 넘겨주었다고 가정, Postman 돌릴 때 header에 값 넣어주기
}

/**
* JWT에서 userIdx 추출
* @return int
* @throws BaseException
*/
public int getUserIdx() throws BaseException {
//1. 헤더에서 JWT 추출
String accessToken = getJwt();
if(accessToken == null || accessToken.length() == 0){
throw new BaseException(EMPTY_JWT);
}

// 2. JWT parsing
Jws<Claims> claims;
try{
claims = Jwts.parser()
.setSigningKey(Secret.JWT_SECRET_KEY)
.parseClaimsJws(accessToken);
}catch (Exception ignored) {
throw new BaseException(INVALID_JWT);
}

// 3. userIdx 추출
return claims.getBody().get("userIdx",Integer.class); // jwt에서 userIdx 추출합
}
}

0 comments on commit a85421e

Please sign in to comment.