feat: jwt token 인증 처리

test 공통 클래스 추가
      AES 암호화 유틸 추가
dev
gitea-관리자 12 months ago
parent 1e4eee368b
commit 3ca0b7eae6

@ -1,9 +1,8 @@
package kr.xit.core.biz.mapper;
import egovframework.com.cmm.model.LoginVO;
import org.egovframe.rte.psl.dataaccess.mapper.Mapper;
import egovframework.com.cmm.LoginVO;
/**
* <pre>
* description :

@ -1,14 +1,12 @@
package kr.xit.core.biz.service;
import javax.annotation.Resource;
import egovframework.com.cmm.model.LoginVO;
import egovframework.com.cmm.util.EgovFileScrty;
import javax.annotation.Resource;
import kr.xit.core.biz.mapper.IAuthApiMapper;
import org.egovframe.rte.fdl.cmmn.EgovAbstractServiceImpl;
import org.springframework.stereotype.Service;
import egovframework.com.cmm.LoginVO;
import kr.xit.core.biz.mapper.IAuthApiMapper;
@Service
public class AuthApiService extends EgovAbstractServiceImpl implements IAuthApiService {

@ -1,6 +1,6 @@
package kr.xit.core.biz.service;
import egovframework.com.cmm.LoginVO;
import egovframework.com.cmm.model.LoginVO;
/**
*

@ -1,7 +1,6 @@
package kr.xit.core.biz.web;
import egovframework.com.cmm.LoginVO;
import egovframework.com.jwt.EgovJwtTokenUtil;
import egovframework.com.cmm.model.LoginVO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
@ -13,6 +12,8 @@ import kr.xit.core.biz.service.IAuthApiService;
import kr.xit.core.consts.Constants;
import kr.xit.core.model.ApiResponseDTO;
import kr.xit.core.model.IApiResponse;
import kr.xit.core.model.TokenDTO;
import kr.xit.core.spring.auth.jwt.JwtTokenProvider;
import kr.xit.core.spring.util.MessageUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
@ -56,7 +57,7 @@ public class AuthApiController {
/** EgovMessageSource */
private final MessageUtil messageUtil;
private final EgovJwtTokenUtil egovJwtTokenUtil;
private final JwtTokenProvider jwtTokenProvider;
/**
*
@ -136,10 +137,11 @@ public class AuthApiController {
Map<String, Object> claimsMap = new HashMap<>();
// claimsMap.put("dkkdk", "kdkkdkdkd");
String jwtToken = egovJwtTokenUtil.generateToken(loginVO, claimsMap);
// String jwtToken = egovJwtTokenUtil.generateToken(loginVO.getId());
TokenDTO tokenDTO = jwtTokenProvider.generateTokenDto(claimsMap, String.format("{}{}",loginVO.getUserSe(), loginVO.getId()));
String username = egovJwtTokenUtil.getUsernameFromToken(jwtToken);
// String jwtToken = egovJwtTokenUtil.generateToken(loginVO.getId());
String username = jwtTokenProvider.getUsernameFromToken(tokenDTO.getAccessToken());
// System.out.println("Dec jwtToken username = "+username);
@ -172,7 +174,7 @@ public class AuthApiController {
//String jwtToken = jwtTokenProvider.generateJwtAccessToken(loginVO.getId(), "ROLE_USER");
resultMap.put("resultVO", loginResultVO);
resultMap.put("token", jwtToken);
resultMap.put("token", tokenDTO);
return ApiResponseDTO.success(resultMap);
}

@ -4,7 +4,7 @@
<mapper namespace="kr.xit.core.biz.mapper.IAuthApiMapper">
<!-- 일반 로그인 -->
<select id="actionLogin" resultType="egovframework.com.cmm.LoginVO">
<select id="actionLogin" resultType="egovframework.com.cmm.model.LoginVO">
<if test="userSe = 'USR'">
/** auth-mysql-mapper|actionLogin-로그인|julim */
SELECT user_id AS id

