mirror of
https://github.com/soybeanjs/soybean-admin.git
synced 2025-09-30 23:26:41 +08:00
feat(projects): 抽离部分登陆逻辑,支持Token或JWT校验方式
This commit is contained in:
parent
34ffd9c1f3
commit
34fcf4ca26
@ -23,7 +23,7 @@ const apis: MockMethod[] = [
|
||||
{
|
||||
url: '/mock/login',
|
||||
method: 'post',
|
||||
response: (options: Service.MockOption): Service.MockServiceResult<ApiAuth.Token | null> => {
|
||||
response: (options: Service.MockOption): Service.MockServiceResult<ApiAuth.JWT | null> => {
|
||||
const { userName = undefined, password = undefined } = options.body;
|
||||
|
||||
if (!userName || !password) {
|
||||
@ -101,7 +101,7 @@ const apis: MockMethod[] = [
|
||||
{
|
||||
url: '/mock/updateToken',
|
||||
method: 'post',
|
||||
response: (options: Service.MockOption): Service.MockServiceResult<ApiAuth.Token | null> => {
|
||||
response: (options: Service.MockOption): Service.MockServiceResult<ApiAuth.JWT | null> => {
|
||||
const { refreshToken = '' } = options.body;
|
||||
|
||||
const findItem = userModel.find(item => item.refreshToken === refreshToken);
|
||||
|
@ -10,14 +10,23 @@ export function fetchSmsCode(phone: string) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录
|
||||
* 登录(Token认证方式)
|
||||
* @param userName - 用户名
|
||||
* @param password - 密码
|
||||
*/
|
||||
export function fetchLogin(userName: string, password: string) {
|
||||
export function fetchLoginToken(userName: string, password: string) {
|
||||
return mockRequest.post<ApiAuth.Token>('/login', { userName, password });
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录(JWT认证方式)
|
||||
* @param userName - 用户名
|
||||
* @param password - 密码
|
||||
*/
|
||||
export function fetchLoginJWT(userName: string, password: string) {
|
||||
return mockRequest.post<ApiAuth.JWT>('/login', { userName, password });
|
||||
}
|
||||
|
||||
/** 获取用户信息 */
|
||||
export function fetchUserInfo() {
|
||||
return mockRequest.get<ApiAuth.UserInfo>('/getUserInfo');
|
||||
@ -37,5 +46,5 @@ export function fetchUserRoutes(userId: string) {
|
||||
* @param refreshToken
|
||||
*/
|
||||
export function fetchUpdateToken(refreshToken: string) {
|
||||
return mockRequest.post<ApiAuth.Token>('/updateToken', { refreshToken });
|
||||
return mockRequest.post<ApiAuth.JWT>('/updateToken', { refreshToken });
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ import {
|
||||
handleServiceResult,
|
||||
transformRequestData
|
||||
} from '@/utils';
|
||||
import { handleRefreshToken } from './helpers';
|
||||
import { defaultAuthType } from '@/store/modules/auth/auth-type';
|
||||
|
||||
/**
|
||||
* 封装axios请求类
|
||||
@ -71,7 +71,7 @@ export default class CustomAxiosInstance {
|
||||
|
||||
// token失效, 刷新token
|
||||
if (REFRESH_TOKEN_CODE.includes(backend[codeKey])) {
|
||||
const config = await handleRefreshToken(response.config);
|
||||
const config = await defaultAuthType.handleTokenFailure(response.config);
|
||||
if (config) {
|
||||
return this.instance.request(config);
|
||||
}
|
||||
|
46
src/store/modules/auth/auth-type.ts
Normal file
46
src/store/modules/auth/auth-type.ts
Normal file
@ -0,0 +1,46 @@
|
||||
import type { AxiosRequestConfig } from 'axios';
|
||||
import { fetchLoginToken, fetchLoginJWT } from '@/service';
|
||||
import { useAuthStore } from '@/store';
|
||||
import { localStg } from '@/utils';
|
||||
import { handleRefreshToken } from '@/service/request/helpers';
|
||||
|
||||
const TokenAuth = {
|
||||
/** 获取token的接口 */
|
||||
fetchLogin: fetchLoginToken,
|
||||
/** 请求登录成功后的数据处理回调 */
|
||||
handleAuthToken(backendToken: ApiAuth.Token) {
|
||||
// 先把token存储到缓存中(后面接口的请求头需要token)
|
||||
const { token } = backendToken;
|
||||
// token由后端控制刷新,不需要前端处理刷新逻辑
|
||||
localStg.set('token', token, null);
|
||||
},
|
||||
/** Token失效后的回调 */
|
||||
async handleTokenFailure(_: AxiosRequestConfig) {
|
||||
// token失效说明已经超过了可刷新token时间,需要重新登录
|
||||
const { resetAuthStore } = useAuthStore();
|
||||
resetAuthStore();
|
||||
}
|
||||
};
|
||||
|
||||
const JWTAuth = {
|
||||
fetchLogin: fetchLoginJWT,
|
||||
/** 请求登录成功后的数据处理回调 */
|
||||
handleAuthToken(backendToken: ApiAuth.JWT) {
|
||||
// 先把token存储到缓存中(后面接口的请求头需要token)
|
||||
const { token, refreshToken } = backendToken;
|
||||
localStg.set('token', token);
|
||||
localStg.set('refreshToken', refreshToken);
|
||||
},
|
||||
/** Token失效后的回调 */
|
||||
async handleTokenFailure(axiosConfig: AxiosRequestConfig) {
|
||||
return handleRefreshToken(axiosConfig);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 选择需要使用哪种认证方式,默认选择JWT方式
|
||||
*/
|
||||
const defaultAuthType = JWTAuth;
|
||||
|
||||
// 如果只使用JWTAuth,不导出会导致TokenAuth报未使用的ts、eslint错误
|
||||
export { defaultAuthType, JWTAuth, TokenAuth };
|
@ -1,11 +1,12 @@
|
||||
import { unref, nextTick } from 'vue';
|
||||
import { defineStore } from 'pinia';
|
||||
import { router } from '@/router';
|
||||
import { fetchLogin, fetchUserInfo } from '@/service';
|
||||
import { fetchUserInfo } from '@/service';
|
||||
import { useRouteStore } from '@/store';
|
||||
import { useRouterPush } from '@/composables';
|
||||
import { localStg } from '@/utils';
|
||||
import { useTabStore } from '../tab';
|
||||
import { useRouteStore } from '../route';
|
||||
import { defaultAuthType } from './auth-type';
|
||||
import { getToken, getUserInfo, clearAuthStorage } from './helpers';
|
||||
|
||||
interface AuthState {
|
||||
@ -53,59 +54,35 @@ export const useAuthStore = defineStore('auth-store', {
|
||||
* 处理登录后成功或失败的逻辑
|
||||
* @param backendToken - 返回的token
|
||||
*/
|
||||
async handleActionAfterLogin(backendToken: ApiAuth.Token) {
|
||||
async handleActionAfterLogin(backendToken: ApiAuth.Token | ApiAuth.JWT) {
|
||||
const route = useRouteStore();
|
||||
const { toLoginRedirect } = useRouterPush(false);
|
||||
|
||||
const loginSuccess = await this.loginByToken(backendToken);
|
||||
|
||||
if (loginSuccess) {
|
||||
await route.initAuthRoute();
|
||||
|
||||
// 跳转登录后的地址
|
||||
toLoginRedirect();
|
||||
|
||||
// 登录成功弹出欢迎提示
|
||||
if (route.isInitAuthRoute) {
|
||||
window.$notification?.success({
|
||||
title: '登录成功!',
|
||||
content: `欢迎回来,${this.userInfo.userName}!`,
|
||||
duration: 3000
|
||||
});
|
||||
}
|
||||
// 保存token到store
|
||||
this.token = backendToken.token;
|
||||
|
||||
// 获取用户信息
|
||||
const userInfo = await this.updateUserInfo();
|
||||
if (!userInfo) {
|
||||
// 获取数据失败,重置状态,退出
|
||||
this.resetAuthStore();
|
||||
return;
|
||||
}
|
||||
|
||||
// 不成功则重置状态
|
||||
this.resetAuthStore();
|
||||
},
|
||||
/**
|
||||
* 根据token进行登录
|
||||
* @param backendToken - 返回的token
|
||||
*/
|
||||
async loginByToken(backendToken: ApiAuth.Token) {
|
||||
let successFlag = false;
|
||||
// 初始化路由
|
||||
await route.initAuthRoute();
|
||||
|
||||
// 先把token存储到缓存中(后面接口的请求头需要token)
|
||||
const { token, refreshToken } = backendToken;
|
||||
localStg.set('token', token);
|
||||
localStg.set('refreshToken', refreshToken);
|
||||
// 跳转登录后的地址
|
||||
toLoginRedirect();
|
||||
|
||||
// 获取用户信息
|
||||
const { data } = await fetchUserInfo();
|
||||
if (data) {
|
||||
// 成功后把用户信息存储到缓存中
|
||||
localStg.set('userInfo', data);
|
||||
|
||||
// 更新状态
|
||||
this.userInfo = data;
|
||||
this.token = token;
|
||||
|
||||
successFlag = true;
|
||||
// 登录成功弹出欢迎提示
|
||||
if (route.isInitAuthRoute) {
|
||||
window.$notification?.success({
|
||||
title: '登录成功!',
|
||||
content: `欢迎回来,${this.userInfo.userName}!`,
|
||||
duration: 3000
|
||||
});
|
||||
}
|
||||
|
||||
return successFlag;
|
||||
},
|
||||
/**
|
||||
* 登录
|
||||
@ -114,12 +91,28 @@ export const useAuthStore = defineStore('auth-store', {
|
||||
*/
|
||||
async login(userName: string, password: string) {
|
||||
this.loginLoading = true;
|
||||
const { data } = await fetchLogin(userName, password);
|
||||
const { data } = await defaultAuthType.fetchLogin(userName, password);
|
||||
if (data) {
|
||||
// 登录成功后对返回的Token或者JWT处理
|
||||
defaultAuthType.handleAuthToken(data);
|
||||
await this.handleActionAfterLogin(data);
|
||||
}
|
||||
this.loginLoading = false;
|
||||
},
|
||||
/**
|
||||
* 查询用户信息并更新到store
|
||||
*/
|
||||
async updateUserInfo() {
|
||||
const { data } = await fetchUserInfo();
|
||||
if (data) {
|
||||
// 成功后把用户信息存储到缓存中
|
||||
localStg.set('userInfo', data);
|
||||
// 更新状态
|
||||
this.userInfo = data;
|
||||
return data;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
/**
|
||||
* 更换用户权限(切换账号)
|
||||
* @param userRole
|
||||
@ -142,9 +135,10 @@ export const useAuthStore = defineStore('auth-store', {
|
||||
}
|
||||
};
|
||||
const { userName, password } = accounts[userRole];
|
||||
const { data } = await fetchLogin(userName, password);
|
||||
const { data } = await defaultAuthType.fetchLogin(userName, password);
|
||||
if (data) {
|
||||
await this.loginByToken(data);
|
||||
this.token = data.token;
|
||||
defaultAuthType.handleAuthToken(data);
|
||||
resetRouteStore();
|
||||
initAuthRoute();
|
||||
}
|
||||
|
6
src/typings/api.d.ts
vendored
6
src/typings/api.d.ts
vendored
@ -2,9 +2,13 @@
|
||||
|
||||
/** 后端返回的用户权益相关类型 */
|
||||
declare namespace ApiAuth {
|
||||
/** 返回的token和刷新token */
|
||||
/** 返回的token */
|
||||
interface Token {
|
||||
token: string;
|
||||
}
|
||||
/** 返回的token和刷新token */
|
||||
interface JWT {
|
||||
token: string;
|
||||
refreshToken: string;
|
||||
}
|
||||
/** 返回的用户信息 */
|
||||
|
Loading…
Reference in New Issue
Block a user