hmkim 03-27
250327 김혜민 로그인방식 변경시 전체 로그아웃 반영
@023c598d7a547cec3e412ee252c5dee84ebb7a85
src/main/java/com/takensoft/cms/loginPolicy/vo/LoginModeVO.java
--- src/main/java/com/takensoft/cms/loginPolicy/vo/LoginModeVO.java
+++ src/main/java/com/takensoft/cms/loginPolicy/vo/LoginModeVO.java
@@ -21,7 +21,7 @@
 public class LoginModeVO {
 
     private String lgnModeId;     // 로그인 방식 설정 ID
-    private String lgnMode;       // 로그인 방식 (JWT / SESSION)
-    private String rgtrId;          // 등록자 ID
+    private String lgnMode;       // 로그인 방식 (JWT / SESSION) J : S
+    private String rgtr;          // 등록자 ID
     private String regDt;           // 등록일시
 }
(파일 끝에 줄바꿈 문자 없음)
src/main/java/com/takensoft/cms/loginPolicy/vo/LoginPolicyVO.java
--- src/main/java/com/takensoft/cms/loginPolicy/vo/LoginPolicyVO.java
+++ src/main/java/com/takensoft/cms/loginPolicy/vo/LoginPolicyVO.java
@@ -21,7 +21,7 @@
 public class LoginPolicyVO {
 
     private String policyId;                  // 중복로그인 ID
-    private boolean allowMultipleLogin;       // 중복 로그인 허용 여부
+    private String allowMultipleLogin;       // 중복 로그인 허용 여부
     private String rgtr;                      // 수정한 관리자 ID
     private String regDt;                     // 등록일시
 }
(파일 끝에 줄바꿈 문자 없음)
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,17 +4,19 @@
 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.token.service.RefreshTokenService;
 import com.takensoft.common.message.MessageCode;
 import com.takensoft.common.util.JWTUtil;
 import com.takensoft.common.util.ResponseUtil;
+import com.takensoft.common.util.SessionUtil;
 import jakarta.servlet.http.HttpServletRequest;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.dao.DuplicateKeyException;
+import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.*;
 
-import java.util.Map;
 
 /**
  * @author 김혜민
@@ -23,7 +25,7 @@
  *     since    |    author    | description
  *  2025.03.22  |    김혜민     | 최초 등록
  *
- * 중복로그인 허용 관련 컨트롤러
+ * 로그인정책 관련 컨트롤러
  */
 @RestController
 @RequiredArgsConstructor
@@ -35,6 +37,9 @@
     private final LoginModeService loginModeService;
     private final ResponseUtil resUtil;
     private final JWTUtil jwtUtil;
+    private final SessionUtil sessionUtil;
+    private final RedisTemplate<String, String> redisTemplate;
+    private final RefreshTokenService refreshTokenService;
 
     /**
      *
@@ -42,23 +47,21 @@
      *
      * 중복로그인 조회
      */
-    @GetMapping("/getLoginPolicy.json")
+    @PostMapping(value ="/getLoginPolicy.json")
     public ResponseEntity<?> getLoginPolicy() {
-        Boolean isAllowed = loginPolicyService.getPolicy();
-        return resUtil.successRes(isAllowed, MessageCode.COMMON_SUCCESS);
+        Boolean result = loginPolicyService.getPolicy();
+        return resUtil.successRes(result, MessageCode.COMMON_SUCCESS);
     }
 
     /**
-     * @param params - 중복로그인 정보
+     * @param loginPolicyVO - 중복로그인 정보
      * @return ResponseEntity - 중복로그인 결과를 포함하는 응답
      *
      * 중복로그인 수정
      */