@ -1,26 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="kr.xit.core.biz.mapper.IAuthApiMapper">
<!-- 일반 로그인 -->
<select id="actionLogin" resultType="egovframework.com.cmm.LoginVO">
<if test="userSe = 'USR'">
/** auth-mysql-mapper|actionLogin-로그인|julim */
SELECT user_id AS id
, user_nm AS name
, password
, ihidnum
, email_adres AS email
, 'USR' AS userSe
, orgnzt_id
, esntl_id
FROM xit_user_info
WHERE user_id = #{id}
AND password = #{password}
AND user_sttus_code = 'P'
</if>
</select>
</mapper>

@ -66,6 +66,24 @@
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!-- spring boot test -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.restdocs</groupId>
<artifactId>spring-restdocs-core</artifactId>
<version>2.0.6.RELEASE</version>
<scope>test</scope>
</dependency>
<!-- spring boot test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>

@ -1,245 +0,0 @@
package egovframework.com.cmm;
import java.io.Serializable;
/**
* @Class Name : LoginVO.java
* @Description : Login VO class
* @Modification Information
* @
* @
* @ ------- -------- ---------------------------
* @ 2009.03.03
*
* @author
* @since 2009.03.03
* @version 1.0
* @see
*
*/
public class LoginVO implements Serializable{
/** 아이디 */
private String id;
/** 이름 */
private String name;
/** 주민등록번호 */
private String ihidNum;
/** 이메일주소 */
private String email;
/** 비밀번호 */
private String password;
/** 비밀번호 힌트 */
private String passwordHint;
/** 비밀번호 정답 */
private String passwordCnsr;
/** 사용자구분 */
private String userSe;
/** 조직(부서)ID */
private String orgnztId;
/** 조직(부서)명 */
private String orgnztNm;
/** 고유아이디 */
private String uniqId;
/** 로그인 후 이동할 페이지 */
private String url;
/** 사용자 IP정보 */
private String ip;
/** GPKI인증 DN */
private String dn;
/**
* id attribute .
* @return String
*/
public String getId() {
return id;
}
/**
* id attribute .
* @param id String
*/
public void setId(String id) {
this.id = id;
}
/**
* name attribute .
* @return String
*/
public String getName() {
return name;
}
/**
* name attribute .
* @param name String
*/
public void setName(String name) {
this.name = name;
}
/**
* ihidNum attribute .
* @return String
*/
public String getIhidNum() {
return ihidNum;
}
/**
* ihidNum attribute .
* @param ihidNum String
*/
public void setIhidNum(String ihidNum) {
this.ihidNum = ihidNum;
}
/**
* email attribute .
* @return String
*/
public String getEmail() {
return email;
}
/**
* email attribute .
* @param email String
*/
public void setEmail(String email) {
this.email = email;
}
/**
* password attribute .
* @return String
*/
public String getPassword() {
return password;
}
/**
* password attribute .
* @param password String
*/
public void setPassword(String password) {
this.password = password;
}
/**
* passwordHint attribute .
* @return String
*/
public String getPasswordHint() {
return passwordHint;
}
/**
* passwordHint attribute .
* @param passwordHint String
*/
public void setPasswordHint(String passwordHint) {
this.passwordHint = passwordHint;
}
/**
* passwordCnsr attribute .
* @return String
*/
public String getPasswordCnsr() {
return passwordCnsr;
}
/**
* passwordCnsr attribute .
* @param passwordCnsr String
*/
public void setPasswordCnsr(String passwordCnsr) {
this.passwordCnsr = passwordCnsr;
}
/**
* userSe attribute .
* @return String
*/
public String getUserSe() {
return userSe;
}
/**
* userSe attribute .
* @param userSe String
*/
public void setUserSe(String userSe) {
this.userSe = userSe;
}
/**
* orgnztId attribute .
* @return String
*/
public String getOrgnztId() {
return orgnztId;
}
/**
* orgnztId attribute .
* @param orgnztId String
*/
public void setOrgnztId(String orgnztId) {
this.orgnztId = orgnztId;
}
/**
* uniqId attribute .
* @return String
*/
public String getUniqId() {
return uniqId;
}
/**
* uniqId attribute .
* @param uniqId String
*/
public void setUniqId(String uniqId) {
this.uniqId = uniqId;
}
/**
* url attribute .
* @return String
*/
public String getUrl() {
return url;
}
/**
* url attribute .
* @param url String
*/
public void setUrl(String url) {
this.url = url;
}
/**
* ip attribute .
* @return String
*/
public String getIp() {
return ip;
}
/**
* ip attribute .
* @param ip String
*/
public void setIp(String ip) {
this.ip = ip;
}
/**
* dn attribute .
* @return String
*/
public String getDn() {
return dn;
}
/**
* dn attribute .
* @param dn String
*/
public void setDn(String dn) {
this.dn = dn;
}
/**
* @return the orgnztNm
*/
public String getOrgnztNm() {
return orgnztNm;
}
/**
* @param orgnztNm the orgnztNm to set
*/
public void setOrgnztNm(String orgnztNm) {
this.orgnztNm = orgnztNm;
}
}

