Commit e5f37885ffb32d04d244f0ef39ac660dda6b71e1

Authored by 无木
1 parent d7b84c78

fix: multi windows token sharing

修复同时打开多个窗口时令牌没能同步共享的问题

fixed: #761
CHANGELOG.zh_CN.md
@@ -12,6 +12,7 @@ @@ -12,6 +12,7 @@
12 - **Table** 修复为 table 提供 rowSelection.onChange 时,无法手动变更 table 的选中项的问题 12 - **Table** 修复为 table 提供 rowSelection.onChange 时,无法手动变更 table 的选中项的问题
13 - **Icon** 修复 SvgIcon 缺少部分样式的问题 13 - **Icon** 修复 SvgIcon 缺少部分样式的问题
14 - **LockScreen** 修复锁屏功能可以通过刷新页面或复制 URL 打开新的浏览器标签来跳过锁定状态的问题 14 - **LockScreen** 修复锁屏功能可以通过刷新页面或复制 URL 打开新的浏览器标签来跳过锁定状态的问题
  15 +- 修复多个窗口同时打开页面时,`Token` 不会同步的问题
15 16
16 ## 2.5.2(2021-06-27) 17 ## 2.5.2(2021-06-27)
17 18
mock/sys/user.ts
@@ -95,4 +95,18 @@ export default [ @@ -95,4 +95,18 @@ export default [
95 return resultSuccess(codeList); 95 return resultSuccess(codeList);
96 }, 96 },
97 }, 97 },
  98 + {
  99 + url: '/basic-api/logout',
  100 + timeout: 200,
  101 + method: 'get',
  102 + response: (request: requestParams) => {
  103 + const token = getRequestToken(request);
  104 + if (!token) return resultError('Invalid token');
  105 + const checkUser = createFakeUserList().find((item) => item.token === token);
  106 + if (!checkUser) {
  107 + return resultError('Invalid token!');
  108 + }
  109 + return resultSuccess(undefined, { message: 'Token has been destroyed' });
  110 + },
  111 + },
