hmkim 03-26
250326 김혜민 중복로그인수정 및 세션방식 반영
@f4fc74f344eb2b6ac507ecb0678929fcdd45dd34
 
src/main/java/com/takensoft/cms/loginPolicy/dao/LoginModeDAO.java (added)
+++ src/main/java/com/takensoft/cms/loginPolicy/dao/LoginModeDAO.java
@@ -0,0 +1,33 @@
+package com.takensoft.cms.loginPolicy.dao;
+
+import com.takensoft.cms.loginPolicy.vo.LoginModeVO;
+import com.takensoft.cms.loginPolicy.vo.LoginPolicyVO;
+import org.egovframe.rte.psl.dataaccess.mapper.Mapper;
+
+/**
+ * @author 김혜민
+ * @since 2025.03.22
+ * @modification
+ *     since    |    author    | description
+ *  2025.03.22  |    김혜민     | 최초 등록
+ *
+ * 로그인 방식 관련 DAO
+ */
+@Mapper("loginModeDAO")
+public interface LoginModeDAO {
+
+    /**
+     * @return String - 중복로그인 여부
+     *
+     * 로그인방식 조회
+     */
+    String selectLatestLoginMode();
+
+    /**
+     * @param loginModeVO - 로그인 방식 정보
+     * @return int - 로그인 방식 저장 결과
+     *
+     * 로그인방식 저장
+     */
+    int insertLoginMode(LoginModeVO loginModeVO);
+}
src/main/java/com/takensoft/cms/loginPolicy/dao/LoginPolicyDAO.java
--- src/main/java/com/takensoft/cms/loginPolicy/dao/LoginPolicyDAO.java
+++ src/main/java/com/takensoft/cms/loginPolicy/dao/LoginPolicyDAO.java
@@ -1,11 +1,7 @@
 package com.takensoft.cms.loginPolicy.dao;
 
-import com.takensoft.cms.accesCtrl.vo.AccesCtrlVO;
 import com.takensoft.cms.loginPolicy.vo.LoginPolicyVO;
-import com.takensoft.common.Pagination;
 import org.egovframe.rte.psl.dataaccess.mapper.Mapper;
