diff --git a/kicc-ui/src/api/sys/model/userModel.ts b/kicc-ui/src/api/sys/model/userModel.ts index 0b6ab320..eaa163b6 100644 --- a/kicc-ui/src/api/sys/model/userModel.ts +++ b/kicc-ui/src/api/sys/model/userModel.ts @@ -49,19 +49,31 @@ export interface LoginResultModel { * @description: Get user information return value */ export interface GetUserInfoModel { - roles: RoleInfo[]; // 用户id - userId: string | number; + id: string; // 用户名 - username: string; + userName: string; // 真实名字 nickName: string; // 头像 avatar: string; - // 介绍 - desc?: string; - // 角色Id - roleId: string | number; + // 所属部门ID + deptId: string; + // 所属部门名称 + deptName: string; + // 邮箱 + email: string; + // 菜单按钮权限 + permissions: Recordable; + // 角色ID权限 + roleIds: Recordable; + // 手机号 + phone: string; + // 备注信息 + remarks: string; + // 多租户ID + tenantId: string; + [key: string]: any; } export interface GetCaptchaModel { diff --git a/kicc-ui/src/api/sys/user.ts b/kicc-ui/src/api/sys/user.ts index a0bce66e..26b7236d 100644 --- a/kicc-ui/src/api/sys/user.ts +++ b/kicc-ui/src/api/sys/user.ts @@ -13,7 +13,7 @@ import qs from 'qs'; enum Api { Login = '/auth/oauth/token', Logout = '/mate-uaa/auth/logout', - GetUserInfo = '/mate-uaa/auth/get/user', + GetUserInfo = '/admin/system/user/info', GetPermCode = '/getPermCode', GetCaptcha = '/code', } diff --git a/kicc-ui/src/enums/cacheEnum.ts b/kicc-ui/src/enums/cacheEnum.ts index 4b203346..e96b4bd9 100644 --- a/kicc-ui/src/enums/cacheEnum.ts +++ b/kicc-ui/src/enums/cacheEnum.ts @@ -4,18 +4,18 @@ * @author: entfrm开发团队-王翔 * @create: 2022/4/9 */ +// 访问令牌密钥 +export const ACCESS_TOKEN_KEY = 'ACCESS__TOKEN__'; -// 令牌密钥 -export const TOKEN_KEY = 'TOKEN__'; +// 刷新令牌密钥 +export const REFRESH_TOKEN_KEY = 'REFRESH__TOKEN__'; +// 国际化键 export const LOCALE_KEY = 'LOCALE__'; // 用户信息键 export const USER_INFO_KEY = 'USER__INFO__'; -// 角色信息键 -export const ROLES_KEY = 'ROLES__KEY__'; - // 项目配置键 export const PROJ_CFG_KEY = 'PROJ__CFG__KEY__'; diff --git a/kicc-ui/src/hooks/web/useLockPage.ts b/kicc-ui/src/hooks/web/useLockPage.ts index f6472eec..9e550106 100644 --- a/kicc-ui/src/hooks/web/useLockPage.ts +++ b/kicc-ui/src/hooks/web/useLockPage.ts @@ -26,7 +26,7 @@ export function useLockPage() { function resetCalcLockTimeout(): void { // 未登录 - if (!userStore.getToken) { + if (!userStore.getAccessToken) { clear(); return; } @@ -50,7 +50,7 @@ export function useLockPage() { } watchEffect((onClean) => { - if (userStore.getToken) { + if (userStore.getAccessToken) { resetCalcLockTimeout(); } else { clear(); diff --git a/kicc-ui/src/hooks/web/usePermission.ts b/kicc-ui/src/hooks/web/usePermission.ts index 512a0b0f..8b383ce3 100644 --- a/kicc-ui/src/hooks/web/usePermission.ts +++ b/kicc-ui/src/hooks/web/usePermission.ts @@ -6,16 +6,18 @@ */ import type { RouteRecordRaw } from 'vue-router'; -import { usePermissionStore } from '/@/store/modules/permission'; +import { usePermissionStoreWithOut } from '/@/store/modules/permission'; import { useTabs } from './useTabs'; import { router, resetRouter } from '/@/router'; import { intersection } from 'lodash-es'; import { isArray } from '/@/utils/is'; import { useMultipleTabStore } from '/@/store/modules/multipleTab'; +import { useUserStoreWithOut } from "/@/store/modules/user"; // 用户权限相关操作 export function usePermission() { - const permissionStore = usePermissionStore(); + const permissionStore = usePermissionStoreWithOut(); + const userStore = useUserStoreWithOut(); const { closeAll } = useTabs(router); /** @@ -42,7 +44,7 @@ export function usePermission() { if (!value) { return def; } - const allCodeList = permissionStore.getPermCodeList as string[]; + const allCodeList = userStore.getPermissions as string[]; if (!isArray(value)) { return allCodeList.includes(value); } diff --git a/kicc-ui/src/router/guard/index.ts b/kicc-ui/src/router/guard/index.ts index fa577230..2caf42cd 100644 --- a/kicc-ui/src/router/guard/index.ts +++ b/kicc-ui/src/router/guard/index.ts @@ -55,7 +55,7 @@ function createPageLoadingGuard(router: Router) { const appStore = useAppStoreWithOut(); const { getOpenPageLoading } = useTransitionSetting(); router.beforeEach(async (to) => { - if (!userStore.getToken) { + if (!userStore.getAccessToken) { return true; } if (to.meta.loaded) { diff --git a/kicc-ui/src/router/guard/permissionGuard.ts b/kicc-ui/src/router/guard/permissionGuard.ts index 9f6de0e5..5104392f 100644 --- a/kicc-ui/src/router/guard/permissionGuard.ts +++ b/kicc-ui/src/router/guard/permissionGuard.ts @@ -37,7 +37,7 @@ export function createPermissionGuard(router: Router) { return; } - const token = userStore.getToken; + const token = userStore.getAccessToken; // 令牌不存在 if (!token) { diff --git a/kicc-ui/src/store/modules/lock.ts b/kicc-ui/src/store/modules/lock.ts index 1810e32e..ec2cbc12 100644 --- a/kicc-ui/src/store/modules/lock.ts +++ b/kicc-ui/src/store/modules/lock.ts @@ -47,7 +47,6 @@ export const useLockStore = defineStore({ username, password: password!, goHome: false, - mode: 'none', // todo: 锁屏解锁登录,需要验证码,后期完善 realKey: '', code: '', diff --git a/kicc-ui/src/store/modules/permission.ts b/kicc-ui/src/store/modules/permission.ts index 6b15f69f..d7e563a2 100644 --- a/kicc-ui/src/store/modules/permission.ts +++ b/kicc-ui/src/store/modules/permission.ts @@ -20,8 +20,6 @@ import { useMessage } from '/@/hooks/web/useMessage'; import { PageEnum } from '/@/enums/pageEnum'; interface PermissionState { - // 权限代码列表 - permCodeList: string[] | number[]; // 路由是否动态添加 isDynamicAddedRoute: boolean; // 触发菜单更新 @@ -33,8 +31,6 @@ interface PermissionState { export const usePermissionStore = defineStore({ id: 'app-permission', state: (): PermissionState => ({ - // 权限代码列表 - permCodeList: [], // 路由是否动态添加 isDynamicAddedRoute: false, // 触发菜单更新 @@ -43,9 +39,6 @@ export const usePermissionStore = defineStore({ menuList: [] }), getters: { - getPermCodeList(): string[] | number[] { - return this.permCodeList; - }, getMenuList(): Menu[] { return this.menuList; }, @@ -57,9 +50,6 @@ export const usePermissionStore = defineStore({ }, }, actions: { - setPermCodeList(codeList: string[]) { - this.permCodeList = codeList; - }, setMenuList(list: Menu[]) { this.menuList = list; list?.length > 0 && this.setLastBuildMenuTime(); diff --git a/kicc-ui/src/store/modules/user.ts b/kicc-ui/src/store/modules/user.ts index 9c1c50fb..42bb8eba 100644 --- a/kicc-ui/src/store/modules/user.ts +++ b/kicc-ui/src/store/modules/user.ts @@ -5,26 +5,28 @@ * @create: 2022/4/9 */ -import type { UserInfo } from '/#/store'; -import { defineStore } from 'pinia'; -import { store } from '/@/store'; -import { PageEnum } from '/@/enums/pageEnum'; -import { ROLES_KEY, TOKEN_KEY, USER_INFO_KEY } from '/@/enums/cacheEnum'; -import { getAuthCache, setAuthCache } from '/@/utils/auth'; -import { GetUserInfoModel, LoginParams } from '/@/api/sys/model/userModel'; -import { doLogout, getUserInfo, loginApi } from '/@/api/sys/user'; -import { useI18n } from '/@/hooks/web/useI18n'; -import { useMessage } from '/@/hooks/web/useMessage'; -import { router } from '/@/router'; -import { usePermissionStore } from '/@/store/modules/permission'; -import { RouteRecordRaw } from 'vue-router'; -import { PAGE_NOT_FOUND_ROUTE } from '/@/router/routes/basic'; +import type {UserInfo} from '/#/store'; +import {defineStore} from 'pinia'; +import {store} from '/@/store'; +import {PageEnum} from '/@/enums/pageEnum'; +import {ACCESS_TOKEN_KEY, REFRESH_TOKEN_KEY, USER_INFO_KEY} from '/@/enums/cacheEnum'; +import {getAuthCache, setAuthCache} from '/@/utils/auth'; +import {GetUserInfoModel, LoginParams} from '/@/api/sys/model/userModel'; +import {doLogout, getUserInfo, loginApi} from '/@/api/sys/user'; +import {useI18n} from '/@/hooks/web/useI18n'; +import {useMessage} from '/@/hooks/web/useMessage'; +import {router} from '/@/router'; +import {usePermissionStore} from '/@/store/modules/permission'; +import {RouteRecordRaw} from 'vue-router'; +import {PAGE_NOT_FOUND_ROUTE} from '/@/router/routes/basic'; interface UserState { userInfo: Nullable; - token?: string; - sessionTimeout?: boolean; - roleId: string | number; + sessionTimeout: boolean; + roleIds: Recordable; + permissions: Recordable; + access_token: string; + refresh_token: string; } export const useUserStore = defineStore({ @@ -32,64 +34,84 @@ export const useUserStore = defineStore({ state: (): UserState => ({ // 用户信息 userInfo: null, - // token - token: undefined, // 登录是否过期 sessionTimeout: false, - roleId: '', + // 角色ID用于权限校验 + roleIds: [], + // 按钮权限标识用于权限校验 + permissions: [], + // 访问令牌 + access_token: '', + // 刷新令牌 + refresh_token: '', }), getters: { - getUserInfo(): UserInfo { - return this.userInfo || getAuthCache(USER_INFO_KEY) || {}; + getUserInfo(): UserInfo | {[key: string]: any} { + return this.userInfo || {}; }, - getToken(): string { - return this.token || getAuthCache(TOKEN_KEY); + getAccessToken(): string { + return this.access_token; + }, + getRefreshToken(): string { + return this.refresh_token; }, getSessionTimeout(): boolean { return !!this.sessionTimeout; }, + getRoleIds(): Recordable { + return this.roleIds; + }, + getPermissions(): Recordable { + return this.permissions; + }, }, actions: { - setToken(info: string | undefined) { - this.token = info; - setAuthCache(TOKEN_KEY, info); + setRoleIds(roleIds: Recordable) { + this.roleIds = roleIds; + }, + setPermissions(permissions: Recordable) { + this.permissions = permissions; + }, + setAccessToken(accessToken: string) { + this.access_token = accessToken; + setAuthCache(ACCESS_TOKEN_KEY, accessToken); }, - setRoleId(roleId: string | number) { - this.roleId = roleId; - setAuthCache(ROLES_KEY, roleId); + setRefreshToken(refreshToken: string) { + this.refresh_token = refreshToken; + setAuthCache(REFRESH_TOKEN_KEY, refreshToken); }, - setUserInfo(info: UserInfo) { - this.userInfo = info; - setAuthCache(USER_INFO_KEY, info); + setUserInfo(userInfo: UserInfo) { + this.userInfo = userInfo; + setAuthCache(USER_INFO_KEY, userInfo); }, setSessionTimeout(flag: boolean) { this.sessionTimeout = flag; }, resetState() { this.userInfo = null; - this.token = ''; - this.roleId = ''; this.sessionTimeout = false; + this.access_token = ''; + this.refresh_token = ''; + this.roleIds = []; + this.permissions = []; }, - /** - * 登录 - */ + /** 登录 */ async login(params: LoginParams & { goHome?: boolean; }): Promise { try { - debugger; const { goHome = true, ...loginParams } = params; const data = await loginApi(loginParams); - const { access_token } = data; - - // 保存令牌 - this.setToken(access_token); + const { access_token, refresh_token } = data; + this.setAccessToken(access_token); + this.setRefreshToken(refresh_token); // 获取用户信息 const userInfo = await this.getUserInfoAction(); + const sessionTimeout = this.sessionTimeout; if (sessionTimeout) { this.setSessionTimeout(false); } else if (goHome) { + const permissionStore = usePermissionStore(); if (!permissionStore.isDynamicAddedRoute) { const routes = await permissionStore.buildRoutesAction(); @@ -100,6 +122,7 @@ export const useUserStore = defineStore({ permissionStore.setDynamicAddedRoute(true); } await router.replace(userInfo.homePath || PageEnum.BASE_HOME); + } return userInfo; } catch (error) { @@ -108,26 +131,25 @@ export const useUserStore = defineStore({ }, async getUserInfoAction(): Promise { const userInfo = await getUserInfo(); + // 存储用户扩展信息,便于鉴权 this.setUserInfo(userInfo); - this.setRoleId(userInfo.roleId); + this.setRoleIds(userInfo.roleIds); + this.setPermissions(userInfo.permissions); return userInfo; }, - /** - * 登出 - */ + /** 登出 */ async logout(goLogin = false) { try { await doLogout(); } catch { console.log('注销Token失败'); } - this.setToken(undefined); + this.setAccessToken(''); + this.setRefreshToken(''); this.setSessionTimeout(false); goLogin && router.push(PageEnum.BASE_LOGIN); }, - /** - * 退出前确认 - */ + /** 退出前确认 */ confirmLoginOut() { const { createConfirm } = useMessage(); const { t } = useI18n(); diff --git a/kicc-ui/src/utils/auth/index.ts b/kicc-ui/src/utils/auth/index.ts index 1ab4263d..79f4ac0d 100644 --- a/kicc-ui/src/utils/auth/index.ts +++ b/kicc-ui/src/utils/auth/index.ts @@ -8,13 +8,13 @@ import { Persistent, BasicKeys } from '/@/utils/cache/persistent'; import { CacheTypeEnum } from '/@/enums/cacheEnum'; import projectSetting from '/@/settings/projectSetting'; -import { TOKEN_KEY } from '/@/enums/cacheEnum'; +import { ACCESS_TOKEN_KEY } from '/@/enums/cacheEnum'; const { permissionCacheType } = projectSetting; const isLocal = permissionCacheType === CacheTypeEnum.LOCAL; -export function getToken() { - return getAuthCache(TOKEN_KEY); +export function getAccessToken() { + return getAuthCache(ACCESS_TOKEN_KEY); } export function getAuthCache(key: BasicKeys) { diff --git a/kicc-ui/src/utils/cache/persistent.ts b/kicc-ui/src/utils/cache/persistent.ts index cf5f96d6..bd29629a 100644 --- a/kicc-ui/src/utils/cache/persistent.ts +++ b/kicc-ui/src/utils/cache/persistent.ts @@ -13,23 +13,22 @@ import type { RouteLocationNormalized } from 'vue-router'; import { createLocalStorage, createSessionStorage } from '/@/utils/cache'; import { Memory } from './memory'; import { - TOKEN_KEY, + ACCESS_TOKEN_KEY, USER_INFO_KEY, - ROLES_KEY, LOCK_INFO_KEY, PROJ_CFG_KEY, APP_LOCAL_CACHE_KEY, APP_SESSION_CACHE_KEY, - MULTIPLE_TABS_KEY, + MULTIPLE_TABS_KEY, REFRESH_TOKEN_KEY, } from '/@/enums/cacheEnum'; import { DEFAULT_CACHE_TIME } from '/@/settings/encryptionSetting'; import { toRaw } from 'vue'; import { pick, omit } from 'lodash-es'; interface BasicStore { - [TOKEN_KEY]: string | number | null | undefined; + [ACCESS_TOKEN_KEY]: string | number | null | undefined; + [REFRESH_TOKEN_KEY]: string | number | null | undefined; [USER_INFO_KEY]: UserInfo; - [ROLES_KEY]: string[]; [LOCK_INFO_KEY]: LockInfo; [PROJ_CFG_KEY]: ProjectConfig; [MULTIPLE_TABS_KEY]: RouteLocationNormalized[]; @@ -106,15 +105,15 @@ export class Persistent { } window.addEventListener('beforeunload', function () { - // TOKEN_KEY 在登录或注销时已经写入到storage了,此处为了解决同时打开多个窗口时token不同步的问题 + // ACCESS_TOKEN_KEY 在登录或注销时已经写入到storage了,此处为了解决同时打开多个窗口时token不同步的问题 // LOCK_INFO_KEY 在锁屏和解锁时写入,此处也不应修改 ls.set(APP_LOCAL_CACHE_KEY, { ...omit(localMemory.getCache, LOCK_INFO_KEY), - ...pick(ls.get(APP_LOCAL_CACHE_KEY), [TOKEN_KEY, USER_INFO_KEY, LOCK_INFO_KEY]), + ...pick(ls.get(APP_LOCAL_CACHE_KEY), [ACCESS_TOKEN_KEY, USER_INFO_KEY, LOCK_INFO_KEY]), }); ss.set(APP_SESSION_CACHE_KEY, { ...omit(sessionMemory.getCache, LOCK_INFO_KEY), - ...pick(ss.get(APP_SESSION_CACHE_KEY), [TOKEN_KEY, USER_INFO_KEY, LOCK_INFO_KEY]), + ...pick(ss.get(APP_SESSION_CACHE_KEY), [ACCESS_TOKEN_KEY, USER_INFO_KEY, LOCK_INFO_KEY]), }); }); diff --git a/kicc-ui/src/utils/cipher.ts b/kicc-ui/src/utils/cipher.ts index dd77d2df..76edb275 100644 --- a/kicc-ui/src/utils/cipher.ts +++ b/kicc-ui/src/utils/cipher.ts @@ -32,12 +32,12 @@ export class AesEncryption { }; } - encryptByAES(cipherText: string, config?: { [key: string]: any; }) { - return encrypt(cipherText, this.key, config ?? this.getOptions).toString(); + encryptByAES(cipherText: string) { + return encrypt(cipherText, this.key, this.getOptions).toString(); } - decryptByAES(cipherText: string, config?: { [key: string]: any; }) { - return decrypt(cipherText, this.key, config ?? this.getOptions).toString(CryptoJS.enc.Utf8); + decryptByAES(cipherText: string) { + return decrypt(cipherText, this.key, this.getOptions).toString(CryptoJS.enc.Utf8); } } diff --git a/kicc-ui/src/utils/http/axios/checkStatus.ts b/kicc-ui/src/utils/http/axios/checkStatus.ts index 0a65f222..0d4df929 100644 --- a/kicc-ui/src/utils/http/axios/checkStatus.ts +++ b/kicc-ui/src/utils/http/axios/checkStatus.ts @@ -31,7 +31,8 @@ export function checkStatus(status: number, msg: string, errorMessageMode: Error case 401: errMessage = t('sys.api.errMsg401'); if (stp === SessionTimeoutProcessingEnum.PAGE_COVERAGE) { - userStore.setToken(undefined); + userStore.setAccessToken(''); + userStore.setRefreshToken(''); userStore.setSessionTimeout(true); } else { userStore.logout(true); diff --git a/kicc-ui/src/utils/http/axios/index.ts b/kicc-ui/src/utils/http/axios/index.ts index 6281fa89..0199450d 100644 --- a/kicc-ui/src/utils/http/axios/index.ts +++ b/kicc-ui/src/utils/http/axios/index.ts @@ -14,7 +14,7 @@ import { useGlobSetting } from '/@/hooks/setting'; import { useMessage } from '/@/hooks/web/useMessage'; import { RequestEnum, ResultEnum, ContentTypeEnum } from '/@/enums/httpEnum'; import { isString } from '/@/utils/is'; -import { getToken } from '/@/utils/auth'; +import { getAccessToken } from '/@/utils/auth'; import { setObjToUrlParams, deepMerge } from '/@/utils'; import { useI18n } from '/@/hooks/web/useI18n'; import { joinTimestamp, formatRequestDate } from './helper'; @@ -105,15 +105,15 @@ const transform: AxiosTransform = { */ requestInterceptors: (config, options) => { // 请求之前处理config - const token = getToken(); + const token = getAccessToken(); const { clientId, clientSecret } = globSetting; - // 是否使用JWT + // 使用token进行请求 if (token && (config as Recordable)?.requestOptions?.withToken !== false) { (config as Recordable).headers.Authorization = options.authenticationScheme ? `${options.authenticationScheme} ${token}` : token; } else { - // 添加客户端信息 + // 使用客户端信息密钥请求 (config as Recordable).headers.Authorization = `Basic ${Base64.encode(`${clientId}:${clientSecret}`)}`; } return config; @@ -167,9 +167,9 @@ const transform: AxiosTransform = { function createAxios(opt?: Partial) { return new VAxios( deepMerge({ - // JWT认证方案,例如:Bearer + // 认证方案,例如:Bearer // 其他方案: https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication#authentication_schemes - authenticationScheme: '', + authenticationScheme: 'Bearer', timeout: 10 * 1000, // 接口可能会有通用的地址部分,可以统一抽取出来 urlPrefix: urlPrefix, diff --git a/kicc-ui/src/views/sys/login/LoginForm.vue b/kicc-ui/src/views/sys/login/LoginForm.vue index af0eb6ab..c9ecc162 100644 --- a/kicc-ui/src/views/sys/login/LoginForm.vue +++ b/kicc-ui/src/views/sys/login/LoginForm.vue @@ -142,7 +142,6 @@ } async function handleLogin() { - debugger const data = await validForm(); if (!data) return; try { diff --git a/kicc-ui/types/store.d.ts b/kicc-ui/types/store.d.ts index e5a4f7dc..cf8c4579 100644 --- a/kicc-ui/types/store.d.ts +++ b/kicc-ui/types/store.d.ts @@ -17,21 +17,33 @@ export interface LockInfo { } export interface UserInfo { - roles: RoleInfo[]; // 用户id - userId: string | number; + id: string; // 用户名 - username: string; + userName: string; // 真实名字 nickName: string; // 头像 avatar: string; - // 介绍 - desc?: string; + // 所属部门ID + deptId: string; + // 所属部门名称 + deptName: string; + // 邮箱 + email: string; + // 菜单按钮权限 + permissions: Recordable; + // 角色ID权限 + roleIds: Recordable; + // 手机号 + phone: string; + // 备注信息 + remarks: string; + // 多租户ID + tenantId: string; + // 指定登录后首页跳转 homePath?: string; - // 角色Id - roleId: string | number; - + [key: string]: any; } export interface BeforeMiniState {