-    @PostMapping("/saveLoginPolicy.json")
-    public ResponseEntity<?> saveLoginPolicy(@RequestBody Map<String, Object> params, HttpServletRequest request) {
+    @PostMapping(value ="/saveLoginPolicy.json")
+    public ResponseEntity<?> saveLoginPolicy(@RequestBody LoginPolicyVO loginPolicyVO, HttpServletRequest request) {
         try {
-            boolean allow = (Boolean) params.get("allowMultipleLogin");
-
             String token = request.getHeader("Authorization");
             String mbrId = (String) jwtUtil.getClaim(token, "mbrId");
 
@@ -66,8 +69,6 @@
                 return resUtil.errorRes(MessageCode.COMMON_BAD_REQUEST);
             }
 
-            LoginPolicyVO loginPolicyVO = new LoginPolicyVO();
-            loginPolicyVO.setAllowMultipleLogin(allow);
             loginPolicyVO.setRgtr(mbrId);
 
             int result = loginPolicyService.insertPolicy(loginPolicyVO);
@@ -91,7 +92,7 @@
      *
      * 로그인 방식 조회
      */
-    @GetMapping("/getLoginMode.json")
+    @PostMapping(value ="/getLoginMode.json")
     public Object getLoginMode() {
         String loginMode = loginModeService.getLoginMode();
         return resUtil.successRes(loginMode, MessageCode.COMMON_SUCCESS);
@@ -103,24 +104,29 @@
      *
      * 로그인 방식 저장
      */
-    @PostMapping("/saveLoginMode.json")
-    public ResponseEntity<?> saveLoginMode(@RequestBody Map<String, Object> params, HttpServletRequest request) {
+    @PostMapping(value ="/saveLoginMode.json")
+    public ResponseEntity<?> saveLoginMode(@RequestBody LoginModeVO loginModeVO, HttpServletRequest request) {
         try {
-            String lgnMode =  params.get("lgnMode").toString();
-
             String token = request.getHeader("Authorization");
             String mbrId = (String) jwtUtil.getClaim(token, "mbrId");
 
             if (mbrId == null || mbrId.isBlank()) {
                 return resUtil.errorRes(MessageCode.COMMON_BAD_REQUEST);
             }
-
-            LoginModeVO loginModeVO = new LoginModeVO();
-            loginModeVO.setLgnMode(lgnMode);
-            loginModeVO.setRgtrId(mbrId);
+            loginModeVO.setRgtr(mbrId);
 
             int result = loginModeService.insertLoginMode(loginModeVO);
 
+           /* if (loginModeVO.getLgnMode().equals("J")) {
+                // JWT 전체 로그아웃
+                Set<String> keys = redisTemplate.keys("jwt:*");
+                if (keys != null && !keys.isEmpty()) redisTemplate.delete(keys);
+                refreshTokenService.deleteAll();
+            } else {
+                // 세션 전체 로그아웃
+                sessionUtil.invalidateAllSessions();
+            }*/
+
             if (result > 0) {
                 return resUtil.successRes(result, MessageCode.COMMON_SUCCESS);
             } else {
src/main/java/com/takensoft/cms/token/dao/RefreshTokenDAO.java
--- src/main/java/com/takensoft/cms/token/dao/RefreshTokenDAO.java
+++ src/main/java/com/takensoft/cms/token/dao/RefreshTokenDAO.java
@@ -46,4 +46,12 @@
      * refresh token 등록 여부 확인
      */
     boolean findByCheckRefresh(RefreshTknVO refreshTknVO);
+
+    /**
+     * @return int - refresh token 전체 삭제 여부
+     *
+     * refresh token 전체 삭제
+     */
+    int deleteAll();
+
 }
src/main/java/com/takensoft/cms/token/service/RefreshTokenService.java
--- src/main/java/com/takensoft/cms/token/service/RefreshTokenService.java
+++ src/main/java/com/takensoft/cms/token/service/RefreshTokenService.java
@@ -62,4 +62,11 @@
      * refresh token 등록 여부 확인
      */
     public boolean findByCheckRefresh(HttpServletRequest req, RefreshTknVO refreshTknVO);
+
+    /**
+     * @return int - refresh token 전체 삭제 여부
+     *
+     * refresh token 전체 삭제
+     */
+    public int deleteAll();
 }
src/main/java/com/takensoft/cms/token/service/impl/RefreshTokenServiceImpl.java
--- src/main/java/com/takensoft/cms/token/service/impl/RefreshTokenServiceImpl.java
+++ src/main/java/com/takensoft/cms/token/service/impl/RefreshTokenServiceImpl.java
@@ -23,10 +23,7 @@
 import jakarta.servlet.http.HttpServletRequest;
 import jakarta.servlet.http.HttpServletResponse;
 
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 
 /**
  * @author takensoft
@@ -265,4 +262,21 @@
         }
     }
 
+    /**
+     * @return int - refresh token 전체 삭제 여부
+     *
+     * refresh token 전체 삭제
+     */
+    @Override
+    public int deleteAll() {
+        // JWT 방식이면서 중복 로그인 비허용인 경우 redis도 정리
+        /*if (!loginPolicyService.getPolicy()) {
+            Set<String> keys = redisTemplate.keys("jwt:*");
+            if (keys != null && !keys.isEmpty()) {
+                redisTemplate.delete(keys);
+            }
+        }*/
+        return refreshTokenDAO.deleteAll(); // DB에서 리프레시 토큰 전부 삭제
+    }
+
 }
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
@@ -61,20 +61,20 @@
         if (auth != null && auth.getPrincipal() instanceof MberVO) {
             MberVO mber = (MberVO) auth.getPrincipal();
             String mbrId = mber.getMbrId();
-            String loginType = loginModeService.getLoginMode(); // "J" or "S"
+            String loginType = loginModeService.getLoginMode(); // J or S
 
-            // ✅ Refresh 토큰 삭제 (DB)
+            // Refresh 토큰 삭제 (DB)
             RefreshTknVO refresh = new RefreshTknVO();
             refresh.setMbrId(mbrId);
             int result =  refreshTokenService.delete(req, refresh);
 
             if ("S".equals(loginType)) {
-                // ✅ 세션 방식: 세션 만료 + SessionMap에서 제거
+                // 세션 방식: 세션 만료 + SessionMap에서 제거
                 HttpSession session = req.getSession(false);
                 if (session != null) session.invalidate();
                 sessionUtil.removeSession(mbrId);
             } else {
-                // ✅ JWT 방식: Redis에서 삭제
+                // JWT 방식: Redis에서 삭제
                 if (!loginPolicyService.getPolicy()) {
                     redisTemplate.delete("jwt:" + mbrId);
                 }
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
@@ -170,12 +170,12 @@
         );
 
         // 로그인 방식에 따라 필터 적용 (JWT or 세션)
-        if ("S".equals(loginModeService.getLoginMode())) {
+       /* if ("S".equals(loginModeService.getLoginMode())) {
             http.addFilterBefore(new SessionAuthFilter(jwtUtil, redisTemplate, loginPolicyService), LoginFilter.class);
         } else {
-            http.addFilterBefore(new JWTFilter(jwtUtil, appConfig, loginPolicyService, redisTemplate), LoginFilter.class);
-        }
 
+        }*/
+        http.addFilterBefore(new JWTFilter(jwtUtil, appConfig, loginPolicyService, redisTemplate), LoginFilter.class);
         http.addFilterBefore(new AccesFilter(accesCtrlService, httpRequestUtil, appConfig), JWTFilter.class); // 아이피 검증
         http.addFilterAt(new LoginFilter(authenticationManager(authenticationConfiguration), jwtUtil, refreshTokenService, lgnHstryService, httpRequestUtil,
                  loginModeService, loginPolicyService, sessionUtil, JWT_ACCESSTIME, JWT_REFRESHTIME, COOKIE_TIME, redisTemplate), UsernamePasswordAuthenticationFilter.class); // 로그인 필터
src/main/java/com/takensoft/common/filter/LoginFilter.java
--- src/main/java/com/takensoft/common/filter/LoginFilter.java
+++ src/main/java/com/takensoft/common/filter/LoginFilter.java
@@ -18,6 +18,7 @@
 import lombok.SneakyThrows;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.http.HttpStatus;
 import org.springframework.security.authentication.AuthenticationManager;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 import org.springframework.security.core.Authentication;
@@ -30,7 +31,9 @@
 import jakarta.servlet.http.HttpServletRequest;
 import jakarta.servlet.http.HttpServletResponse;
 import java.io.IOException;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -168,7 +171,16 @@
             if (!loginPolicyService.getPolicy()) {
                 sessionUtil.registerSession(mber.getMbrId(), session);
             }
+            Map<String, Object> result = new HashMap<>();
+            result.put("mbrId", mber.getMbrId());
+            result.put("mbrNm", mber.getMbrNm());
+            result.put("roles", mber.getAuthorList());
 
+            res.setContentType("application/json;charset=UTF-8");
+            res.setStatus(HttpStatus.OK.value());
+
+            ObjectMapper mapper = new ObjectMapper();
+            res.getOutputStream().write(mapper.writeValueAsBytes(result));
         } else {
             res.setHeader("Authorization", accessToken);
             res.addCookie(jwtUtil.createCookie("refresh", refreshToken, COOKIE_TIME));
src/main/java/com/takensoft/common/util/SessionUtil.java
--- src/main/java/com/takensoft/common/util/SessionUtil.java
+++ src/main/java/com/takensoft/common/util/SessionUtil.java
@@ -3,22 +3,22 @@
 import jakarta.servlet.http.HttpSession;
 import org.springframework.stereotype.Component;
 
-import java.util.HashMap;
 import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 
 /**
  * @author  : takensoft
- * @since   : 2025.01.22
+ * @since   : 2025.03.21
  * @modification
  *     since    |    author    | description
- *  2025.01.22  |  takensoft   | 최초 등록
+ *  2025.03.21  |  takensoft   | 최초 등록
  *
- * 중복로그인, 로그인 방식 등의 유틸리티
+ * 세션 로그인 방식의 유틸리티
  */
 @Component
 public class SessionUtil {
 
-        private final Map<String, HttpSession> sessionMap = new HashMap<>();
+        private final Map<String, HttpSession> sessionMap = new ConcurrentHashMap<>();
 
         public synchronized void registerSession(String mbrId, HttpSession newSession) {
             // 기존 세션 있으면 강제 로그아웃
@@ -28,11 +28,18 @@
             }
             sessionMap.put(mbrId, newSession);
         }
-
+        //로그아웃처리
         public void removeSession(String mbrId) {
             sessionMap.remove(mbrId);
         }
-
-
+        //전체 로그아웃 처리
+        public void invalidateAllSessions() {
+            for (HttpSession session : sessionMap.values()) {
+                if (session != null) {
+                    session.invalidate();
+                }
+            }
+            sessionMap.clear(); // 전체 초기화
+        }
 
 }
src/main/resources/mybatis/mapper/loginPolicy/loginMode-SQL.xml
--- src/main/resources/mybatis/mapper/loginPolicy/loginMode-SQL.xml
+++ src/main/resources/mybatis/mapper/loginPolicy/loginMode-SQL.xml
@@ -28,12 +28,12 @@
        INSERT INTO lgn_mode_hstry (
             lgn_mode_id,
             lgn_mode,
-            rgtr_id,
+            rgtr,
             reg_dt
         ) VALUES (
             #{lgnModeId},
             #{lgnMode},
-            #{rgtrId},
+            #{rgtr},
             NOW()
         )
     </insert>
src/main/resources/mybatis/mapper/mber/refresh-SQL.xml
--- src/main/resources/mybatis/mapper/mber/refresh-SQL.xml
+++ src/main/resources/mybatis/mapper/mber/refresh-SQL.xml
@@ -62,4 +62,12 @@
                AND use_ip = #{useIp}
         ) AS result
     </select>
+    <!--
+        작성자 : 김혜민
+        작성일 : 2025.03.27
+        내 용 : refresh token 전체 삭제
+       -->
+    <delete id="deleteAll">
+        DELETE FROM mbr_refresh
+    </delete>
 </mapper>
(파일 끝에 줄바꿈 문자 없음)
Add a comment
List