From 1a35c995d98d980d4d6ac5b4730317d093603898 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EC=84=9D=20=EC=B5=9C?= Date: Fri, 15 Dec 2023 18:00:46 +0900 Subject: [PATCH] =?UTF-8?q?=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=20=EC=A0=80=EC=9E=A5=20=EC=9C=84=EC=B9=98=20=EC=88=98?= =?UTF-8?q?=EC=A0=95.=20jwt=20=EB=B3=B4=EC=99=84=EC=A4=91.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/api/egovFetch.js | 6 ++++-- .../src/components/EgovHeader.jsx | 8 +++++--- .../src/pages/login/EgovLoginContent.jsx | 10 +++++++--- .../src/pages/standardCode/viewer.js | 4 ++-- .../dbnt/kcscbackend/config/jwt/EgovJwtTokenUtil.java | 9 ++++----- .../kcscbackend/config/jwt/redis/RefreshToken.java | 6 +++--- .../config/jwt/redis/RefreshTokenRepository.java | 3 +++ .../CustomUrlAuthenticationSuccessHandler.java | 4 +++- .../kcscbackend/config/security/SecurityConfig.java | 5 ++++- 9 files changed, 35 insertions(+), 20 deletions(-) diff --git a/egovframe-template-simple-react-contribution/src/api/egovFetch.js b/egovframe-template-simple-react-contribution/src/api/egovFetch.js index 39ce795..07fecf0 100644 --- a/egovframe-template-simple-react-contribution/src/api/egovFetch.js +++ b/egovframe-template-simple-react-contribution/src/api/egovFetch.js @@ -3,6 +3,7 @@ import { SERVER_URL } from '../config'; import URL from 'constants/url'; import CODE from 'constants/code'; import { getSessionItem, setSessionItem } from 'utils/storage'; +import { getLocalItem, setLocalItem } from 'utils/storage'; export function getQueryString(params){ return `?${Object.entries(params).map(e => e.join('=')).join('&') }` @@ -14,9 +15,10 @@ export function requestFetch(url, requestOptions, handler, errorHandler) { console.log("requestFetch [requestOption] : ", requestOptions); // Login 했을경우 JWT 설정 - const sessionUser = getSessionItem('loginUser'); + const sessionUser = getLocalItem('loginUser'); const sessionUserId = sessionUser?.userId || null; - const jToken = getSessionItem('jToken'); + const jToken = getLocalItem('jToken'); + const refreshToken = getLocalItem('refreshToken'); if(sessionUserId != null && sessionUserId !== undefined){ if( !requestOptions['headers'] ) requestOptions['headers']={} if( !requestOptions['headers']['Authorization'] ) requestOptions['headers']['Authorization']=null; diff --git a/egovframe-template-simple-react-contribution/src/components/EgovHeader.jsx b/egovframe-template-simple-react-contribution/src/components/EgovHeader.jsx index 8f7beaf..9b198a6 100644 --- a/egovframe-template-simple-react-contribution/src/components/EgovHeader.jsx +++ b/egovframe-template-simple-react-contribution/src/components/EgovHeader.jsx @@ -6,12 +6,13 @@ import * as EgovNet from 'api/egovFetch'; import URL from 'constants/url'; import CODE from 'constants/code'; import { getSessionItem, setSessionItem } from 'utils/storage'; +import { getLocalItem, setLocalItem } from 'utils/storage'; function EgovHeader({ loginUser, onChangeLogin }) { console.group("EgovHeader"); console.log("[Start] EgovHeader ------------------------------"); - const sessionUser = getSessionItem('loginUser'); + const sessionUser = getLocalItem('loginUser'); const sessionUserId = sessionUser?.userId; const sessionUserSe = sessionUser?.userSe; @@ -38,8 +39,9 @@ function EgovHeader({ loginUser, onChangeLogin }) { console.log("===>>> logout resp= ", resp); if (parseInt(resp.resultCode) === parseInt(CODE.RCV_SUCCESS)) { onChangeLogin({ loginVO: {} }); - setSessionItem('loginUser', {"id":""}); - setSessionItem('jToken', null); + setLocalItem('loginUser', {"id":""}); + setLocalItem('jToken', null); + setLocalItem('refreshToken', null); window.alert("로그아웃되었습니다!"); navigate(URL.MAIN); // PC와 Mobile 열린메뉴 닫기: 2023.04.13(목) 김일국 추가 diff --git a/egovframe-template-simple-react-contribution/src/pages/login/EgovLoginContent.jsx b/egovframe-template-simple-react-contribution/src/pages/login/EgovLoginContent.jsx index c8403f7..532e828 100644 --- a/egovframe-template-simple-react-contribution/src/pages/login/EgovLoginContent.jsx +++ b/egovframe-template-simple-react-contribution/src/pages/login/EgovLoginContent.jsx @@ -76,12 +76,16 @@ function EgovLoginContent(props) { (resp) => { let resultVO = resp.resultVO; let jToken = resp?.jToken || null; + let refreshToken = resp?.refreshToken || null; - setSessionItem('jToken', jToken); - + // setSessionItem('jToken', jToken); + setLocalItem('jToken', jToken); + setLocalItem('refreshToken', refreshToken); + debugger if (Number(resp.resultCode) === Number(CODE.RCV_SUCCESS)) { setLoginVO(resultVO); - setSessionItem('loginUser', resultVO); + // setSessionItem('loginUser', resultVO); + setLocalItem('loginUser', resultVO); props.onChangeLogin(resultVO); if (saveIDFlag) setLocalItem(KEY_ID, resultVO?.id); navigate(URL.MAIN); diff --git a/egovframe-template-simple-react-contribution/src/pages/standardCode/viewer.js b/egovframe-template-simple-react-contribution/src/pages/standardCode/viewer.js index 7cb29aa..64e6c50 100644 --- a/egovframe-template-simple-react-contribution/src/pages/standardCode/viewer.js +++ b/egovframe-template-simple-react-contribution/src/pages/standardCode/viewer.js @@ -10,7 +10,7 @@ import Row from 'react-bootstrap/Row'; import Col from 'react-bootstrap/Col'; import Modal from 'react-bootstrap/Modal'; import * as EgovNet from 'api/egovFetch'; -import {getSessionItem} from "../../utils/storage"; +import {getLocalItem} from "../../utils/storage"; import CODE from "../../constants/code"; function CodeViewer(props) { @@ -29,7 +29,7 @@ function CodeViewer(props) { const [bookMarkModal, setBookMarkModal] = useState(); - const sessionUser = getSessionItem('loginUser'); + const sessionUser = getLocalItem('loginUser'); const sessionUserSe = sessionUser?.userSe; const handleClose = () => setShow(false); diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/config/jwt/EgovJwtTokenUtil.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/config/jwt/EgovJwtTokenUtil.java index d3c9b3e..91f8699 100644 --- a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/config/jwt/EgovJwtTokenUtil.java +++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/config/jwt/EgovJwtTokenUtil.java @@ -45,6 +45,7 @@ import java.util.UUID; */ //security 관련 제외한 jwt util 클래스 @Slf4j +@RequiredArgsConstructor @Component public class EgovJwtTokenUtil implements Serializable{ @@ -52,8 +53,8 @@ public class EgovJwtTokenUtil implements Serializable{ //public static final long JWT_TOKEN_VALIDITY = 24 * 60 * 60; //하루 public static final long JWT_ACCESS_TOKEN_VALIDITY = (30); //토큰의 유효시간 설정, 기본 60분 60*60 public static final String SECRET_KEY = EgovProperties.getProperty("Globals.jwt.secret"); - @Autowired - private RefreshTokenRepository refreshTokenRepository; + + private final RefreshTokenRepository refreshTokenRepository; //retrieve username from jwt token @@ -107,9 +108,7 @@ public class EgovJwtTokenUtil implements Serializable{ @Transactional public String generateRefreshTokenToken(UserInfo loginVO){ - RefreshToken refreshToken = new RefreshToken(); - refreshToken.setRefreshToken(UUID.randomUUID().toString()); - refreshToken.setUserSeq(loginVO.getUserSeq()); + RefreshToken refreshToken = new RefreshToken(loginVO.getUserSeq(), UUID.randomUUID().toString()); refreshTokenRepository.save(refreshToken); return refreshToken.getRefreshToken(); } diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/config/jwt/redis/RefreshToken.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/config/jwt/redis/RefreshToken.java index 310c680..3c7e53c 100644 --- a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/config/jwt/redis/RefreshToken.java +++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/config/jwt/redis/RefreshToken.java @@ -3,18 +3,18 @@ package com.dbnt.kcscbackend.config.jwt.redis; import lombok.*; import org.springframework.data.annotation.Id; import org.springframework.data.redis.core.RedisHash; - +import org.springframework.data.redis.core.index.Indexed; @Builder @Getter -@Setter @AllArgsConstructor @NoArgsConstructor @RedisHash(value="refreshToken", timeToLive = 60) // *60*24*14 public class RefreshToken { @Id - private String refreshToken; private Integer userSeq; + @Indexed + private String refreshToken; } diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/config/jwt/redis/RefreshTokenRepository.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/config/jwt/redis/RefreshTokenRepository.java index 497f940..a75facf 100644 --- a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/config/jwt/redis/RefreshTokenRepository.java +++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/config/jwt/redis/RefreshTokenRepository.java @@ -3,6 +3,9 @@ package com.dbnt.kcscbackend.config.jwt.redis; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; +import java.util.Optional; + @Repository public interface RefreshTokenRepository extends CrudRepository { + Optional findByRefreshToken(String refreshToken); } diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/config/security/CustomUrlAuthenticationSuccessHandler.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/config/security/CustomUrlAuthenticationSuccessHandler.java index 68eb6ad..c11c916 100644 --- a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/config/security/CustomUrlAuthenticationSuccessHandler.java +++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/config/security/CustomUrlAuthenticationSuccessHandler.java @@ -2,6 +2,7 @@ package com.dbnt.kcscbackend.config.security; import com.dbnt.kcscbackend.auth.entity.UserInfo; import com.dbnt.kcscbackend.config.jwt.EgovJwtTokenUtil; +import lombok.NoArgsConstructor; import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Configuration; import org.springframework.http.MediaType; @@ -21,10 +22,11 @@ import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.HashMap; +@RequiredArgsConstructor @Configuration public class CustomUrlAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler { - private final EgovJwtTokenUtil jwtTokenUtil = new EgovJwtTokenUtil(); + private final EgovJwtTokenUtil jwtTokenUtil; private RequestCache requestCache = new HttpSessionRequestCache(); @Override diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/config/security/SecurityConfig.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/config/security/SecurityConfig.java index 4ea66e4..944fa06 100644 --- a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/config/security/SecurityConfig.java +++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/config/security/SecurityConfig.java @@ -3,6 +3,7 @@ package com.dbnt.kcscbackend.config.security; import com.dbnt.kcscbackend.config.jwt.EgovJwtTokenUtil; import com.dbnt.kcscbackend.config.jwt.JwtAuthenticationEntryPoint; import com.dbnt.kcscbackend.config.jwt.JwtAuthenticationFilter; +import com.dbnt.kcscbackend.config.jwt.redis.RefreshTokenRepository; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; @@ -48,6 +49,7 @@ public class SecurityConfig { @Resource(name = "loginService") private UserDetailsService loginService; private final ObjectMapper objectMapper; + private final RefreshTokenRepository refreshTokenRepository; //Http Methpd : Get 인증예외 List private String[] AUTH_GET_WHITELIST = { @@ -139,7 +141,8 @@ public class SecurityConfig { @Bean public JsonAuthenticationFilter jsonUsernamePasswordAuthenticationFilter() { - JsonAuthenticationFilter jsonAuthenticationFilter = new JsonAuthenticationFilter(objectMapper, new CustomUrlAuthenticationSuccessHandler(), loginFailureHandler()); + EgovJwtTokenUtil jwtTokenUtil = new EgovJwtTokenUtil(refreshTokenRepository); + JsonAuthenticationFilter jsonAuthenticationFilter = new JsonAuthenticationFilter(objectMapper, new CustomUrlAuthenticationSuccessHandler(jwtTokenUtil), loginFailureHandler()); jsonAuthenticationFilter.setAuthenticationManager(authenticationManager()); return jsonAuthenticationFilter; }