@ -1,19 +1,15 @@
package egovframework.com.cmm.util;
import egovframework.com.cmm.model.LoginVO;
import java.util.ArrayList;
import java.util.List;
import kr.xit.core.consts.Constants;
import kr.xit.core.support.utils.Checks;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import egovframework.com.cmm.LoginVO;
import kr.xit.core.consts.Constants;
import kr.xit.core.support.utils.Checks;
import org.egovframe.rte.fdl.string.EgovObjectUtil;
/**
* EgovUserDetails Helper
*

@ -1,148 +0,0 @@
package egovframework.com.jwt;
import egovframework.com.cmm.LoginVO;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import java.io.Serializable;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import kr.xit.core.consts.ErrorCode;
import kr.xit.core.exception.BizRuntimeException;
import kr.xit.core.spring.config.properties.JwtProperties;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
//security 관련 제외한 jwt util 클래스
@Component
public class EgovJwtTokenUtil implements Serializable{
private Key key;
private final transient JwtProperties jwtProp;
public EgovJwtTokenUtil(@Value("${app.token.secretKey}")String secret, JwtProperties jwtProperties) {
this.key = Keys.hmacShaKeyFor(secret.getBytes(StandardCharsets.UTF_8));
this.jwtProp = jwtProperties;
}
public String getUserIdFromToken(String token) {
Claims claims = getClaimFromToken(token);
return claims.get("id").toString();
}
public String getUserSeFromToken(String token) {
Claims claims = getClaimFromToken(token);
return claims.get("userSe").toString();
}
public String getInfoFromToken(String type, String token) {
Claims claims = getClaimFromToken(token);
return claims.get(type).toString();
}
public Claims getClaimFromToken(String token) {
final Claims claims = getAllClaimsFromToken(token);
return claims;
}
//retrieve username from jwt token
public String getUsernameFromToken(String token) {
return getClaimFromToken(token, Claims::getSubject);
}
//retrieve expiration date from jwt token
public Date getExpirationDateFromToken(String token) {
return getClaimFromToken(token, Claims::getExpiration);
}
//generate token for user
public String generateToken(LoginVO loginVO) {
return doGenerateToken(new HashMap<>(), loginVO.getUserSe()+loginVO.getId());
}
/**
*
* @param loginVO LoginVO
* @param claims Map<String,Object> JWT Payload(Claims)
* @return
*/
public String generateToken(LoginVO loginVO, Map<String, Object> claims) {
return doGenerateToken(claims, loginVO.getUserSe()+loginVO.getId());
}
/**
*
*
* @param token
* @param loginVO
* @return
*/
public Boolean validateToken(String token, LoginVO loginVO) {
final String username = getUsernameFromToken(token);
if(!username.equals(loginVO.getUserSe()+loginVO.getId())){
throw BizRuntimeException.create(ErrorCode.INVALID_TOKEN);
}
return isTokenExpired(token);
}
//----------------------------------------------------------------------------------------
//while creating the token -
//1. Define claims of the token, like Issuer, Expiration, Subject, and the ID
//2. Sign the JWT using the HS512 algorithm and secret key.
//3. According to JWS Compact Serialization(https://tools.ietf.org/html/draft-ietf-jose-json-web-signature-41#section-3.1)
// compaction of the JWT to a URL-safe string
private String doGenerateToken(final Map<String, Object> claimMap, final String subject) {
Instant now = new Date().toInstant();
// payload(claimMap)에 시스템 속성 추가
Claims claims = Jwts.claims(claimMap)
.setIssuer(jwtProp.getIssuer())
.setAudience(jwtProp.getAudience())
.setSubject(subject)
.setIssuedAt(Date.from(now))
.setExpiration(Date.from(now.plus(jwtProp.getTokenExpiry(), ChronoUnit.DAYS)));
return Jwts.builder()
// 2. Signature
.signWith(key, SignatureAlgorithm.valueOf(jwtProp.getAlg())) // header "alg": "HS512"
.setHeaderParam("typ", jwtProp.getTyp())
.setHeaderParam("alg", jwtProp.getAlg())
// 1. Payload claim
.setClaims(claims)
// 3. JWT compact
.compact();
}
private <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {
final Claims claims = getAllClaimsFromToken(token);
return claimsResolver.apply(claims);
}
//for retrieveing any information from token we will need the secret key
private Claims getAllClaimsFromToken(String token) {
return Jwts.parserBuilder()
.setSigningKey(key)
.build()
.parseClaimsJws(token)
.getBody();
}
//check if the token has expired
private Boolean isTokenExpired(String token) {
final Date expiration = getExpirationDateFromToken(token);
if(expiration.before(new Date())) throw BizRuntimeException.create(ErrorCode.EXPIRED_TOKEN);
return true;
}
}

