hmkim 04-23
250423 김혜민 세션로그인 오류 수정
@404bc5ff8abcea6066e2face5f3ed66c9f1ff857
build.gradle
--- build.gradle
+++ build.gradle
@@ -3,29 +3,38 @@
  */
 
 plugins {
-//    id 'java-library'
-//    id 'maven-publish'
     id 'java'
     id 'org.springframework.boot' version '3.4.1'
     id 'io.spring.dependency-management' version '1.1.7'
 }
 
+
+group = 'com.takensoft'
+version = '0.0.1-SNAPSHOT'
+
+java {
+    toolchain {
+        languageVersion = JavaLanguageVersion.of(17)
+    }
+}
+
+configurations {
+    compileOnly {
+        extendsFrom annotationProcessor
+    }
+}
+
+
 repositories {
-//    mavenLocal()
     mavenCentral()
     maven {
-        url = uri('https://repo1.maven.org/maven2/')
+        url "https://repo1.maven.org/maven2/"
     }
-
     maven {
-        url = uri('https://maven.egovframe.go.kr/maven/')
+        url "https://maven.egovframe.go.kr/maven/"
         mavenContent {
             releasesOnly()
         }
-    }
-
-    maven {
-        url = uri('https://repo.maven.apache.org/maven2/')
     }
 }
 
@@ -77,13 +86,9 @@
     testImplementation 'org.springframework.security:spring-security-test'
 }
 
-group = 'com.takensoft'
-// version = '1.0.0'
-version = '0.0.1-SNAPSHOT'
-//description = 'cms'
 
 // java.sourceCompatibility = JavaVersion.VERSION_1_8
-java.sourceCompatibility = '17'
+//java.sourceCompatibility = '17'
 /*publishing {
     publications {
         maven(MavenPublication) {
src/main/java/com/takensoft/cms/loginPolicy/web/LoginPolicyController.java
--- src/main/java/com/takensoft/cms/loginPolicy/web/LoginPolicyController.java
+++ src/main/java/com/takensoft/cms/loginPolicy/web/LoginPolicyController.java
@@ -4,6 +4,7 @@
 import com.takensoft.cms.loginPolicy.service.LoginPolicyService;
 import com.takensoft.cms.loginPolicy.vo.LoginModeVO;
 import com.takensoft.cms.loginPolicy.vo.LoginPolicyVO;
+import com.takensoft.cms.mber.vo.MberVO;
 import com.takensoft.cms.token.service.RefreshTokenService;
 import com.takensoft.common.message.MessageCode;
 import com.takensoft.common.util.JWTUtil;
@@ -15,6 +16,8 @@
 import org.springframework.dao.DuplicateKeyException;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.http.ResponseEntity;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.web.bind.annotation.*;
 
 import java.util.Set;
@@ -65,7 +68,22 @@
     public ResponseEntity<?> saveLoginPolicy(@RequestBody LoginPolicyVO loginPolicyVO, HttpServletRequest request) {
         try {
             String token = request.getHeader("Authorization");
-            String mbrId = (String) jwtUtil.getClaim(token, "mbrId");
+
+            String loginMode = loginModeService.getLoginMode();
+            String mbrId = null;
+
+            if ("J".equals(loginMode)) {
+                if (token == null || token.isBlank()) {
+                    return resUtil.errorRes(MessageCode.COMMON_BAD_REQUEST); // JWT인데 토큰 없음
+                }
+                mbrId = (String) jwtUtil.getClaim(token, "mbrId");
+            } else {
+
+                Authentication auth = SecurityContextHolder.getContext().getAuthentication();
+                if (auth != null && auth.getPrincipal() instanceof MberVO) {
+                    mbrId = ((MberVO) auth.getPrincipal()).getMbrId();
+                }
+            }
 
             if (mbrId == null || mbrId.isBlank()) {
                 return resUtil.errorRes(MessageCode.COMMON_BAD_REQUEST);
@@ -74,11 +92,10 @@
             loginPolicyVO.setRgtr(mbrId);
 
             int result = loginPolicyService.insertPolicy(loginPolicyVO);
-
             if (result > 0) {
                 return resUtil.successRes(result, MessageCode.COMMON_SUCCESS);
             } else {
-                return resUtil.errorRes(MessageCode.COMMON_INSERT_FAIL); // 저장 실패
+                return resUtil.errorRes(MessageCode.COMMON_INSERT_FAIL);
             }
 
         } catch (DuplicateKeyException e) {
@@ -96,8 +113,7 @@
      */
     @PostMapping(value ="/getLoginMode.json")
     public Object getLoginMode() {
-     //   String loginMode = loginModeService.getLoginMode();
-        String loginMode = "S";
+           String loginMode = loginModeService.getLoginMode();
         return resUtil.successRes(loginMode, MessageCode.COMMON_SUCCESS);
     }
 