-
-import java.util.List;
 
 /**
  * @author 김혜민
@@ -14,13 +10,13 @@
  *     since    |    author    | description
  *  2025.03.22  |    김혜민     | 최초 등록
  *
- * 중복로그인 허용 관련 DAO
+ * 중복로그인 관련 DAO
  */
 @Mapper("loginPolicyDAO")
 public interface LoginPolicyDAO {
 
     /**
-     * @return Boolean - 중복로그인 여부
+     * @return String - 중복로그인 여부
      *
      * 중복로그인 조회
      */
 
src/main/java/com/takensoft/cms/loginPolicy/service/LoginModeService.java (added)
+++ src/main/java/com/takensoft/cms/loginPolicy/service/LoginModeService.java
@@ -0,0 +1,31 @@
+package com.takensoft.cms.loginPolicy.service;
+
+import com.takensoft.cms.loginPolicy.vo.LoginModeVO;
+
+/**
+ * @author 김혜민
+ * @since 2024.05.21
+ * @modification
+ *     since    |    author    | description
+ *  2024.05.21  |    김혜민     | 최초 등록
+ *
+ * 로그인 방식 관련 인터페이스
+ */
+public interface LoginModeService {
+
+    /**
+     *
+     * @return LoginPolicyVO - 로그인 방식 조회
+     *
+     * 로그인 방식 조회
+     */
+    public String getLoginMode();
+    /**
+     * @param loginModeVO - 로그인 방식 정보
+     * @return ResponseEntity - 로그인 방식 수정 결과를 포함하는 응답
+     *
+     * 로그인 방식 수정
+     */
+    public int insertLoginMode(LoginModeVO loginModeVO);
+
+}(파일 끝에 줄바꿈 문자 없음)
src/main/java/com/takensoft/cms/loginPolicy/service/LoginPolicyService.java
--- src/main/java/com/takensoft/cms/loginPolicy/service/LoginPolicyService.java
+++ src/main/java/com/takensoft/cms/loginPolicy/service/LoginPolicyService.java
@@ -1,14 +1,6 @@
 package com.takensoft.cms.loginPolicy.service;
 
-import com.takensoft.cms.bbs.vo.BbsCnVO;
 import com.takensoft.cms.loginPolicy.vo.LoginPolicyVO;
-import com.takensoft.common.Pagination;
-import org.springframework.dao.DataAccessException;
-import org.springframework.web.multipart.MultipartFile;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
 
 /**
  * @author 김혜민
@@ -29,8 +21,8 @@
      */
     public boolean getPolicy();
     /**
-     * @param loginPolicyVO - 접근 제어 정보
-     * @return ResponseEntity - 접근 제어 수정 결과를 포함하는 응답
+     * @param loginPolicyVO - 중복로그인 정보
+     * @return ResponseEntity - 중복로그인 수정 결과를 포함하는 응답
      *
      * 중복로그인 수정
      */
 
src/main/java/com/takensoft/cms/loginPolicy/service/impl/LoginModeServiceImpl.java (added)
+++ src/main/java/com/takensoft/cms/loginPolicy/service/impl/LoginModeServiceImpl.java
@@ -0,0 +1,54 @@
+package com.takensoft.cms.loginPolicy.service.impl;
+
+import com.takensoft.cms.loginPolicy.dao.LoginModeDAO;
+import com.takensoft.cms.loginPolicy.service.LoginModeService;
+import com.takensoft.cms.loginPolicy.vo.LoginModeVO;
+import com.takensoft.common.idgen.service.IdgenService;
+import lombok.RequiredArgsConstructor;
+import org.egovframe.rte.fdl.cmmn.EgovAbstractServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author 김혜민
+ * @since 2024.05.21
+ * @modification
+ *     since    |    author    | description
+ *  2024.05.21  |    김혜민     | 최초 등록
+ *
+ * EgovAbstractServiceImpl : 전자정부 상속
+ * LoginModeService : 중복 로그인 관련 인터페이스 상속
+ *
+ * 로그인 방식 관련 인터페이스 구현체
+ */
+@Service("loginModeService")
+@RequiredArgsConstructor
+public class LoginModeServiceImpl extends EgovAbstractServiceImpl implements LoginModeService {
+
+    private final LoginModeDAO loginModeDAO;
+    private final IdgenService loginModeIdgen;
+
+    /**
+     * @return Boolean - 중복로그인 여부
+     *
+     * 로그인 방식 조회
+     */
+    @Override
+    public String getLoginMode() {
+
+        return  loginModeDAO.selectLatestLoginMode();
+    }
+
+    /**
+     * @param loginModeVO - 로그인 방식 정보
+     * @return int - 로그인 방식 저장 결과
+     *
+     * 로그인 방식 저장
+     */
+    @Override
+    public int insertLoginMode(LoginModeVO loginModeVO) {
+        loginModeVO.setLgnModeId(loginModeIdgen.getNextStringId()); // ID 자동 생성
+        return loginModeDAO.insertLoginMode(loginModeVO);
+    }
+
+
+}(파일 끝에 줄바꿈 문자 없음)
src/main/java/com/takensoft/cms/loginPolicy/service/impl/LoginPolicyServiceImpl.java
--- src/main/java/com/takensoft/cms/loginPolicy/service/impl/LoginPolicyServiceImpl.java
+++ src/main/java/com/takensoft/cms/loginPolicy/service/impl/LoginPolicyServiceImpl.java
@@ -1,32 +1,12 @@
 package com.takensoft.cms.loginPolicy.service.impl;
 
-import com.takensoft.cms.bbs.dao.BbsCnDAO;
-import com.takensoft.cms.bbs.dao.BbsMngDAO;
-import com.takensoft.cms.bbs.dao.WordMngDAO;
-import com.takensoft.cms.bbs.service.BbsCnService;
-import com.takensoft.cms.bbs.vo.BbsCnVO;
-import com.takensoft.cms.bbs.vo.BbsMngVO;
 import com.takensoft.cms.loginPolicy.dao.LoginPolicyDAO;
 import com.takensoft.cms.loginPolicy.service.LoginPolicyService;
 import com.takensoft.cms.loginPolicy.vo.LoginPolicyVO;
-import com.takensoft.common.Pagination;
-import com.takensoft.common.exception.*;
-import com.takensoft.common.file.dao.FileDAO;
-import com.takensoft.common.file.service.FileMngService;
-import com.takensoft.common.file.vo.FileMngVO;
 import com.takensoft.common.idgen.service.IdgenService;
-import com.takensoft.common.util.JWTUtil;
 import lombok.RequiredArgsConstructor;
 import org.egovframe.rte.fdl.cmmn.EgovAbstractServiceImpl;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.dao.DataAccessException;
 import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-import org.springframework.web.multipart.MultipartFile;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
 
 /**
  * @author 김혜민
@@ -36,7 +16,7 @@
  *  2024.05.21  |    김혜민     | 최초 등록
  *
  * EgovAbstractServiceImpl : 전자정부 상속
- * LoginPolicyService : 중복 로그인 관련 인터페이스 상속
+ * LoginMultiService : 중복 로그인 관련 인터페이스 상속
  *
  * 중복 로그인 관련 인터페이스 구현체
  */
 
src/main/java/com/takensoft/cms/loginPolicy/vo/LoginModeVO.java (added)
+++ src/main/java/com/takensoft/cms/loginPolicy/vo/LoginModeVO.java
@@ -0,0 +1,27 @@
+package com.takensoft.cms.loginPolicy.vo;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+/**
+ * @author  : 김혜민
+ * @since   : 2025.03.22
+ * @modification
+ *     since    |    author    | description
+ *  2025.03.22  |    김혜민     | 최초 등록
+ *
+ * 로그인 방식 설정 관련 VO
+ */
+@Getter
+@Setter
+@NoArgsConstructor
+@AllArgsConstructor
+public class LoginModeVO {
+
+    private String lgnModeId;     // 로그인 방식 설정 ID
+    private String lgnMode;       // 로그인 방식 (JWT / SESSION)
+    private String rgtrId;          // 등록자 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,6 +21,7 @@
 public class LoginPolicyVO {
 
     private String policyId;                  // 중복로그인 ID
-    private boolean allowMultipleLogin;  // 중복 로그인 허용 여부
-    private String rgtr;            // 수정한 관리자 ID
+    private boolean 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
@@ -1,6 +1,8 @@
 package com.takensoft.cms.loginPolicy.web;
 
+import com.takensoft.cms.loginPolicy.service.LoginModeService;
 import com.takensoft.cms.loginPolicy.service.LoginPolicyService;
+import com.takensoft.cms.loginPolicy.vo.LoginModeVO;
 import com.takensoft.cms.loginPolicy.vo.LoginPolicyVO;
 import com.takensoft.common.message.MessageCode;
 import com.takensoft.common.util.JWTUtil;
@@ -26,33 +28,34 @@
 @RestController
 @RequiredArgsConstructor
 @Slf4j
-@RequestMapping(value = "/admin/allowMultipleLogin")
+@RequestMapping(value = "/admin/loginPolicy")
 public class LoginPolicyController {
 
     private final LoginPolicyService loginPolicyService;
+    private final LoginModeService loginModeService;
     private final ResponseUtil resUtil;
     private final JWTUtil jwtUtil;
 
     /**
      *
-     * @return ResponseEntity - 접근 제어 목록 조회 결과를 포함하는 응답
+     * @return ResponseEntity - 중복로그인 조회 결과를 포함하는 응답
      *
      * 중복로그인 조회
      */
-    @GetMapping("/login-policy")
-    public ResponseEntity<?> getPolicy() {
+    @GetMapping("/getLoginPolicy.json")
+    public ResponseEntity<?> getLoginPolicy() {
         Boolean isAllowed = loginPolicyService.getPolicy();
         return resUtil.successRes(isAllowed, MessageCode.COMMON_SUCCESS);
     }
 
     /**
-     * @param params - 접근 제어 정보
-     * @return ResponseEntity - 접근 제어 수정 결과를 포함하는 응답
+     * @param params - 중복로그인 정보
+     * @return ResponseEntity - 중복로그인 결과를 포함하는 응답
      *
      * 중복로그인 수정
      */
-    @PostMapping("/login-policy")
-    public ResponseEntity<?> updatePolicy(@RequestBody Map<String, Object> params, HttpServletRequest request) {
+    @PostMapping("/saveLoginPolicy.json")
+    public ResponseEntity<?> saveLoginPolicy(@RequestBody Map<String, Object> params, HttpServletRequest request) {
         try {
             boolean allow = (Boolean) params.get("allowMultipleLogin");
 
@@ -82,4 +85,53 @@
         }
     }
 
+    /**
+     *
+     * @return ResponseEntity - 로그인 방식 조회 결과를 포함하는 응답
+     *
+     * 로그인 방식 조회
+     */
+    @GetMapping("/getLoginMode.json")
+    public Object getLoginMode() {
+        String loginMode = loginModeService.getLoginMode();
+        return resUtil.successRes(loginMode, MessageCode.COMMON_SUCCESS);
+    }
+
+    /**
+     *
+     * @return ResponseEntity - 로그인 방식 저장 결과를 포함하는 응답
+     *
+     * 로그인 방식 저장
+     */
+    @PostMapping("/saveLoginMode.json")
+    public ResponseEntity<?> saveLoginMode(@RequestBody Map<String, Object> params, 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);
+
+            int result = loginModeService.insertLoginMode(loginModeVO);
+
+            if (result > 0) {
+                return resUtil.successRes(result, MessageCode.COMMON_SUCCESS);
+            } else {
+                return resUtil.errorRes(MessageCode.COMMON_INSERT_FAIL); // 저장 실패
+            }
+
+        } catch (DuplicateKeyException e) {
+            return resUtil.errorRes(MessageCode.COMMON_DUPLICATION_DATA); // 중복 저장
+        } catch (Exception e) {
+            return resUtil.errorRes(MessageCode.COMMON_UNKNOWN_ERROR); // 기타 예외
+        }
+    }
+
 }
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
@@ -8,6 +8,7 @@
 import com.takensoft.common.config.RedisConfig;
 import com.takensoft.common.util.HttpRequestUtil;
 import com.takensoft.common.util.JWTUtil;
+import com.takensoft.common.util.LoginUtil;
 import io.jsonwebtoken.ExpiredJwtException;
 import lombok.RequiredArgsConstructor;
 import org.egovframe.rte.fdl.cmmn.EgovAbstractServiceImpl;
@@ -47,7 +48,7 @@
     private final RefreshTokenDAO refreshTokenDAO;
     private final JWTUtil jwtUtil;
     private final HttpRequestUtil httpRequestUtil;
-    private final RedisConfig redisConfig;
+    private final LoginUtil loginUtil;
     private final RedisTemplate<String, String> redisTemplate;
 
     @Value("${jwt.accessTime}")
@@ -148,7 +149,7 @@
             refreshTknVO.setMbrId((String) jwtUtil.getClaim(refreshTokenCheck(req).get("refreshToken").toString(), "mbrId"));
 
             //중복로그인 비허용시 삭제
-            if (!redisConfig.isAllowMultipleLogin()) {
+            if (!loginUtil.isAllowMultipleLogin()) {
                 redisTemplate.delete("jwt:" + refreshTknVO.getMbrId()); // 기존 JWT 삭제
             }
             return delete(req, refreshTknVO);
@@ -179,7 +180,7 @@
             String userId = (String) jwtUtil.getClaim(refreshToken, "mbrId");
 
             // 중복 로그인 비허용 체크 (DB에 저장된 리프레시 토큰과 비교)
-            if (!redisConfig.isAllowMultipleLogin()) {
+            if (!loginUtil.isAllowMultipleLogin()) {
                 String storedRefreshToken = redisTemplate.opsForValue().get("jwt:" + userId);
 
                 if (storedRefreshToken == null || !storedRefreshToken.equals(refreshToken)) {
@@ -238,7 +239,7 @@
     public int delete(HttpServletRequest req, RefreshTknVO refreshTknVO) {
             refreshTknVO.setUseIp(httpRequestUtil.getIp(req));
             //중복로그인 비허용시 삭제
-            if (!redisConfig.isAllowMultipleLogin()) {
+            if (!loginUtil.isAllowMultipleLogin()) {
                 redisTemplate.delete("jwt:" + refreshTknVO.getMbrId()); // 기존 JWT 삭제
             }
             return refreshTokenDAO.deleteByRefresh(refreshTknVO);
src/main/java/com/takensoft/common/config/RedisConfig.java
--- src/main/java/com/takensoft/common/config/RedisConfig.java
+++ src/main/java/com/takensoft/common/config/RedisConfig.java
@@ -28,12 +28,6 @@
     @Value("${redis.port}")
     private int redisPort;
 
-    private final LoginPolicyService loginPolicyService;
-
-    public RedisConfig(LoginPolicyService loginPolicyService) {
-        this.loginPolicyService = loginPolicyService;
-    }
-
     @Bean
     @ConditionalOnProperty(name = "config.allow-multiple-logins", havingValue = "false", matchIfMissing = true) //redis 사용 안 할 경우 빈 등록x
     public RedisConnectionFactory redisConnectionFactory() {
@@ -47,16 +41,6 @@
         redisTemp.setKeySerializer(new StringRedisSerializer());
         redisTemp.setValueSerializer(new StringRedisSerializer());
         return redisTemp;
-    }
-
-    /**
-     * @return allowMultipleLogin - 중복로그인 허용/비허용 반환
-     *
-     * 중복 로그인 허용 여부를 반환하는 메서드
-     */
-    public boolean isAllowMultipleLogin() {
-        Boolean result = loginPolicyService.getPolicy();
-        return result;
     }
 
 }
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
@@ -6,10 +6,12 @@
 import com.takensoft.common.filter.AccesFilter;
 import com.takensoft.common.filter.JWTFilter;
 import com.takensoft.common.filter.LoginFilter;
+import com.takensoft.common.filter.SessionAuthFilter;
 import com.takensoft.common.util.HttpRequestUtil;
 import com.takensoft.common.exception.CustomAccessDenieHandler;
 import com.takensoft.common.exception.CustomAuthenticationEntryPoint;
 import com.takensoft.common.util.JWTUtil;
+import com.takensoft.common.util.LoginUtil;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
@@ -52,6 +54,7 @@
     private final HttpRequestUtil httpRequestUtil;
     private final AppConfig appConfig;
     private final RedisConfig redisConfig;
+    private final LoginUtil loginUtil;
 
     private static String FRONT_URL;    // 프론트 접근 허용 URL
     private static long JWT_ACCESSTIME; // access 토큰 유지 시간
@@ -61,21 +64,21 @@
     private final RedisTemplate<String, String> redisTemplate;
 
     /**
+     * @param authenticationConfiguration - 인증 구성 객체
+     * @param jwtUtil - JWT 유틸리티 객체
+     * @param authenticationEntryPoint - 인증 실패 시 처리 엔트리 포인트
+     * @param accessDenieHandler - 접근 거부 처리 핸들러
+     * @param loginUtil
      * @param fUrl - 프론트엔드 URL (application.yml에서 값을 읽어 옴)
      * @param aTime - JWT 접근 토큰 유효 시간 (application.yml에서 값을 읽어 옴)
      * @param rTime - JWT 리프레시 토큰 유효 시간 (application.yml에서 값을 읽어 옴)
      * @param ctime - 쿠키 유효 시간 (application.yml에서 값을 읽어 옴)
-     * @param authenticationConfiguration - 인증 구성 객체
-     * @param authenticationEntryPoint - 인증 실패 시 처리 엔트리 포인트
-     * @param accessDenieHandler - 접근 거부 처리 핸들러
-     * @param jwtUtil - JWT 유틸리티 객체
      * @param redisTemplate
-     *
-     * SecurityConfig 생성자
+*
      */
     public SecurityConfig(AuthenticationConfiguration authenticationConfiguration, JWTUtil jwtUtil, RefreshTokenService refreshTokenService, AccesCtrlService accesCtrlService, AppConfig appConfig, RedisConfig redisConfig,
                           LgnHstryService lgnHstryService, CustomAuthenticationEntryPoint authenticationEntryPoint, CustomAccessDenieHandler accessDenieHandler, HttpRequestUtil httpRequestUtil,
-                          @Value("${front.url}")String fUrl, @Value("${jwt.accessTime}")long aTime, @Value("${jwt.refreshTime}")long rTime, @Value("${cookie.time}")int ctime, RedisTemplate<String, String> redisTemplate) {
+                          LoginUtil loginUtil, @Value("${front.url}") String fUrl, @Value("${jwt.accessTime}") long aTime, @Value("${jwt.refreshTime}") long rTime, @Value("${cookie.time}") int ctime, RedisTemplate<String, String> redisTemplate) {
 
         this.authenticationConfiguration = authenticationConfiguration;
         this.refreshTokenService = refreshTokenService;
@@ -87,6 +90,7 @@
         this.httpRequestUtil = httpRequestUtil;
         this.appConfig = appConfig;
         this.redisConfig = redisConfig;
+        this.loginUtil = loginUtil;
 
         this.FRONT_URL = fUrl;
         this.JWT_ACCESSTIME = aTime;
@@ -164,16 +168,16 @@
         );
 
         // 로그인 방식에 따라 필터 적용 (JWT vs 세션)
-       /* if ("SESSION".equals(authConfig.getLoginType())) {
-            http.addFilterBefore(sessionAuthFilter, LoginFilter.class); // 세션 인증 필터 추가
+        if ("S".equals(loginUtil.getLoginMode())) {
+            http.addFilterBefore(new SessionAuthFilter(jwtUtil, redisTemplate, redisConfig, loginUtil), LoginFilter.class);
         } else {
-            http.addFilterBefore(new JWTFilter(jwtUtil, commonConfig, redisConfig, redisTemplate), LoginFilter.class); // JWT 인증 필터 추가
-        }*/
+            http.addFilterBefore(new JWTFilter(jwtUtil, appConfig, loginUtil, redisTemplate), LoginFilter.class);
+        }
 
-        http.addFilterBefore(new JWTFilter(jwtUtil, appConfig, redisConfig, redisTemplate), LoginFilter.class); // 토큰 검증 필터
+//        http.addFilterBefore(new JWTFilter(jwtUtil, appConfig, redisConfig, redisTemplate), LoginFilter.class); // 토큰 검증 필터
         http.addFilterBefore(new AccesFilter(accesCtrlService, httpRequestUtil, appConfig), JWTFilter.class); // 아이피 검증
         http.addFilterAt(new LoginFilter(authenticationManager(authenticationConfiguration), jwtUtil, refreshTokenService, lgnHstryService, httpRequestUtil,
-                appConfig,redisConfig, JWT_ACCESSTIME, JWT_REFRESHTIME, COOKIE_TIME, redisTemplate), UsernamePasswordAuthenticationFilter.class); // 로그인 필터
+                appConfig,loginUtil, JWT_ACCESSTIME, JWT_REFRESHTIME, COOKIE_TIME, redisTemplate), UsernamePasswordAuthenticationFilter.class); // 로그인 필터
 
         return http.build();
     }
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
@@ -7,6 +7,7 @@
 import com.takensoft.common.exception.FilterExceptionHandler;
 import com.takensoft.common.util.ErrorResponse;
 import com.takensoft.common.util.JWTUtil;
+import com.takensoft.common.util.LoginUtil;
 import io.jsonwebtoken.ExpiredJwtException;
 import io.jsonwebtoken.JwtException;
 import org.springframework.data.redis.core.RedisTemplate;
@@ -41,17 +42,17 @@
     private static final String AUTHORIZATION_HEADER = "Authorization";
     private final JWTUtil jwtUtil;
     private final AppConfig appConfig;
-    private final RedisConfig redisConfig;
+    private final LoginUtil loginUtil;
     private final RedisTemplate<String, String> redisTemplate;
     /**
      * @param jwtUtil JWT 유틸리티 클래스의 인스턴스
      *
      * JWTFilter 생성자
      */
-    public JWTFilter(JWTUtil jwtUtil, AppConfig appConfig, RedisConfig redisConfig, RedisTemplate<String, String> redisTemplate) {
+    public JWTFilter(JWTUtil jwtUtil, AppConfig appConfig, LoginUtil loginUtil, RedisTemplate<String, String> redisTemplate) {
         this.jwtUtil = jwtUtil;
         this.appConfig = appConfig;
-        this.redisConfig = redisConfig;
+        this.loginUtil = loginUtil;
         this.redisTemplate = redisTemplate;
     }
     /**
@@ -101,7 +102,7 @@
 
             // 중복 로그인 비허용 설정이면 Redis에서 최신 JWT 가져와 비교
             String userId = (String) jwtUtil.getClaim(accessToken, "mbrId");
-            if (!redisConfig.isAllowMultipleLogin()) {
+            if (!loginUtil.isAllowMultipleLogin()) {
                 String storedToken = redisTemplate.opsForValue().get("jwt:" + userId);
                 if (storedToken == null) {
                 } else if (!storedToken.equals(accessToken)) {
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
@@ -8,10 +8,10 @@
 import com.takensoft.cms.mber.vo.MberVO;
 import com.takensoft.cms.token.vo.RefreshTknVO;
 import com.takensoft.common.config.AppConfig;
-import com.takensoft.common.config.RedisConfig;
 import com.takensoft.common.exception.FilterExceptionHandler;
 import com.takensoft.common.util.HttpRequestUtil;
 import com.takensoft.common.util.JWTUtil;
+import com.takensoft.common.util.LoginUtil;
 import lombok.SneakyThrows;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.data.redis.core.RedisTemplate;
@@ -50,7 +50,7 @@
     private final LgnHstryService lgnHstryService;
     private final HttpRequestUtil httpRequestUtil;
     private final AppConfig appConfig;
-    private final RedisConfig redisConfig;
+    private final LoginUtil loginUtil;
 
     private static long JWT_ACCESSTIME; // access 토큰 유지 시간
     private static long JWT_REFRESHTIME; // refresh 토큰 유지 시간
@@ -67,14 +67,14 @@
      * LoginFilter 생성자
      */
     public LoginFilter(AuthenticationManager authenticationManager, JWTUtil jwtUtil, RefreshTokenService refreshTokenService, LgnHstryService lgnHstryService, HttpRequestUtil httpRequestUtil,
-                       AppConfig appConfig, RedisConfig redisConfig, @Value("${jwt.accessTime}")long aTime, @Value("${jwt.refreshTime}")long rTime, @Value("${cookie.time}")int ctime, RedisTemplate<String, String> redisTemplate) {
+                       AppConfig appConfig, LoginUtil loginUtil, @Value("${jwt.accessTime}")long aTime, @Value("${jwt.refreshTime}")long rTime, @Value("${cookie.time}")int ctime, RedisTemplate<String, String> redisTemplate) {
         this.authenticationManager = authenticationManager;
         this.jwtUtil = jwtUtil;
         this.refreshTokenService = refreshTokenService;
         this.lgnHstryService = lgnHstryService;
         this.httpRequestUtil = httpRequestUtil;
         this.appConfig = appConfig;
-        this.redisConfig = redisConfig;
+        this.loginUtil = loginUtil;
 
         this.JWT_ACCESSTIME = aTime;
         this.JWT_REFRESHTIME = rTime;
@@ -155,7 +155,7 @@
         refreshTokenService.saveRefreshToken(req, res, refresh, JWT_REFRESHTIME);
 
         // Redis에 AccessToken 저장 (중복 로그인 비허용 설정일 때)
-        if (!redisConfig.isAllowMultipleLogin()) {
+        if (!loginUtil.isAllowMultipleLogin()) {
             redisTemplate.delete("jwt:" + mber.getMbrId()); // 기존 JWT 삭제
             redisTemplate.opsForValue().set("jwt:" + mber.getMbrId(), accessToken, JWT_ACCESSTIME, TimeUnit.MILLISECONDS);
         }
src/main/java/com/takensoft/common/filter/SessionAuthFilter.java
--- src/main/java/com/takensoft/common/filter/SessionAuthFilter.java
+++ src/main/java/com/takensoft/common/filter/SessionAuthFilter.java
@@ -1,13 +1,22 @@
 package com.takensoft.common.filter;
 
+import com.takensoft.cms.mber.vo.MberAuthorVO;
+import com.takensoft.cms.mber.vo.MberVO;
+import com.takensoft.common.config.RedisConfig;
 import com.takensoft.common.util.JWTUtil;
+import com.takensoft.common.util.LoginUtil;
 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.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
@@ -23,16 +32,17 @@
 public class SessionAuthFilter extends OncePerRequestFilter {
 
     private final JWTUtil jwtUtil;
-
-    /**
-     * @param jwtUtil JWT 유틸리티 클래스의 인스턴스
-     *
-     * 세션 Filter 생성자
-     */
-    public SessionAuthFilter(JWTUtil jwtUtil) {
+    private final RedisTemplate<String, String> redisTemplate;
+    private final RedisConfig redisConfig;
+    private final LoginUtil loginUtil;
+    public SessionAuthFilter(JWTUtil jwtUtil,
+                             RedisTemplate<String, String> redisTemplate,
+                             RedisConfig redisConfig, LoginUtil loginUtil) {
         this.jwtUtil = jwtUtil;
+        this.redisTemplate = redisTemplate;
+        this.redisConfig = redisConfig;
+        this.loginUtil = loginUtil;
     }
-
     /**
      * @param request HttpServletRequest 객체
      * @param response HttpServletResponse 객체
@@ -43,10 +53,12 @@
      * 세션 Filter 검증
      */
     @Override
-    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)  throws ServletException, IOException {
-/*
-        // 현재 로그인 방식 확인
-        if (!"SESSION".equals(authConfig.getLoginType())) {
+    protected void doFilterInternal(HttpServletRequest request,
+                                    HttpServletResponse response,
+                                    FilterChain filterChain) throws ServletException, IOException {
+
+        // JWT 방식이면 이 필터는 동작하지 않음
+        if (!"S".equalsIgnoreCase(loginUtil.getLoginMode())) {
             filterChain.doFilter(request, response);
             return;
         }
@@ -59,22 +71,35 @@
 
         String accessToken = (String) session.getAttribute("JWT_TOKEN");
 
-        // JWT 검증
-        if (jwtUtil.isExpired(accessToken)) {
+        // 토큰 만료 검증
+        if ((Boolean) jwtUtil.getClaim(accessToken, "isExpired")) {
             response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Token expired");
             return;
         }
+
+        // 중복 로그인 허용 여부 확인
+        if (!loginUtil.isAllowMultipleLogin()) {
+            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 = jwtUtil.getRoles(accessToken);
-        mber.setLgnId(jwtUtil.getLgnId(accessToken));
-        mber.setMbrId(jwtUtil.getMbrId(accessToken));
+        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);
 
-        // 사용자 정보 추출 후 SecurityContext에 저장
         UsernamePasswordAuthenticationToken authentication =
                 new UsernamePasswordAuthenticationToken(mber, null, mber.getAuthorities());
+
         SecurityContextHolder.getContext().setAuthentication(authentication);
 
-        filterChain.doFilter(request, response);*/
+        filterChain.doFilter(request, response);
     }
 }
(파일 끝에 줄바꿈 문자 없음)
src/main/java/com/takensoft/common/idgen/context/ContextIdgen.java
--- src/main/java/com/takensoft/common/idgen/context/ContextIdgen.java
+++ src/main/java/com/takensoft/common/idgen/context/ContextIdgen.java
@@ -158,7 +158,7 @@
         return idgenServiceImpl;
     }
 
-    // 중복 로그인 정책 이력 ID
+    // 중복 로그인 정책
     @Bean(name = "loginPolicyIdgn")
     public IdgenService loginPolicyIdgn() {
         IdgenService idgenServiceImpl = new IdgenService();
@@ -168,4 +168,14 @@
         idgenServiceImpl.setTblNm("LOGIN_POLICY_ID");   // 시퀀스 테이블명
         return idgenServiceImpl;
     }
+    // 로그인 방식
+    @Bean(name = "loginModeIdgen")
+    public IdgenService loginModeIdgen() {
+        IdgenService idgenService = new IdgenService();
+        idgenService.setCipers(15);
+        idgenService.setFillChar('0');
+        idgenService.setPrefix("LOGIN_MODE_");
+        idgenService.setTblNm("LOGIN_MODE_ID");
+        return idgenService;
+    }
 }
(파일 끝에 줄바꿈 문자 없음)
 
src/main/java/com/takensoft/common/util/LoginUtil.java (added)
+++ src/main/java/com/takensoft/common/util/LoginUtil.java
@@ -0,0 +1,55 @@
+package com.takensoft.common.util;
+
+import com.takensoft.cms.loginPolicy.service.LoginModeService;
+import com.takensoft.cms.loginPolicy.service.LoginPolicyService;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author  : takensoft
+ * @since   : 2025.01.22
+ * @modification
+ *     since    |    author    | description
+ *  2025.01.22  |  takensoft   | 최초 등록
+ *
+ * 중복로그인, 로그인 방식 등의 유틸리티
+ */
+@Component
+public class LoginUtil {
+
+
+    private final LoginPolicyService loginPolicyService;
+    private final LoginModeService loginModeService;
+    /**
+     *
+     * 기본 생성자
+     * @param loginPolicyService
+     * @param loginModeService
+     */
+    public LoginUtil(LoginPolicyService loginPolicyService, LoginModeService loginModeService) {
+        this.loginPolicyService = loginPolicyService;
+        this.loginModeService = loginModeService;
+    }
+
+    /**
+     * @return allowMultipleLogin - 중복로그인 허용/비허용 반환
+     *
+     * 중복 로그인 허용 여부를 반환하는 메서드
+     */
+    public boolean isAllowMultipleLogin() {
+        Boolean result = loginPolicyService.getPolicy();
+        return result;
+    }
+
+    /**
+     * @return allowMultipleLogin - 중복로그인 허용/비허용 반환
+     *
+     * 중복 로그인 허용 여부를 반환하는 메서드
+     */
+    public String getLoginMode() {
+        String result = loginModeService.getLoginMode();
+        return result;
+    }
+
+
+
+}
 
src/main/resources/mybatis/mapper/loginPolicy/loginMode-SQL.xml (added)
+++ src/main/resources/mybatis/mapper/loginPolicy/loginMode-SQL.xml
@@ -0,0 +1,40 @@
+<?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">
+<!--
+    작성자 : 김혜민
+    작성일 : 2025.03.22
+    내 용 : 로그인 방식 설정 관련
+-->
+<mapper namespace="com.takensoft.cms.loginPolicy.dao.LoginModeDAO">
+
+    <!--
+        작성자 : 김혜민
+        작성일 : 2025.03.22
+        내 용 : 로그인 방식 설정 최신값 조회
+    -->
+    <select id="selectLatestLoginMode" resultType="String">
+       SELECT lgn_mode
+        FROM lgn_mode_hstry
+        ORDER BY reg_dt DESC
+        LIMIT 1
+    </select>
+
+    <!--
+        작성자 : 김혜민
+        작성일 : 2025.03.22
+        내 용 : 로그인 방식 설정 등록
+    -->
+    <insert id="insertLoginMode" parameterType="LoginModeVO">
+       INSERT INTO lgn_mode_hstry (
+            lgn_mode_id,
+            lgn_mode,
+            rgtr_id,
+            reg_dt
+        ) VALUES (
+            #{lgnModeId},
+            #{lgnMode},
+            #{rgtrId},
+            NOW()
+        )
+    </insert>
+</mapper>(파일 끝에 줄바꿈 문자 없음)
src/main/resources/mybatis/mapper/loginPolicy/loginPolicy-SQL.xml
--- src/main/resources/mybatis/mapper/loginPolicy/loginPolicy-SQL.xml
+++ src/main/resources/mybatis/mapper/loginPolicy/loginPolicy-SQL.xml
@@ -14,7 +14,7 @@
     -->
     <select id="selectLatestPolicy" resultType="String">
         SELECT allow_multiple_login
-        FROM login_policy_history
+        FROM lgn_policy_hstry
         ORDER BY reg_dt DESC
         LIMIT 1
     </select>
@@ -25,7 +25,7 @@
         내 용 : 중복로그인 여부 등록
     -->
     <insert id="insertPolicy" parameterType="LoginPolicyVO">
-        INSERT INTO login_policy_history (
+        INSERT INTO lgn_policy_hstry (
             policy_id,
             allow_multiple_login,
             rgtr,
Add a comment
List