@ -54,7 +54,18 @@ public class BizRuntimeException extends BaseRuntimeException {
this.code = String.valueOf(errorCode.getHttpStatus().value());
this.errorCode = errorCode;
}
/**
* BizRuntimeException .
* @param errorCode
*/
public static BizRuntimeException of(String errorCode) {
BizRuntimeException e = new BizRuntimeException();
e.setCode(errorCode);
e.setMessage(messageUtil.getMessage(errorCode));
return e;
}
/**
* BizRuntimeException .
* @param defaultMessage

@ -0,0 +1,12 @@
package kr.xit.core.model;
import lombok.Builder;
import lombok.Data;
@Data
@Builder
public class RefreshTokenDTO {
private final String id;
private final String refreshToken;
private final Long refreshTokenExpiresIn;
}

@ -0,0 +1,15 @@
package kr.xit.core.model;
import lombok.Builder;
import lombok.Data;
@Data
@Builder
public class TokenDTO {
private final String grantType;
private final String authorizationType;
private final String accessToken;
private final String refreshToken;
private final Long accessTokenExpiresIn;
private final Long refreshTokenExpiresIn;
}

@ -0,0 +1,224 @@
package kr.xit.core.spring.auth.jwt;
import egovframework.com.cmm.model.LoginVO;
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.io.Decoders;
import io.jsonwebtoken.io.Encoders;
import io.jsonwebtoken.security.Keys;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.Map;
import java.util.function.Function;
import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import kr.xit.core.consts.Constants.JwtToken;
import kr.xit.core.consts.ErrorCode;
import kr.xit.core.exception.BizRuntimeException;
import kr.xit.core.model.TokenDTO;
import kr.xit.core.spring.config.properties.JwtProperties;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
/**
* <pre>
* description : JWT ,
* packageName : kr.xit.core.spring.auth
* fileName : JwtTokenProvider
* author : julim
* date : 2023-11-29
* ======================================================================
*
* ----------------------------------------------------------------------
* 2023-11-29 julim
*
* </pre>
*/
@Slf4j
@RequiredArgsConstructor
@Component
public class JwtTokenProvider {
public static final String REFRESH_HEADER = "Refresh";
private Key key;
private final transient JwtProperties jwtProp;
// Bean 등록후 Key SecretKey HS256 decode
@PostConstruct
public void init() {
String base64EncodedSecretKey = encodeBase64SecretKey(jwtProp.getSecretKey());
this.key = getKeyFromBase64EncodedKey(base64EncodedSecretKey);
}
public String encodeBase64SecretKey(String secretKey) {
return Encoders.BASE64.encode(secretKey.getBytes(StandardCharsets.UTF_8));
}
private Key getKeyFromBase64EncodedKey(String base64EncodedSecretKey) {
byte[] keyBytes = Decoders.BASE64.decode(base64EncodedSecretKey);
return Keys.hmacShaKeyFor(keyBytes);
}
public TokenDTO generateTokenDto(final Map<String, Object> claims, final String subject) {
Instant now = new Date().toInstant();
Date accessTokenExpiresIn = getTokenExpiration(jwtProp.getTokenExpiry(), now);
Date refreshTokenExpiresIn = getTokenExpiration(jwtProp.getRefreshTokenExpiry(), now);
String accessToken = Jwts.builder()
.setClaims(claims)
.setSubject(subject)
.setExpiration(accessTokenExpiresIn)
.setIssuedAt(Date.from(now))
.signWith(key, SignatureAlgorithm.HS256)
.compact();
String refreshToken = Jwts.builder()
.setSubject(subject)
.setIssuedAt(Date.from(now))
.setExpiration(refreshTokenExpiresIn)
.signWith(key)
.compact();
return TokenDTO.builder()
.grantType(JwtToken.GRANT_TYPE.getCode())
.authorizationType(JwtToken.HEADER_NAME.getCode())
.accessToken(accessToken)
.accessTokenExpiresIn(accessTokenExpiresIn.getTime())
.refreshToken(refreshToken)
.build();
}
// JWT 토큰을 복호화하여 토큰 정보를 반환
// public Authentication getAuthentication(String accessToken) {
// Claims claims = parseClaims(accessToken);
//
// if (claims.get("role") == null) {
// throw new BusinessLogicException(ExceptionCode.NO_ACCESS_TOKEN);
// }
//
// String authority = claims.get("role").toString();
//
// CustomUserDetails customUserDetails = CustomUserDetails.of(
// claims.getSubject(),
// authority);
//
//
// log.info("# AuthMember.getRoles 권한 체크 = {}", customUserDetails.getAuthorities().toString());
//
// return new UsernamePasswordAuthenticationToken(customUserDetails, null, customUserDetails.getAuthorities());
// }
// 토큰 검증
public boolean validateToken(String token, HttpServletResponse response) {
try {
parseClaims(token);
} catch (MalformedJwtException e) {
log.info("Invalid JWT token");
log.trace("Invalid JWT token trace = {}", e);
throw BizRuntimeException.of("fail.jwt.invalid");
} catch (ExpiredJwtException e) {
log.info("Expired JWT token");
log.trace("Expired JWT token trace = {}", e);
throw BizRuntimeException.of("fail.jwt.expired");
} catch (UnsupportedJwtException e) {
log.info("Unsupported JWT token");
log.trace("Unsupported JWT token trace = {}", e);
throw BizRuntimeException.of("fail.jwt.unsupported");
} catch (IllegalArgumentException e) {
log.info("JWT claims string is empty.");
log.trace("JWT claims string is empty trace = {}", e);
throw BizRuntimeException.of("fail.jwt.illegalArgument");
}
return true;
}
private Date getTokenExpiration(final int expirationDay, final Instant now) {
return Date.from(now.plus(expirationDay, ChronoUnit.DAYS));
}
// Token 복호화 및 예외 발생(토큰 만료, 시그니처 오류)시 Claims 객체가 안만들어짐.
public Claims parseClaims(String token) {
return Jwts.parserBuilder()
.setSigningKey(key)
.build()
.parseClaimsJws(token)
.getBody();
}
public void accessTokenSetHeader(String accessToken, HttpServletResponse response) {
String headerValue = JwtToken.GRANT_TYPE + accessToken;
response.setHeader(JwtToken.HEADER_NAME.getCode(), headerValue);
}
public void refresshTokenSetHeader(String refreshToken, HttpServletResponse response) {
response.setHeader("Refresh", refreshToken);
}
// Request Header에 Access Token 정보를 추출하는 메서드
public String resolveAccessToken(HttpServletRequest request) {
String bearerToken = request.getHeader(JwtToken.HEADER_NAME.getCode());
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(JwtToken.GRANT_TYPE.getCode())) {
return bearerToken.substring(JwtToken.GRANT_TYPE.getCode().length()+1);
}
return null;
}
// Request Header에 Refresh Token 정보를 추출하는 메서드
public String resolveRefreshToken(HttpServletRequest request) {
String bearerToken = request.getHeader(REFRESH_HEADER);
if (StringUtils.hasText(bearerToken)) {
return bearerToken;
}
return null;
}
public Date getExpirationDateFromToken(String token) {
return getClaimFromToken(token, Claims::getExpiration);
}
public String getUserIdFromToken(String token) {
Claims claims = parseClaims(token);
return claims.get("id").toString();
}
public String getUsernameFromToken(String token) {
return getClaimFromToken(token, Claims::getSubject);
}
public String getUserSeFromToken(String token) {
Claims claims = parseClaims(token);
return claims.get("userSe").toString();
}
public String getInfoFromToken(String type, String token) {
Claims claims = parseClaims(token);
return claims.get(type).toString();
}
public Boolean validateToken(String token, LoginVO loginVO) {
final String username = getUsernameFromToken(token);
if(!username.equals(loginVO.getUserSe()+loginVO.getId())){
throw BizRuntimeException.create(ErrorCode.INVALID_TOKEN);
}
return isTokenExpired(token);
}
private <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {
final Claims claims = parseClaims(token);
return claimsResolver.apply(claims);
}
private Boolean isTokenExpired(String token) {
final Date expiration = getExpirationDateFromToken(token);
if(expiration.before(new Date())) throw BizRuntimeException.create(ErrorCode.EXPIRED_TOKEN);
return true;
}
}