src/main/java/com/takensoft/cms/token/web/RefreshTokenController.java
--- src/main/java/com/takensoft/cms/token/web/RefreshTokenController.java
+++ src/main/java/com/takensoft/cms/token/web/RefreshTokenController.java
@@ -73,6 +73,11 @@
                 HttpSession session = req.getSession(false);
                 if (session != null) session.invalidate();
                 sessionUtil.removeSession(mbrId);
+
+                Cookie cookie = new Cookie("JSESSIONID", null);
+                cookie.setMaxAge(0); // 삭제
+                cookie.setPath("/");
+                res.addCookie(cookie);
             } else {
                 // JWT 방식: Redis에서 삭제
                 if (!loginPolicyService.getPolicy()) {
src/main/java/com/takensoft/common/config/SecurityConfig.java
--- src/main/java/com/takensoft/common/config/SecurityConfig.java
+++ src/main/java/com/takensoft/common/config/SecurityConfig.java
@@ -173,12 +173,7 @@
 //                .anyRequest().permitAll() // 모든 사용자 접근 가능
         );
 
-        // 로그인 방식에 따라 필터 적용 (JWT or 세션)
-        if (loginModeService.getLoginMode().equals("S")) {
-            http.addFilterBefore(new SessionAuthFilter(jwtUtil, redisTemplate, loginPolicyService, refreshTokenService), LoginFilter.class);
-        } else {
-            http.addFilterBefore(new JWTFilter(jwtUtil, appConfig, loginPolicyService, redisTemplate), LoginFilter.class);
-        }
+        http.addFilterBefore(new JWTFilter(jwtUtil, appConfig, loginModeService, loginPolicyService, redisTemplate), LoginFilter.class);
 
         http.addFilterBefore(new AccesFilter(accesCtrlService, httpRequestUtil, appConfig), JWTFilter.class); // 아이피 검증
         http.addFilterAt(new LoginFilter(authenticationManager(authenticationConfiguration), jwtUtil, refreshTokenService, lgnHstryService, httpRequestUtil,
src/main/java/com/takensoft/common/filter/JWTFilter.java
--- src/main/java/com/takensoft/common/filter/JWTFilter.java
+++ src/main/java/com/takensoft/common/filter/JWTFilter.java
@@ -1,5 +1,6 @@
 package com.takensoft.common.filter;
 
+import com.takensoft.cms.loginPolicy.service.LoginModeService;
 import com.takensoft.cms.loginPolicy.service.LoginPolicyService;
 import com.takensoft.cms.mber.vo.MberAuthorVO;
 import com.takensoft.cms.mber.vo.MberVO;
@@ -9,6 +10,7 @@
 import com.takensoft.common.util.JWTUtil;
 import io.jsonwebtoken.ExpiredJwtException;
 import io.jsonwebtoken.JwtException;
+import jakarta.servlet.http.HttpSession;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.MediaType;
@@ -39,18 +41,22 @@
 public class JWTFilter extends OncePerRequestFilter {
 
     private static final String AUTHORIZATION_HEADER = "Authorization";
+    private static final String SESSION_JWT_KEY = "JWT_TOKEN";
     private final JWTUtil jwtUtil;
     private final AppConfig appConfig;
     private final LoginPolicyService loginPolicyService;
     private final RedisTemplate<String, String> redisTemplate;
+    private final LoginModeService loginModeService;
+
     /**
      * @param jwtUtil JWT 유틸리티 클래스의 인스턴스
      *
      * JWTFilter 생성자
      */
-    public JWTFilter(JWTUtil jwtUtil, AppConfig appConfig, LoginPolicyService loginPolicyService, RedisTemplate<String, String> redisTemplate) {
+    public JWTFilter(JWTUtil jwtUtil, AppConfig appConfig, LoginModeService loginModeService, LoginPolicyService loginPolicyService, RedisTemplate<String, String> redisTemplate) {
         this.jwtUtil = jwtUtil;
         this.appConfig = appConfig;
+        this.loginModeService = loginModeService;
         this.loginPolicyService = loginPolicyService;
         this.redisTemplate = redisTemplate;
     }
@@ -66,66 +72,33 @@
     @Override
     protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
         try {
-            // 헤더에서 access에 대한 토큰을 꺼냄
-            String accessToken = request.getHeader(AUTHORIZATION_HEADER);
-            // 토큰이 없다면 다음 필터로 넘김
-            if(accessToken == null) {
+            String loginMode = loginModeService.getLoginMode();
+            String accessToken = resolveToken(request, loginMode);
+
+            if (accessToken == null) {
                 filterChain.doFilter(request, response);
                 return;
             }
 
-            // 토큰 만료 여부 검증
             if ((Boolean) jwtUtil.getClaim(accessToken, "isExpired")) {
-                response.setContentType(MediaType.APPLICATION_JSON_VALUE);
-                response.setStatus(HttpStatus.UNAUTHORIZED.value());
-
-                ErrorResponse errorResponse = new ErrorResponse();
-                errorResponse.setMessage("Token expired");
-                errorResponse.setPath(request.getRequestURI());
-                errorResponse.setError(HttpStatus.UNAUTHORIZED.getReasonPhrase());
-                errorResponse.setStatus(HttpStatus.UNAUTHORIZED.value());
-                errorResponse.setTimestamp(LocalDateTime.now());
-
-                response.getOutputStream().write(appConfig.getObjectMapper().writeValueAsBytes(errorResponse));
+                sendTokenExpiredResponse(response, request);
                 return;
             }
-            // 토큰에서 페이로드 확인[ 발급시 명시 ]
-            String category = (String) jwtUtil.getClaim(accessToken, "category");
-
 
             MberVO mber = new MberVO(
-                    (String) jwtUtil.getClaim(accessToken, "mbrId")
-                    , (String) jwtUtil.getClaim(accessToken, "lgnId")
-                    , (List<MberAuthorVO>) jwtUtil.getClaim(accessToken, "roles")
+                    (String) jwtUtil.getClaim(accessToken, "mbrId"),
+                    (String) jwtUtil.getClaim(accessToken, "lgnId"),
+                    (List<MberAuthorVO>) jwtUtil.getClaim(accessToken, "roles")
             );
 
-            // 중복 로그인 비허용 설정이면 Redis에서 최신 JWT 가져와 비교
-            String userId = (String) jwtUtil.getClaim(accessToken, "mbrId");
-            if (!loginPolicyService.getPolicy()) {
-                String storedToken = redisTemplate.opsForValue().get("jwt:" + userId);
-                if (storedToken == null) {
-                } else if (!storedToken.equals(accessToken)) {
-
-                    response.setContentType(MediaType.APPLICATION_JSON_VALUE);
-                    response.setStatus(HttpStatus.UNAUTHORIZED.value());
-
-                    ErrorResponse errorResponse = new ErrorResponse();
-                    errorResponse.setMessage("Token expired");
-                    errorResponse.setPath(request.getRequestURI());
-                    errorResponse.setError(HttpStatus.UNAUTHORIZED.getReasonPhrase());
-                    errorResponse.setStatus(HttpStatus.UNAUTHORIZED.value());
-                    errorResponse.setTimestamp(LocalDateTime.now());
-                    // 응답 헤더 설정 및 json 응답 전송
-                    response.setContentType(MediaType.APPLICATION_JSON_VALUE);
-                    response.setStatus(HttpStatus.UNAUTHORIZED.value());
-                    response.getOutputStream().write(appConfig.getObjectMapper().writeValueAsBytes(errorResponse));
-                    return;
-                }
+            if (!loginPolicyService.getPolicy() && !isTokenValid(mber.getMbrId(), accessToken)) {
+                sendTokenExpiredResponse(response, request);
+                return;
             }
-            // 시큐리티 컨텍스트에 사용자 정보 설정
+
             Authentication authToken = new UsernamePasswordAuthenticationToken(mber, null, mber.getAuthorities());
             SecurityContextHolder.getContext().setAuthentication(authToken);
-            // 다음 필터로 이동
+
             filterChain.doFilter(request, response);
         } catch (ExpiredJwtException e) {
             FilterExceptionHandler.jwtError(response, e);
@@ -137,4 +110,32 @@
             FilterExceptionHandler.jwtError(response, e);
         }
     }
+
+    private String resolveToken(HttpServletRequest request, String loginMode) {
+        if ("S".equals(loginMode)) {
+            HttpSession session = request.getSession(false);
+            return session != null ? (String) session.getAttribute(SESSION_JWT_KEY) : null;
+        } else {
+            return request.getHeader(AUTHORIZATION_HEADER);
+        }
+    }
+
+    private boolean isTokenValid(String mbrId, String accessToken) {
+        String storedToken = redisTemplate.opsForValue().get("jwt:" + mbrId);
+        return storedToken == null || storedToken.equals(accessToken);
+    }
+
+
+    private void sendTokenExpiredResponse(HttpServletResponse response, HttpServletRequest request) throws IOException {
+        ErrorResponse errorResponse = new ErrorResponse();
+        errorResponse.setMessage("Token expired");
+        errorResponse.setPath(request.getRequestURI());
+        errorResponse.setError(HttpStatus.UNAUTHORIZED.getReasonPhrase());
+        errorResponse.setStatus(HttpStatus.UNAUTHORIZED.value());
+        errorResponse.setTimestamp(LocalDateTime.now());
+
+        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
+        response.setStatus(HttpStatus.UNAUTHORIZED.value());
+        response.getOutputStream().write(appConfig.getObjectMapper().writeValueAsBytes(errorResponse));
+    }
 }
(파일 끝에 줄바꿈 문자 없음)
 
src/main/java/com/takensoft/common/filter/SessionAuthFilter.java (deleted)
--- src/main/java/com/takensoft/common/filter/SessionAuthFilter.java
@@ -1,120 +0,0 @@
-package com.takensoft.common.filter;
-
-import com.takensoft.cms.loginPolicy.service.LoginPolicyService;
-import com.takensoft.cms.mber.vo.MberAuthorVO;
-import com.takensoft.cms.mber.vo.MberVO;
-import com.takensoft.cms.token.service.RefreshTokenService;
-import com.takensoft.common.util.JWTUtil;
-import jakarta.servlet.FilterChain;
-import jakarta.servlet.ServletException;
-import jakarta.servlet.http.HttpServletRequest;
-import jakarta.servlet.http.HttpServletResponse;
-import jakarta.servlet.http.HttpSession;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.data.redis.core.RedisTemplate;
-import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
-import org.springframework.security.core.context.SecurityContextHolder;
-import org.springframework.web.filter.OncePerRequestFilter;
-
-import java.io.IOException;
-import java.util.List;
-
-/**
- * @author takensoft
- * @since 2024.03.20
- * @modification
- *     since    |    author    | description
- *  2024.03.20  |  takensoft   | 최초 등록
- *
- * OncePerRequestFilter - 한 번의 요청마다 단 한 번만 필터링 작업을 수행하는 필터를 제공하는 클래스
- *
- * 세션 검증 Filter
- */
-public class SessionAuthFilter extends OncePerRequestFilter {
-
-    private final JWTUtil jwtUtil;
-    private final RedisTemplate<String, String> redisTemplate;
-    private final LoginPolicyService loginPolicyService;
-    private final RefreshTokenService refreshTokenService;
-
-    @Value("${jwt.accessTime}")
-    private long JWT_ACCESSTIME;
-    public SessionAuthFilter(JWTUtil jwtUtil, RedisTemplate<String, String> redisTemplate, LoginPolicyService loginPolicyService, RefreshTokenService refreshTokenService) {
-        this.jwtUtil = jwtUtil;
-        this.redisTemplate = redisTemplate;
-        this.loginPolicyService = loginPolicyService;
-        this.refreshTokenService = refreshTokenService;
-    }
-    /**
-     * @param request HttpServletRequest 객체
-     * @param response HttpServletResponse 객체
-     * @param filterChain 필터 체인을 통해 다음 필터로 요청을 전달
-     * @throws ServletException 필터 처리 중 발생한 서블릿 예외
-     * @throws IOException 필터 처리 중 발생한 IO 예외
-     *
-     * 세션 Filter 검증
-     */
-    @Override
-    protected void doFilterInternal(HttpServletRequest request,HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
-        HttpSession session = request.getSession(false);
-
-        // 세션이 없거나 JWT 토큰이 없으면 인증 실패 처리
-        if (session == null || session.getAttribute("JWT_TOKEN") == null) {
-            response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
-            return;
-        }
-
-        // 세션에서 JWT 토큰 가져오기
-        String accessToken = (String) session.getAttribute("JWT_TOKEN");
-
-        // 만료 여부 검증
-        if ((Boolean) jwtUtil.getClaim(accessToken, "isExpired")) {
-            // 만료된 경우, refresh 토큰 검사
-            String refreshToken = refreshTokenService.getRefreshTokenFromCookie(request);
-
-            if (refreshToken == null || (Boolean) jwtUtil.getClaim(refreshToken, "isExpired")) {
-                response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Token expired");
-                return;
-            }
-
-            // Refresh 토큰이 유효하다면 새로운 Access 토큰 발급
-            try {
-                String newAccessToken = jwtUtil.createJwt(
-                        "Authorization",
-                        (String) jwtUtil.getClaim(refreshToken, "mbrId"),
-                        (String) jwtUtil.getClaim(refreshToken, "lgnId"),
-                        (String) jwtUtil.getClaim(refreshToken, "mbrNm"),
-                        (List) jwtUtil.getClaim(refreshToken, "roles"),
-                        JWT_ACCESSTIME);
-                session.setAttribute("JWT_TOKEN", newAccessToken);
-                accessToken = newAccessToken;
-            } catch (Exception e) {
-                response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Failed to refresh token");
-                return;
-            }
-        }
-
-        // 중복 로그인 여부 확인 (JWT 방식과 동일하게 Redis 체크)
-        if (!loginPolicyService.getPolicy()) {
-            String mbrId = (String) jwtUtil.getClaim(accessToken, "mbrId");
-            String storedToken = redisTemplate.opsForValue().get("jwt:" + mbrId);
-            if (storedToken != null && !storedToken.equals(accessToken)) {
-                response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "다른 기기에서 로그인되었습니다.");
-                return;
-            }
-        }
-
-        // 사용자 인증 정보 SecurityContext에 저장
-        MberVO mber = new MberVO();
-        List<MberAuthorVO> roles = (List<MberAuthorVO>) jwtUtil.getClaim(accessToken, "roles");
-        mber.setLgnId((String) jwtUtil.getClaim(accessToken, "lgnId"));
-        mber.setMbrId((String) jwtUtil.getClaim(accessToken, "mbrId"));
-        mber.setMbrNm((String) jwtUtil.getClaim(accessToken, "mbrNm"));
-        mber.setAuthorList(roles);
-
-        UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(mber, null, mber.getAuthorities());
-        SecurityContextHolder.getContext().setAuthentication(authToken);
-
-        filterChain.doFilter(request, response);
-    }
-}(파일 끝에 줄바꿈 문자 없음)
Add a comment
List