Skip to content

Commit

Permalink
feat(projects): 增加登录鉴权
Browse files Browse the repository at this point in the history
  • Loading branch information
chansee97 committed Aug 12, 2022
1 parent 0786413 commit 5e9e3d7
Show file tree
Hide file tree
Showing 19 changed files with 224 additions and 87 deletions.
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,6 @@ module.exports = {
'no-debugger': 'off', // 关闭debugger警告
'vue/multi-word-component-names': 0, // 关闭文件名多单词
// 'import/no-unresolved': ['error', { ignore: ['~icons/*'] }],
"@typescript-eslint/no-explicit-any": ["off"]
},
};
44 changes: 8 additions & 36 deletions mock/module/user.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,17 @@
import Mock from 'mockjs';
function resultSuccess(data: any, { msg = 'success' } = {}) {
return Mock.mock({
code: 200,
data,
msg,
});
}
import { resultSuccess } from '../utils';

const Random = Mock.Random;

const token = Random.string('upper', 32, 32);

const adminInfo = {
const userInfo = {
userId: '1',
username: 'admin',
realName: 'Admin',
avatar: Random.image(),
desc: 'manager',
password: Random.string('upper', 4, 16),
userName: 'admin',
realName: '管理员大人',
avatar: 'https://z3.ax1x.com/2021/10/29/5jnWgf.jpg',
role: 'admin',
password: '123456',
token,
permissions: [
{
Expand All @@ -28,18 +22,6 @@ const adminInfo = {
label: '监控页',
value: 'dashboard_monitor',
},
{
label: '工作台',
value: 'dashboard_workplace',
},
{
label: '基础列表',
value: 'basic_list',
},
{
label: '基础列表删除',
value: 'basic_list_delete',
},
],
};

Expand All @@ -49,17 +31,7 @@ export default [
timeout: 1000,
method: 'post',
response: () => {
return resultSuccess({ token });
},
},
{
url: '/mock/admin_info',
timeout: 1000,
method: 'get',
response: () => {
// const token = getRequestToken(request);
// if (!token) return resultError('Invalid token');
return resultSuccess(adminInfo);
return resultSuccess(userInfo);
},
},
];
16 changes: 16 additions & 0 deletions mock/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import Mock from 'mockjs';

export function resultSuccess(data: any, { msg = 'success' } = {}) {
return Mock.mock({
code: 200,
data,
msg,
});
}
export function resultFailed(data: any, { msg = 'failed' } = {}) {
return Mock.mock({
code: 400,
data,
msg,
});
}
5 changes: 5 additions & 0 deletions src/enum/common.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/* 缓存的Key值 */
export enum EnumStorageKey {
userInfo = '__USER_INFO__',
token = '__TOKEN__',
}
1 change: 1 addition & 0 deletions src/enum/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './common';
4 changes: 2 additions & 2 deletions src/layouts/BasicLayout/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<Logo />
<Menu />
</n-layout-sider>
<n-layout class="h-full bg-hex-f3f4f6" :native-scrollbar="false">
<n-layout class="h-full" :native-scrollbar="false" embedded>
<n-layout-header bordered class="h-60px flex-y-center justify-between">
<div class="flex-y-center h-full">
<CollapaseButton />
Expand All @@ -30,7 +30,7 @@
</router-view>
</n-layout-content>
</div>
<n-layout-footer position="absolute" bordered class="flex-center bg-white h-40px">
<n-layout-footer position="absolute" bordered class="flex-center h-40px">
{{ appStore.footerText }}
</n-layout-footer>
</n-layout>
Expand Down
2 changes: 1 addition & 1 deletion src/layouts/components/header/UserCenter.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<n-dropdown trigger="hover" :options="options" @select="handleSelect">
<n-dropdown trigger="click" :options="options" @select="handleSelect">
<HeaderButton>
<n-avatar round size="large" src="https://z3.ax1x.com/2021/10/29/5jnWgf.jpg" />
{{ authStore.name }}
Expand Down
17 changes: 16 additions & 1 deletion src/router/guard/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,22 @@
import type { Router } from 'vue-router';
import { getToken } from '@/utils/auth';

// const authStore = useAuthStore();

export function setupRouterGuard(router: Router) {
router.beforeEach((_to, _from, next) => {
const isLogin = Boolean(getToken());

router.beforeEach((to, _from, next) => {
// 登录鉴权
if (!isLogin) {
if (to.name === 'login') {
next();
} else {
const redirect = to.fullPath;
next({ path: '/login', query: { redirect } });
}
return false;
}
next();
});
// router.afterEach((_to) => {});
Expand Down
2 changes: 1 addition & 1 deletion src/router/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ const routes: RouteRecordRaw[] = [
},
{
path: '/login',
name: 'Login',
name: 'login',
component: () => import('@/views/login/index.vue'), // 注意这里要带上 文件后缀.vue
},
{
Expand Down
1 change: 0 additions & 1 deletion src/service/api/index.ts

This file was deleted.

31 changes: 5 additions & 26 deletions src/service/api/login.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,9 @@
import { request } from '../http';
import { mockRequest } from '../http';

interface Itest {
data: string;
interface Ilogin {
userName: string;
password: string;
}
/* get方法测试 */
export function fetachGet() {
return request.get('/getAPI');
}
/* post方法测试 */
export function fetachPost(params: Itest) {
return request.post('/postAPI', params);
}
/* delete方法测试 */
export function fetachDelete() {
return request.Delete('/deleteAPI');
}
/* put方法测试 */
export function fetachPut(params: Itest) {
return request.put('/putAPI', params);
}
/* patch方法测试 */
export function fetachPatch(params: Itest) {
return request.patch('/patchAPI', params);
}
/* mock方法测试 */
export function fetchMock() {
return mockRequest.post('/login');
export function fetchLogin(params: Ilogin) {
return mockRequest.post('/login', params);
}
30 changes: 30 additions & 0 deletions src/service/api/test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { request } from '../http';
import { mockRequest } from '../http';

interface Itest {
data: string;
}
/* get方法测试 */
export function fetachGet() {
return request.get('/getAPI');
}
/* post方法测试 */
export function fetachPost(params: Itest) {
return request.post('/postAPI', params);
}
/* delete方法测试 */
export function fetachDelete() {
return request.Delete('/deleteAPI');
}
/* put方法测试 */
export function fetachPut(params: Itest) {
return request.put('/putAPI', params);
}
/* patch方法测试 */
export function fetachPatch(params: Itest) {
return request.patch('/patchAPI', params);
}
/* mock方法测试 */
export function fetchMock() {
return mockRequest.post('/login');
}
2 changes: 2 additions & 0 deletions src/service/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './api/test';
export * from './api/login';
48 changes: 47 additions & 1 deletion src/store/modules/auth.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,55 @@
import { defineStore } from 'pinia';
import { fetchLogin } from '@/service';
import { setUserInfo, getUserInfo, getToken, setToken } from '@/utils/auth';
import { router } from '@/router';

export const useAuthStore = defineStore('auth-store', {
state: () => {
return {
name: '张三',
userInfo: getUserInfo(),
token: getToken(),
loginLoading: false,
};
},
getters: {
/** 是否登录 */
isLogin(state) {
return Boolean(state.token);
},
},
actions: {
/* 用户登录 */
async login(userName: string, password: string) {
this.loginLoading = true;
const data = await fetchLogin({ userName, password });

// 处理登录信息
this.handleAfterLogin(data as any);

this.loginLoading = false;
},
handleAfterLogin(data: Auth.UserInfo) {
// 存储用户信息
setUserInfo(data);
setToken(data.token);
this.userInfo = data;
this.token = data.token;

// 触发用户提示
window.$notification?.success({
title: '登录成功!',
content: `欢迎回来,${this.userInfo.realName}!`,
duration: 3000,
});

// 进行跳转
const route = router.currentRoute;
const { query } = route.value;
if (query?.redirect) {
router.push(query.redirect as string);
} else {
router.push('/');
}
},
},
});
7 changes: 7 additions & 0 deletions src/types/api.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/* 接口类型数据 */

/** 后端返回的用户相关类型 */
declare namespace ApiAuth {
/** 返回的用户信息 */
type UserInfo = Auth.UserInfo;
}
31 changes: 31 additions & 0 deletions src/types/business.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/** 用户相关模块 */
declare namespace Auth {
/**
* 用户角色类型(前端静态路由用角色类型进行路由权限的控制)
* - super: 超级管理员(该权限具有所有路由数据)
* - admin: 管理员
* - user: 用户
* - custom: 自定义角色
*/
// type RoleType = keyof typeof import('@/enum').EnumUserRole;

/** 用户信息 */
interface UserInfo {
/** 用户id */
userId: string;
/** 用户名 */
userName: string;
/* 用户称呼 */
realName: string;
/* 用户头像 */
avatar: string;
/** 用户角色类型 */
role: RoleType;
/* 密码 */
password: string;
/* token */
token: string;
/* 权限路由 */
permissions: [];
}
}
34 changes: 34 additions & 0 deletions src/utils/auth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { setLocal, getLocal, removeLocal } from './storage';
import { EnumStorageKey } from '@/enum';

/* 获取当前token */
export function getToken() {
return getLocal(EnumStorageKey.token);
}
/* 设置token */
export function setToken(data: string) {
setLocal(EnumStorageKey.token, data);
}
/* 移除token */
export function removeToken() {
removeLocal(EnumStorageKey.token);
}

/* 获取用户详情 */
export function getUserInfo() {
return getLocal(EnumStorageKey.userInfo);
}
/* 设置用户详情 */
export function setUserInfo(data: any) {
setLocal(EnumStorageKey.userInfo, data);
}
/* 移除用户详情 */
export function removeUserInfo() {
removeLocal(EnumStorageKey.userInfo);
}

/** 去除用户相关缓存 */
export function clearAuthStorage() {
removeToken();
removeUserInfo();
}
Loading

0 comments on commit 5e9e3d7

Please sign in to comment.