98 ] as MockMethod[]; 112 ] as MockMethod[];
src/api/sys/user.ts
@@ -5,6 +5,7 @@ import { ErrorMessageMode } from '/#/axios'; @@ -5,6 +5,7 @@ import { ErrorMessageMode } from '/#/axios';
5 5
6 enum Api { 6 enum Api {
7 Login = '/login', 7 Login = '/login',
  8 + Logout = '/logout',
8 GetUserInfo = '/getUserInfo', 9 GetUserInfo = '/getUserInfo',
9 GetPermCode = '/getPermCode', 10 GetPermCode = '/getPermCode',
10 } 11 }
@@ -34,3 +35,7 @@ export function getUserInfo() { @@ -34,3 +35,7 @@ export function getUserInfo() {
34 export function getPermCode() { 35 export function getPermCode() {
35 return defHttp.get<string[]>({ url: Api.GetPermCode }); 36 return defHttp.get<string[]>({ url: Api.GetPermCode });
36 } 37 }
  38 +
  39 +export function doLogout() {
  40 + return defHttp.get({ url: Api.Logout });
  41 +}
src/store/modules/user.ts
@@ -7,7 +7,7 @@ import { PageEnum } from &#39;/@/enums/pageEnum&#39;; @@ -7,7 +7,7 @@ import { PageEnum } from &#39;/@/enums/pageEnum&#39;;
7 import { ROLES_KEY, TOKEN_KEY, USER_INFO_KEY } from '/@/enums/cacheEnum'; 7 import { ROLES_KEY, TOKEN_KEY, USER_INFO_KEY } from '/@/enums/cacheEnum';
8 import { getAuthCache, setAuthCache } from '/@/utils/auth'; 8 import { getAuthCache, setAuthCache } from '/@/utils/auth';
9 import { GetUserInfoModel, LoginParams } from '/@/api/sys/model/userModel'; 9 import { GetUserInfoModel, LoginParams } from '/@/api/sys/model/userModel';
10 -import { getUserInfo, loginApi } from '/@/api/sys/user'; 10 +import { doLogout, getUserInfo, loginApi } from '/@/api/sys/user';
11 import { useI18n } from '/@/hooks/web/useI18n'; 11 import { useI18n } from '/@/hooks/web/useI18n';
12 import { useMessage } from '/@/hooks/web/useMessage'; 12 import { useMessage } from '/@/hooks/web/useMessage';
13 import { router } from '/@/router'; 13 import { router } from '/@/router';
@@ -105,7 +105,14 @@ export const useUserStore = defineStore({ @@ -105,7 +105,14 @@ export const useUserStore = defineStore({
105 /** 105 /**
106 * @description: logout 106 * @description: logout
107 */ 107 */
108 - logout(goLogin = false) { 108 + async logout(goLogin = false) {
  109 + try {
  110 + await doLogout();
  111 + } catch {
  112 + console.log('注销Token失败');
  113 + }
  114 + this.setToken(undefined);
  115 + this.setSessionTimeout(false);
109 goLogin && router.push(PageEnum.BASE_LOGIN); 116 goLogin && router.push(PageEnum.BASE_LOGIN);
110 }, 117 },
111 118
src/utils/auth/index.ts
@@ -19,3 +19,8 @@ export function setAuthCache(key: BasicKeys, value) { @@ -19,3 +19,8 @@ export function setAuthCache(key: BasicKeys, value) {
19 const fn = isLocal ? Persistent.setLocal : Persistent.setSession; 19 const fn = isLocal ? Persistent.setLocal : Persistent.setSession;
20 return fn(key, value, true); 20 return fn(key, value, true);
21 } 21 }
  22 +
  23 +export function clearAuthCache(immediate = true) {
  24 + const fn = isLocal ? Persistent.clearLocal : Persistent.clearSession;
  25 + return fn(immediate);
  26 +}
src/utils/cache/persistent.ts
@@ -16,6 +16,7 @@ import { @@ -16,6 +16,7 @@ import {
16 } from '/@/enums/cacheEnum'; 16 } from '/@/enums/cacheEnum';
17 import { DEFAULT_CACHE_TIME } from '/@/settings/encryptionSetting'; 17 import { DEFAULT_CACHE_TIME } from '/@/settings/encryptionSetting';
18 import { toRaw } from 'vue'; 18 import { toRaw } from 'vue';
  19 +import { pick } from 'lodash-es';
19 20
20 interface BasicStore { 21 interface BasicStore {
21 [TOKEN_KEY]: string | number | null | undefined; 22 [TOKEN_KEY]: string | number | null | undefined;
@@ -96,8 +97,15 @@ export class Persistent { @@ -96,8 +97,15 @@ export class Persistent {
96 } 97 }
97 98
98 window.addEventListener('beforeunload', function () { 99 window.addEventListener('beforeunload', function () {
99 - ls.set(APP_LOCAL_CACHE_KEY, localMemory.getCache);  
100 - ss.set(APP_SESSION_CACHE_KEY, sessionMemory.getCache); 100 + // TOKEN_KEY 在登录或注销时已经写入到storage了,此处为了解决同时打开多个窗口时token不同步的问题
  101 + ls.set(APP_LOCAL_CACHE_KEY, {
  102 + ...localMemory.getCache,
  103 + ...pick(ls.get(APP_LOCAL_CACHE_KEY), [TOKEN_KEY, USER_INFO_KEY]),
  104 + });
  105 + ss.set(APP_SESSION_CACHE_KEY, {
  106 + ...sessionMemory.getCache,
  107 + ...pick(sessionMemory.getCache, [TOKEN_KEY, USER_INFO_KEY]),
  108 + });
101 }); 109 });
102 110
103 function storageChange(e: any) { 111 function storageChange(e: any) {