@ -1,6 +1,6 @@
package egovframework.com.jwt;
package kr.xit.core.spring.auth.jwt;
import egovframework.com.cmm.LoginVO;
import egovframework.com.cmm.model.LoginVO;
import egovframework.com.cmm.util.EgovStringUtil;
import egovframework.com.cmm.util.EgovUserDetailsHelper;
import io.jsonwebtoken.ExpiredJwtException;
@ -17,7 +17,7 @@ import org.springframework.stereotype.Component;
@Component
public class JwtVerification {
private final EgovJwtTokenUtil jwtTokenUtil;
private final JwtTokenProvider jwtTokenProvider;
private final Logger log = LoggerFactory.getLogger(JwtVerification.class);
@ -40,7 +40,7 @@ public class JwtVerification {
String username = null;
try {
username = jwtTokenUtil.getUsernameFromToken(jwtToken);
username = jwtTokenProvider.getUsernameFromToken(jwtToken);
} catch (IllegalArgumentException e) {
log.debug("Unable to get JWT Token");
} catch (ExpiredJwtException e) {
@ -52,7 +52,7 @@ public class JwtVerification {
}
// step 4. 가져온 username이랑 2에서 가져온 loginVO랑 비교해서 같은지 체크 & 이 과정에서 한번 더 기간 체크를 한다.
if (username == null || !(jwtTokenUtil.validateToken(jwtToken, loginVO))) {
if (username == null || !(jwtTokenProvider.validateToken(jwtToken, loginVO))) {
log.debug("jwtToken not validate");
return false;
}

@ -78,7 +78,7 @@ public class HeaderUtil {
if(Checks.isEmpty(accessToken)) throw BizRuntimeException.create(ErrorCode.AUTH_HEADER_NOT_EXISTS);
try {
String username = CoreSpringUtils.getEgovJwtTokenUtil().getUsernameFromToken(accessToken);
String username = CoreSpringUtils.getJwtTokenProvider().getUsernameFromToken(accessToken);
return username;
}catch (Exception e){
throw BizRuntimeException.create(ErrorCode.INVALID_TOKEN);
@ -89,7 +89,7 @@ public class HeaderUtil {
if(Checks.isEmpty(accessToken)) throw BizRuntimeException.create(ErrorCode.AUTH_HEADER_NOT_EXISTS);
try {
return CoreSpringUtils.getEgovJwtTokenUtil().getUsernameFromToken(accessToken);
return CoreSpringUtils.getJwtTokenProvider().getUsernameFromToken(accessToken);
}catch (Exception e){
throw BizRuntimeException.create(ErrorCode.INVALID_TOKEN);
}

@ -14,6 +14,7 @@ public class JwtProperties {
private String alg;
private String issuer;
private String audience;
private String secretKey;
// minute
private int tokenExpiry;
// day

@ -0,0 +1,83 @@
package kr.xit.core.spring.util;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;
import javax.annotation.PostConstruct;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import kr.xit.core.exception.BizRuntimeException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* <pre>
* description : AES128 AES128Config class
* packageName : kr.xit.core.spring.util
* fileName : AES128Config
* author : julim
* date : 2023-11-29
* ======================================================================
*
* ----------------------------------------------------------------------
* 2023-11-29 julim
*
* </pre>
*/
@Component
public class AES128Config {
private static final Charset ENCODING_TYPE = StandardCharsets.UTF_8;
private static final String INSTANCE_TYPE = "AES/CBC/PKCS5Padding";
@Value("${app.aes.secret-key:}")
private String secretKey;
private IvParameterSpec ivParameterSpec;
private SecretKeySpec secretKeySpec;
private Cipher cipher;
@PostConstruct
public void init() throws NoSuchPaddingException, NoSuchAlgorithmException {
SecureRandom secureRandom = new SecureRandom();
byte[] iv = new byte[16]; // 16bytes = 128bits
secureRandom.nextBytes(iv);
ivParameterSpec = new IvParameterSpec(iv);
secretKeySpec = new SecretKeySpec(secretKey.getBytes(ENCODING_TYPE), "AES");
cipher = Cipher.getInstance(INSTANCE_TYPE);
}
// AES 암호화
/**
* AES
* @param plaintext String
* @return String
*/
public String encryptAes(String plaintext) {
try {
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
byte[] encryted = cipher.doFinal(plaintext.getBytes(ENCODING_TYPE));
return new String(Base64.getEncoder().encode(encryted), ENCODING_TYPE);
} catch (Exception e) {
throw BizRuntimeException.of("fail.aes.encode");
}
}
/**
* AES
* @param plaintext String
* @return String
*/
public String decryptAes(String plaintext) {
try {
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
byte[] decoded = Base64.getDecoder().decode(plaintext.getBytes(ENCODING_TYPE));
return new String(cipher.doFinal(decoded), ENCODING_TYPE);
} catch (Exception e) {
throw BizRuntimeException.of("fail.aes.decode");
}
}
}

@ -1,8 +1,8 @@
package kr.xit.core.spring.util;
import com.fasterxml.jackson.databind.ObjectMapper;
import egovframework.com.jwt.EgovJwtTokenUtil;
import egovframework.com.jwt.JwtVerification;
import kr.xit.core.spring.auth.jwt.JwtTokenProvider;
import kr.xit.core.spring.auth.jwt.JwtVerification;
import kr.xit.core.spring.config.properties.CorsProperties;
import kr.xit.core.spring.config.support.ApplicationContextProvider;
import lombok.AccessLevel;
@ -75,8 +75,8 @@ public class CoreSpringUtils {
*
* @return EgovJwtTokenUtil
*/
public static EgovJwtTokenUtil getEgovJwtTokenUtil(){
return (EgovJwtTokenUtil)getBean(EgovJwtTokenUtil.class);
public static JwtTokenProvider getJwtTokenProvider(){
return (JwtTokenProvider)getBean(JwtTokenProvider.class);
}
/**

@ -144,3 +144,7 @@ app:
allow-Credentials: true
# 기본적으로 브라우저에게 노출이 되지 않지만, 브라우저 측에서 접근할 수 있게 허용해주는 헤더를 지정
expose-Headers: Content-Length
# AES128 암호화 및 복호화 기능을 하는 AES128Config class 에서 사용
aes:
secret-key: c3ByaW5nLWJvb3Qtc2VjdXJpdHktand0LWlucGl4LWNvcmUtamF2YWZyYW1ld29yay1qYXZhLXRva2VuLWtleQ

@ -1,8 +1,22 @@
#------------------------------------------------
# \uACF5\uD1B5 \uBA54\uC138\uC9C0 \uC815\uC758 : framework
#------------------------------------------------
fail.jwt.invalid=\uC815\uC0C1\uC801\uC778 \uD1A0\uD070\uC774 \uC544\uB2D9\uB2C8\uB2E4(\uC798\uBABB\uB41C \uAD6C\uC870).
fail.jwt.expired=\uD1A0\uD070 \uC720\uD6A8\uAE30\uAC04\uC774 \uACBD\uACFC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.
fail.jwt.unsupported=\uC815\uC0C1\uC801\uC778 \uD1A0\uD070\uC774 \uC544\uB2D9\uB2C8\uB2E4(\uD615\uC2DD \uB610\uB294 \uAD6C\uC131)
fail.jwt.illegalArgument=\uC815\uC0C1\uC801\uC778 \uD1A0\uD070\uC774 \uC544\uB2D9\uB2C8\uB2E4.
fail.jwt.role.invalid=\uC720\uD6A8\uD558\uC9C0 \uC54A\uC740 \uD1A0\uD070 \uAD8C\uD55C\uC815\uBCF4 \uC785\uB2C8\uB2E4[{0}]
fail.jwt.role.notExists=\uD1A0\uD070\uC5D0 \uAD8C\uD55C\uC815\uBCF4\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4
fail.aes.encode=\uC554\uD638\uD654\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4.
fail.aes.decode=\uBCF5\uD638\uD654\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4.
fail.common.msg=\uC5D0\uB7EC\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4!
fail.common.sql=sql \uC5D0\uB7EC\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4! error code: {0}, error msg: {1}
info.nodata.msg=\uD574\uB2F9 \uB370\uC774\uD130\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.

@ -0,0 +1,51 @@
package kr.xit.core.spring.test;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.restdocs.RestDocumentationExtension;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.transaction.annotation.Transactional;
/**
* <pre>
* description :
* <code>@Disabled</code> :
* -> .
* <code>@Transactional</code> : ,
* -> @Rollback(false)
* <code>@AutoConfigureMockMvc</code> : @WebMvcTest @SpringBootTest
* MockMvc
* <code>@ActiveProfiles</code> :
* <code>@AutoConfigureRestDocs</code> : Spring REST Docs MockMvc
* -> Mock MVC, REST Assured WebTestClient Spring REST Docs
* <code>@ExtendWith(RestDocumentationExtension.class)</code> : Spring REST Docs JUNit 5
* packageName : kr.xit.core.spring.test
* fileName : BaseIntegrationTest
* author : julim
* date : 2023-11-29
* ======================================================================
*
* ----------------------------------------------------------------------
* 2023-11-29 julim
*
* </pre>
*/
@Disabled
@Transactional
@SpringBootTest
@AutoConfigureMockMvc
@AutoConfigureRestDocs
@ActiveProfiles("test")
@ExtendWith(RestDocumentationExtension.class)
public class BaseIntegrationTest {
@Autowired
protected MockMvc mockMvc;
}

@ -0,0 +1,29 @@
package kr.xit.core.spring.util;
import static org.assertj.core.api.Assertions.assertThat;
import kr.xit.core.spring.test.BaseIntegrationTest;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
@Slf4j
class AES128ConfigTest extends BaseIntegrationTest {
@Autowired
private AES128Config aes128Config;
@Test
@DisplayName("Aes128 암호화가 잘 이루어지는지 테스트")
void aes128Test() {
String text = "this is test";
String enc = aes128Config.encryptAes(text);
String dec = aes128Config.decryptAes(enc);
log.info("enc = {}", enc);
log.info("dec = {}", dec);
assertThat(dec).isEqualTo(text);
}
}
Loading…
Cancel
Save