류윤주 류윤주 03-28
Merge branch 'master' of http://210.180.118.83/jhpark/cms_frontend
@995da79e192fc9289f78b211ff30d50a152b6354
client/resources/api/index.js
--- client/resources/api/index.js
+++ client/resources/api/index.js
@@ -19,16 +19,24 @@
 )
 
 apiClient.interceptors.response.use(
+  
   response => {
     return response;
   },
   async error => {
+    if (!error.response) {
+      return Promise.reject(error);
+    }
     if (error.response.status == 403 && error.response.data.message == '접근 권한이 없습니다.') {
       window.history.back();
     }
     const originalReq = error.config;
+    if (originalReq.url.includes('/refresh/tokenReissue.json')) {
+      return Promise.reject(error);
+    }
     // 토큰의 만료기간이 끝난경우
-    if (error.response.status == 401 && error.response.data.message == 'Token expired' && !originalReq._retry) {
+  //  if (error.response.status == 401 && error.response.data.message == 'Token expired' && !originalReq._retry) {
+  if (error.response.status === 401 && error.response.data?.message?.toLowerCase().includes('expired') && !originalReq._retry) {
       originalReq._retry = true; // 재요청 시도(한번만 실행)
       try {
         const res = await axios.post('/refresh/tokenReissue.json', {});
@@ -49,7 +57,7 @@
       } catch (refreshError) {
         const redirect = window.location.pathname + window.location.search;
         sessionStorage.setItem("redirect", redirect);
-        alert('세션이 종료되었습니다.\n로그인을 새로 해주세요.');
+        alert('세션이 종료 되었습니다.\n로그인을 새로 해주세요.');
         store.commit("setStoreReset");
         window.location = '/login.page';
         return Promise.reject(refreshError);
 
client/resources/api/loginPolicy (added)
+++ client/resources/api/loginPolicy
@@ -0,0 +1,17 @@
+import apiClient from "./index";
+
+export const findAllByLoginPolicy = () => {
+    return apiClient.post(`/admin/loginPolicy/getLoginPolicy.json`);
+}
+
+export const saveByLoginPolicy = loginPolicy => {
+    return apiClient.post(`/admin/loginPolicy/saveLoginPolicy.json`, loginPolicy);
+}
+
+export const findAllByLoginMode = () => {
+    return apiClient.post(`/admin/loginPolicy/getLoginMode.json`);
+}
+
+export const saveByLoginMode = loginMode => {
+    return apiClient.post(`/admin/loginPolicy/saveLoginMode.json`, loginMode);
+}(파일 끝에 줄바꿈 문자 없음)
 
client/views/pages/adm/system/LoginPolicy/LoginPolicy.vue (added)
+++ client/views/pages/adm/system/LoginPolicy/LoginPolicy.vue
@@ -0,0 +1,114 @@
+<template>
+  <div class="content admin-style">
+    <div class="admin-page-title  point-font2 mb30">
+          <p>로그인 정책 설정</p>
+      </div>
+      <details open class="form-table-style mb30">
+          <summary class="point-font2">
+              <p class="summary-style pl10">로그인 정책</p>
+          </summary>
+          <div class="pt10 pb10">
+              <table class="form-table">
+                  <colgroup>
+                      <col width="50%" />
+                      <col width="50%" />
+                  </colgroup>
+                  <tr>
+                      <td>
+                          <div class="gd-12 pl0">
+                              <label for="" class="form-title point-font2 mb10">중복로그인 설정</label>
+                              <label>
+                                <input type="checkbox" v-model="allowMultipleLogin" @change="saveByLoginPolicy" />
+                              </label>
+                              <p>{{ allowMultipleLogin ? '중복 로그인을 허용하고 있습니다.' : '중복 로그인을 허용하지 않습니다.' }}</p>
+                              <p style="color: red;"> ※ 로그인 방식을 변경하면 전체 사용자가 로그아웃됩니다.</p>
+                          </div>
+                      </td>
+                      <td>
+                          <div class="gd-12 pl0"> 
+                              <label for="" class="form-title point-font2 ">로그인 방식 설정</label>
+                                <div class="gd-4">
+                                  <input type="radio" class="mr5" value="J" v-model="lgnMode" @change="saveByLoginMode" /> 
+                                  <label>JWT 방식</label>
+                                </div>
+                                <div class="gd-4">
+                                <input type="radio" class="mr5" value="S" v-model="lgnMode" @change="saveByLoginMode" /> 
+                                <label>SESSION 방식</label>
+                              </div>
+                                <span class="ml10 gray">
+                                  현재 로그인 방식은 <strong>{{ loginModeLabel  }}</strong> 입니다.
+                                </span>
+                              
+                          </div>
+                      </td>
+                  </tr>
+              </table>
+          </div>
+      </details>
+    </div>
+</template>
+  
+  <script>
+  import { findAllByLoginPolicy, saveByLoginPolicy, findAllByLoginMode, saveByLoginMode } from '../../../../../resources/api/loginPolicy'
+  
+  export default {
+    data() {
+      return {
+        allowMultipleLogin:  null,
+        lgnMode : null
+      }
+    },
+    created() {
+      this.findAll();
+    },
+    mounted() {
+    },
+    computed: {
+      loginModeLabel() {
+        return this.loginMode === 'J' ? 'JWT' : 'SESSION';
+      }
+    },
+    methods: {
+      async findAll() {
+        try {
+          const res1 = await findAllByLoginPolicy();
+          this.allowMultipleLogin = res1.data.data;
+
+          const res2 = await findAllByLoginMode();
+          this.lgnMode = res2.data.data;
+          
+        } catch (err) {
+          alert('설정 정보를 불러오는 데 실패했습니다.');
+        }
+      },
+      async saveByLoginPolicy() {
+      try {
+        const loginPolicy = {};
+        loginPolicy.allowMultipleLogin = this.allowMultipleLogin ? "Y" : "N";
+  //      await saveByLoginPolicy(loginPolicy);
+        alert('중복 로그인 설정이 저장되었습니다.');
+      } catch (err) {
+        alert('중복 로그인 설정 저장 실패');
+      }
+    },
+    async saveByLoginMode() {
+      const confirmed = confirm(
+        '로그인 방식을 변경하면 전체 사용자가 로그아웃됩니다.\n계속하시겠습니까?'
+      );
+      if (!confirmed) return;
+
+      try {
+        const loginMode = {};
+        loginMode.lgnMode = this.lgnMode;
+ //       await saveByLoginMode(loginMode);
+        alert('로그인 방식이 변경되었습니다.\n다시 로그인해주세요.');
+        store.commit("setStoreReset");
+        window.location = '/login.page';
+        return Promise.reject(refreshError);
+      } catch (err) {
+        alert('로그인 방식 저장 실패', err);
+      }
+    }
+    }
+  }
+  </script>(파일 끝에 줄바꿈 문자 없음)
client/views/pages/login/Login.vue
--- client/views/pages/login/Login.vue
+++ client/views/pages/login/Login.vue
@@ -100,31 +100,35 @@
       try {
         const res = await loginProc(this.member);
         if (res.status == 200) {
-          store.commit("setAuthorization", res.headers.authorization);
-          // store.commit("setRefresh", res.headers.refresh);
-          /** jwt토큰 복호화 **/
-          const base64String = store.state.authorization.split(".")[1];
-          const base64 = base64String.replace(/-/g, "+").replace(/_/g, "/");
-          const jsonPayload = decodeURIComponent(
-            atob(base64)
-              .split("")
-              .map((c) => {
-                return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2);
-              })
-              .join("")
-          );
-          const mbr = JSON.parse(jsonPayload);
-          //const mbr = JSON.parse(decodeURIComponent(escape(window.atob(base64String)))); // jwt claim 추출
-          store.commit("setMbrId", mbr.mbrId);
-          store.commit("setMbrNm", mbr.mbrNm);
-          store.commit("setRoles", mbr.roles);
-          /** jwt토큰 복호화 **/
+          const loginType = res.headers['login-type']; // 세션/토큰 로그인 구분
+          if (loginType === 'J') {
+              // JWT 방식
+              store.commit("setAuthorization", res.headers.authorization);
+              const base64String = store.state.authorization.split(".")[1];
+              const base64 = base64String.replace(/-/g, "+").replace(/_/g, "/");
+              const jsonPayload = decodeURIComponent(
+                atob(base64).split("").map((c) => {
+                  return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2);
+                }).join("")
+              );
+              const mbr = JSON.parse(jsonPayload);
+              store.commit("setMbrId", mbr.mbrId);
+              store.commit("setMbrNm", mbr.mbrNm);
+              store.commit("setRoles", mbr.roles);
+          } else if (loginType === 'S') {
+              // 세션 방식 (서버에서 따로 body에 사용자 정보 내려줘야 함)
+              const mbr = res.data;
+              store.commit("setAuthorization", null);
+              store.commit("setMbrId", mbr.mbrId);
+              store.commit("setMbrNm", mbr.mbrNm);
+              store.commit("setRoles", mbr.roles);
+          } else {
+              alert("알 수 없는 로그인 방식입니다.");
+              return;
+          }
           const url = this.restoreRedirect("redirect");
           if (url != null && url != "") {
-            if (
-              url == "/searchId.page" ||
-              url == "/resetPswd.page"
-            ) {
+            if (url == "/searchId.page" || url == "/resetPswd.page") {
               this.$router.push({ path: "/main.page" });
             } else {
               this.$router.push({ path: url });
@@ -145,7 +149,7 @@
         },
       });
     },
-    moveResetPswd() {
+    moveResetPswd() { 
       this.$router.push({
         path: "/resetPswd.page",
         query: {
Add a comment
List