mirror of
https://github.com/pure-admin/pure-admin-thin.git
synced 2025-04-24 23:47:17 +08:00
perf: 登录
This commit is contained in:
parent
52ab1f8a33
commit
cdac80a1c2
@ -82,7 +82,7 @@ login:
|
|||||||
verifyCodeSixReg: Please enter a 6-digit verify code
|
verifyCodeSixReg: Please enter a 6-digit verify code
|
||||||
phoneReg: Please enter the phone
|
phoneReg: Please enter the phone
|
||||||
phoneCorrectReg: Please enter the correct phone number format
|
phoneCorrectReg: Please enter the correct phone number format
|
||||||
passwordRuleReg: The password format should be any combination of 8-18 digits
|
passwordRuleReg: The password format should be any combination of 5-12 digits
|
||||||
passwordSureReg: Please enter confirm password
|
passwordSureReg: Please enter confirm password
|
||||||
passwordDifferentReg: The two passwords do not match!
|
passwordDifferentReg: The two passwords do not match!
|
||||||
passwordUpdateReg: Password has been updated
|
passwordUpdateReg: Password has been updated
|
||||||
|
@ -82,7 +82,7 @@ login:
|
|||||||
verifyCodeSixReg: 请输入6位数字验证码
|
verifyCodeSixReg: 请输入6位数字验证码
|
||||||
phoneReg: 请输入手机号码
|
phoneReg: 请输入手机号码
|
||||||
phoneCorrectReg: 请输入正确的手机号码格式
|
phoneCorrectReg: 请输入正确的手机号码格式
|
||||||
passwordRuleReg: 密码格式应为8-18位数字、字母、符号的任意两种组合
|
passwordRuleReg: 密码格式应为5-12位数字、字母、符号的任意两种组合
|
||||||
passwordSureReg: 请输入确认密码
|
passwordSureReg: 请输入确认密码
|
||||||
passwordDifferentReg: 两次密码不一致!
|
passwordDifferentReg: 两次密码不一致!
|
||||||
passwordUpdateReg: 修改密码成功
|
passwordUpdateReg: 修改密码成功
|
||||||
|
@ -14,7 +14,6 @@ export default defineFakeRoute([
|
|||||||
// 一个用户可能有多个角色
|
// 一个用户可能有多个角色
|
||||||
roles: ["admin"],
|
roles: ["admin"],
|
||||||
accessToken: "eyJhbGciOiJIUzUxMiJ9.admin",
|
accessToken: "eyJhbGciOiJIUzUxMiJ9.admin",
|
||||||
refreshToken: "eyJhbGciOiJIUzUxMiJ9.adminRefresh",
|
|
||||||
expires: "2030/10/30 00:00:00"
|
expires: "2030/10/30 00:00:00"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -26,7 +25,6 @@ export default defineFakeRoute([
|
|||||||
// 一个用户可能有多个角色
|
// 一个用户可能有多个角色
|
||||||
roles: ["common"],
|
roles: ["common"],
|
||||||
accessToken: "eyJhbGciOiJIUzUxMiJ9.common",
|
accessToken: "eyJhbGciOiJIUzUxMiJ9.common",
|
||||||
refreshToken: "eyJhbGciOiJIUzUxMiJ9.commonRefresh",
|
|
||||||
expires: "2030/10/30 00:00:00"
|
expires: "2030/10/30 00:00:00"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
import { defineFakeRoute } from "vite-plugin-fake-server/client";
|
|
||||||
|
|
||||||
// 模拟刷新token接口
|
|
||||||
export default defineFakeRoute([
|
|
||||||
{
|
|
||||||
url: "/refresh-token",
|
|
||||||
method: "post",
|
|
||||||
response: ({ body }) => {
|
|
||||||
if (body.refreshToken) {
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
data: {
|
|
||||||
accessToken: "eyJhbGciOiJIUzUxMiJ9.newAdmin",
|
|
||||||
refreshToken: "eyJhbGciOiJIUzUxMiJ9.newAdminRefresh",
|
|
||||||
// `expires`选择这种日期格式是为了方便调试,后端直接设置时间戳或许更方便(每次都应该递增)。如果后端返回的是时间戳格式,前端开发请来到这个目录`src/utils/auth.ts`,把第`38`行的代码换成expires = data.expires即可。
|
|
||||||
expires: "2030/10/30 23:59:59"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
data: {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]);
|
|
@ -76,7 +76,8 @@
|
|||||||
"vue-i18n": "^9.10.1",
|
"vue-i18n": "^9.10.1",
|
||||||
"vue-router": "^4.3.0",
|
"vue-router": "^4.3.0",
|
||||||
"vue-tippy": "^6.4.1",
|
"vue-tippy": "^6.4.1",
|
||||||
"vue-types": "^5.1.1"
|
"vue-types": "^5.1.1",
|
||||||
|
"jsencrypt": "^3.3.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@commitlint/cli": "^18.6.1",
|
"@commitlint/cli": "^18.6.1",
|
||||||
|
7
pnpm-lock.yaml
generated
7
pnpm-lock.yaml
generated
@ -44,6 +44,9 @@ dependencies:
|
|||||||
js-cookie:
|
js-cookie:
|
||||||
specifier: ^3.0.5
|
specifier: ^3.0.5
|
||||||
version: 3.0.5
|
version: 3.0.5
|
||||||
|
jsencrypt:
|
||||||
|
specifier: ^3.3.2
|
||||||
|
version: 3.3.2
|
||||||
localforage:
|
localforage:
|
||||||
specifier: ^1.10.0
|
specifier: ^1.10.0
|
||||||
version: 1.10.0
|
version: 1.10.0
|
||||||
@ -3907,6 +3910,10 @@ packages:
|
|||||||
argparse: 2.0.1
|
argparse: 2.0.1
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/jsencrypt@3.3.2:
|
||||||
|
resolution: {integrity: sha512-arQR1R1ESGdAxY7ZheWr12wCaF2yF47v5qpB76TtV64H1pyGudk9Hvw8Y9tb/FiTIaaTRUyaSnm5T/Y53Ghm/A==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/jsesc@2.5.2:
|
/jsesc@2.5.2:
|
||||||
resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==}
|
resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
|
67
src/api/login.ts
Normal file
67
src/api/login.ts
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
import { http } from "@/utils/http";
|
||||||
|
import { ApiAbstract } from "@/utils/http/ApiAbstract";
|
||||||
|
import { baseUrlAuth } from "./utils";
|
||||||
|
import Cookies from "js-cookie";
|
||||||
|
export class UserResult extends ApiAbstract {
|
||||||
|
declare data: {
|
||||||
|
img: string;
|
||||||
|
uuid: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
export interface UserUser {
|
||||||
|
avatarName?: string;
|
||||||
|
avatarPath?: string;
|
||||||
|
createTime?: Date;
|
||||||
|
dept?: any;
|
||||||
|
deptId?: 0;
|
||||||
|
email?: string;
|
||||||
|
enabled?: boolean;
|
||||||
|
gender?: string;
|
||||||
|
id?: Number;
|
||||||
|
isAdmin?: boolean;
|
||||||
|
jobs?: any;
|
||||||
|
nickName?: string;
|
||||||
|
password?: string;
|
||||||
|
phone?: string;
|
||||||
|
roles?: any;
|
||||||
|
updateBy?: string;
|
||||||
|
updateTime?: Date;
|
||||||
|
username?: string;
|
||||||
|
}
|
||||||
|
export interface User {
|
||||||
|
authorities?: any;
|
||||||
|
dataScopes?: any;
|
||||||
|
roles?: any;
|
||||||
|
user?: UserUser;
|
||||||
|
}
|
||||||
|
export class UserLogResult extends ApiAbstract {
|
||||||
|
declare data: {
|
||||||
|
token: string;
|
||||||
|
user: User;
|
||||||
|
username: string;
|
||||||
|
roles: Array<string>;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 获取验证码 */
|
||||||
|
export const getCode = () => {
|
||||||
|
return http.request<UserResult>("get", baseUrlAuth("code"));
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 登录 */
|
||||||
|
export const login = (data?: object) => {
|
||||||
|
return http.request<UserLogResult>("post", baseUrlAuth("login"), { data });
|
||||||
|
};
|
||||||
|
/** 获取用户信息 */
|
||||||
|
export const userInfo = () => {
|
||||||
|
return http.request<ApiAbstract>("get", baseUrlAuth("info"), null, {
|
||||||
|
headers: {
|
||||||
|
Authorization: Cookies.get("token")
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 退出登录 */
|
||||||
|
export const logout = () => {
|
||||||
|
return http.request<UserResult>("delete", baseUrlAuth("logout"));
|
||||||
|
};
|
@ -1,39 +0,0 @@
|
|||||||
import { http } from "@/utils/http";
|
|
||||||
|
|
||||||
export type UserResult = {
|
|
||||||
success: boolean;
|
|
||||||
data: {
|
|
||||||
/** 用户名 */
|
|
||||||
username: string;
|
|
||||||
/** 当前登陆用户的角色 */
|
|
||||||
roles: Array<string>;
|
|
||||||
/** `token` */
|
|
||||||
accessToken: string;
|
|
||||||
/** 用于调用刷新`accessToken`的接口时所需的`token` */
|
|
||||||
refreshToken: string;
|
|
||||||
/** `accessToken`的过期时间(格式'xxxx/xx/xx xx:xx:xx') */
|
|
||||||
expires: Date;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export type RefreshTokenResult = {
|
|
||||||
success: boolean;
|
|
||||||
data: {
|
|
||||||
/** `token` */
|
|
||||||
accessToken: string;
|
|
||||||
/** 用于调用刷新`accessToken`的接口时所需的`token` */
|
|
||||||
refreshToken: string;
|
|
||||||
/** `accessToken`的过期时间(格式'xxxx/xx/xx xx:xx:xx') */
|
|
||||||
expires: Date;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/** 登录 */
|
|
||||||
export const getLogin = (data?: object) => {
|
|
||||||
return http.request<UserResult>("post", "/login", { data });
|
|
||||||
};
|
|
||||||
|
|
||||||
/** 刷新token */
|
|
||||||
export const refreshTokenApi = (data?: object) => {
|
|
||||||
return http.request<RefreshTokenResult>("post", "/refresh-token", { data });
|
|
||||||
};
|
|
@ -1,85 +1,30 @@
|
|||||||
import { ref, onMounted } from "vue";
|
import { ref, onMounted } from "vue";
|
||||||
|
import { getCode } from "@/api/login";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 绘制图形验证码
|
* 绘制图形验证码
|
||||||
* @param width - 图形宽度
|
* @param width - 图形宽度
|
||||||
* @param height - 图形高度
|
* @param height - 图形高度
|
||||||
*/
|
*/
|
||||||
export const useImageVerify = (width = 120, height = 40) => {
|
export const useImageVerify = () => {
|
||||||
const domRef = ref<HTMLCanvasElement>();
|
|
||||||
const imgCode = ref("");
|
const imgCode = ref("");
|
||||||
|
const imgSrc = ref("");
|
||||||
function setImgCode(code: string) {
|
|
||||||
imgCode.value = code;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getImgCode() {
|
function getImgCode() {
|
||||||
if (!domRef.value) return;
|
getCode().then(data => {
|
||||||
imgCode.value = draw(domRef.value, width, height);
|
if (data.status) {
|
||||||
|
imgCode.value = data.data.uuid;
|
||||||
|
imgSrc.value = data.data.img;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getImgCode();
|
getImgCode();
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
domRef,
|
imgSrc,
|
||||||
imgCode,
|
imgCode,
|
||||||
setImgCode,
|
|
||||||
getImgCode
|
getImgCode
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
function randomNum(min: number, max: number) {
|
|
||||||
const num = Math.floor(Math.random() * (max - min) + min);
|
|
||||||
return num;
|
|
||||||
}
|
|
||||||
|
|
||||||
function randomColor(min: number, max: number) {
|
|
||||||
const r = randomNum(min, max);
|
|
||||||
const g = randomNum(min, max);
|
|
||||||
const b = randomNum(min, max);
|
|
||||||
return `rgb(${r},${g},${b})`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function draw(dom: HTMLCanvasElement, width: number, height: number) {
|
|
||||||
let imgCode = "";
|
|
||||||
|
|
||||||
const NUMBER_STRING = "0123456789";
|
|
||||||
|
|
||||||
const ctx = dom.getContext("2d");
|
|
||||||
if (!ctx) return imgCode;
|
|
||||||
|
|
||||||
ctx.fillStyle = randomColor(180, 230);
|
|
||||||
ctx.fillRect(0, 0, width, height);
|
|
||||||
for (let i = 0; i < 4; i += 1) {
|
|
||||||
const text = NUMBER_STRING[randomNum(0, NUMBER_STRING.length)];
|
|
||||||
imgCode += text;
|
|
||||||
const fontSize = randomNum(18, 41);
|
|
||||||
const deg = randomNum(-30, 30);
|
|
||||||
ctx.font = `${fontSize}px Simhei`;
|
|
||||||
ctx.textBaseline = "top";
|
|
||||||
ctx.fillStyle = randomColor(80, 150);
|
|
||||||
ctx.save();
|
|
||||||
ctx.translate(30 * i + 15, 15);
|
|
||||||
ctx.rotate((deg * Math.PI) / 180);
|
|
||||||
ctx.fillText(text, -15 + 5, -15);
|
|
||||||
ctx.restore();
|
|
||||||
}
|
|
||||||
for (let i = 0; i < 5; i += 1) {
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.moveTo(randomNum(0, width), randomNum(0, height));
|
|
||||||
ctx.lineTo(randomNum(0, width), randomNum(0, height));
|
|
||||||
ctx.strokeStyle = randomColor(180, 230);
|
|
||||||
ctx.closePath();
|
|
||||||
ctx.stroke();
|
|
||||||
}
|
|
||||||
for (let i = 0; i < 41; i += 1) {
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.arc(randomNum(0, width), randomNum(0, height), 1, 0, 2 * Math.PI);
|
|
||||||
ctx.closePath();
|
|
||||||
ctx.fillStyle = randomColor(150, 200);
|
|
||||||
ctx.fill();
|
|
||||||
}
|
|
||||||
return imgCode;
|
|
||||||
}
|
|
||||||
|
@ -20,14 +20,8 @@ const props = withDefaults(defineProps<Props>(), {
|
|||||||
|
|
||||||
const emit = defineEmits<Emits>();
|
const emit = defineEmits<Emits>();
|
||||||
|
|
||||||
const { domRef, imgCode, setImgCode, getImgCode } = useImageVerify();
|
const { imgSrc, imgCode, getImgCode } = useImageVerify();
|
||||||
|
|
||||||
watch(
|
|
||||||
() => props.code,
|
|
||||||
newValue => {
|
|
||||||
setImgCode(newValue);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
watch(imgCode, newValue => {
|
watch(imgCode, newValue => {
|
||||||
emit("update:code", newValue);
|
emit("update:code", newValue);
|
||||||
});
|
});
|
||||||
@ -36,11 +30,10 @@ defineExpose({ getImgCode });
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<canvas
|
<el-image
|
||||||
ref="domRef"
|
style="width: 120; height: 40"
|
||||||
width="120"
|
:src="imgSrc"
|
||||||
height="40"
|
fit="contain"
|
||||||
class="cursor-pointer"
|
|
||||||
@click="getImgCode"
|
@click="getImgCode"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
@ -38,7 +38,6 @@ export type setType = {
|
|||||||
export type userType = {
|
export type userType = {
|
||||||
username?: string;
|
username?: string;
|
||||||
roles?: Array<string>;
|
roles?: Array<string>;
|
||||||
verifyCode?: string;
|
|
||||||
currentPage?: number;
|
currentPage?: number;
|
||||||
isRemembered?: boolean;
|
isRemembered?: boolean;
|
||||||
loginDay?: number;
|
loginDay?: number;
|
||||||
|
@ -4,10 +4,10 @@ import type { userType } from "./types";
|
|||||||
import { routerArrays } from "@/layout/types";
|
import { routerArrays } from "@/layout/types";
|
||||||
import { router, resetRouter } from "@/router";
|
import { router, resetRouter } from "@/router";
|
||||||
import { storageLocal } from "@pureadmin/utils";
|
import { storageLocal } from "@pureadmin/utils";
|
||||||
import { getLogin, refreshTokenApi } from "@/api/user";
|
import { type UserLogResult, login } from "@/api/login";
|
||||||
import type { UserResult, RefreshTokenResult } from "@/api/user";
|
|
||||||
import { useMultiTagsStoreHook } from "@/store/modules/multiTags";
|
import { useMultiTagsStoreHook } from "@/store/modules/multiTags";
|
||||||
import { type DataInfo, setToken, removeToken, userKey } from "@/utils/auth";
|
import { type DataInfo, setToken, removeToken, userKey } from "@/utils/auth";
|
||||||
|
import { encrypt } from "@/utils/rsaEncrypt";
|
||||||
|
|
||||||
export const useUserStore = defineStore({
|
export const useUserStore = defineStore({
|
||||||
id: "pure-user",
|
id: "pure-user",
|
||||||
@ -16,8 +16,6 @@ export const useUserStore = defineStore({
|
|||||||
username: storageLocal().getItem<DataInfo<number>>(userKey)?.username ?? "",
|
username: storageLocal().getItem<DataInfo<number>>(userKey)?.username ?? "",
|
||||||
// 页面级别权限
|
// 页面级别权限
|
||||||
roles: storageLocal().getItem<DataInfo<number>>(userKey)?.roles ?? [],
|
roles: storageLocal().getItem<DataInfo<number>>(userKey)?.roles ?? [],
|
||||||
// 前端生成的验证码(按实际需求替换)
|
|
||||||
verifyCode: "",
|
|
||||||
// 判断登录页面显示哪个组件(0:登录(默认)、1:手机登录、2:二维码登录、3:注册、4:忘记密码)
|
// 判断登录页面显示哪个组件(0:登录(默认)、1:手机登录、2:二维码登录、3:注册、4:忘记密码)
|
||||||
currentPage: 0,
|
currentPage: 0,
|
||||||
// 是否勾选了登录页的免登录
|
// 是否勾选了登录页的免登录
|
||||||
@ -34,10 +32,6 @@ export const useUserStore = defineStore({
|
|||||||
SET_ROLES(roles: Array<string>) {
|
SET_ROLES(roles: Array<string>) {
|
||||||
this.roles = roles;
|
this.roles = roles;
|
||||||
},
|
},
|
||||||
/** 存储前端生成的验证码 */
|
|
||||||
SET_VERIFYCODE(verifyCode: string) {
|
|
||||||
this.verifyCode = verifyCode;
|
|
||||||
},
|
|
||||||
/** 存储登录页面显示哪个组件 */
|
/** 存储登录页面显示哪个组件 */
|
||||||
SET_CURRENTPAGE(value: number) {
|
SET_CURRENTPAGE(value: number) {
|
||||||
this.currentPage = value;
|
this.currentPage = value;
|
||||||
@ -52,11 +46,23 @@ export const useUserStore = defineStore({
|
|||||||
},
|
},
|
||||||
/** 登入 */
|
/** 登入 */
|
||||||
async loginByUsername(data) {
|
async loginByUsername(data) {
|
||||||
return new Promise<UserResult>((resolve, reject) => {
|
return new Promise<UserLogResult>((resolve, reject) => {
|
||||||
getLogin(data)
|
login({
|
||||||
|
username: data.username,
|
||||||
|
password: encrypt(data.password),
|
||||||
|
code: data.code,
|
||||||
|
uuid: data.uuid
|
||||||
|
})
|
||||||
.then(data => {
|
.then(data => {
|
||||||
if (data) {
|
if (data) {
|
||||||
setToken(data.data);
|
//;
|
||||||
|
setToken({
|
||||||
|
accessToken: data.data.token,
|
||||||
|
username: data.data?.user?.user?.nickName,
|
||||||
|
expires: new Date("2033-03-15T12:00:00Z"),
|
||||||
|
roles: data.data?.user?.roles,
|
||||||
|
user: data.data?.user?.user
|
||||||
|
});
|
||||||
resolve(data);
|
resolve(data);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -73,21 +79,6 @@ export const useUserStore = defineStore({
|
|||||||
useMultiTagsStoreHook().handleTags("equal", [...routerArrays]);
|
useMultiTagsStoreHook().handleTags("equal", [...routerArrays]);
|
||||||
resetRouter();
|
resetRouter();
|
||||||
router.push("/login");
|
router.push("/login");
|
||||||
},
|
|
||||||
/** 刷新`token` */
|
|
||||||
async handRefreshToken(data) {
|
|
||||||
return new Promise<RefreshTokenResult>((resolve, reject) => {
|
|
||||||
refreshTokenApi(data)
|
|
||||||
.then(data => {
|
|
||||||
if (data) {
|
|
||||||
setToken(data.data);
|
|
||||||
resolve(data);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
reject(error);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -7,12 +7,12 @@ export interface DataInfo<T> {
|
|||||||
accessToken: string;
|
accessToken: string;
|
||||||
/** `accessToken`的过期时间(时间戳) */
|
/** `accessToken`的过期时间(时间戳) */
|
||||||
expires: T;
|
expires: T;
|
||||||
/** 用于调用刷新accessToken的接口时所需的token */
|
|
||||||
refreshToken: string;
|
|
||||||
/** 用户名 */
|
/** 用户名 */
|
||||||
username?: string;
|
username?: string;
|
||||||
/** 当前登陆用户的角色 */
|
/** 当前登陆用户的角色 */
|
||||||
roles?: Array<string>;
|
roles?: Array<string>;
|
||||||
|
/** 当前登陆用户的角色 */
|
||||||
|
user?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const userKey = "user-info";
|
export const userKey = "user-info";
|
||||||
@ -35,13 +35,13 @@ export function getToken(): DataInfo<number> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 设置`token`以及一些必要信息并采用无感刷新`token`方案
|
* @description 设置`token`以及一些必要信息并采用无感刷新`token`方案
|
||||||
* 无感刷新:后端返回`accessToken`(访问接口使用的`token`)、`refreshToken`(用于调用刷新`accessToken`的接口时所需的`token`,`refreshToken`的过期时间(比如30天)应大于`accessToken`的过期时间(比如2小时))、`expires`(`accessToken`的过期时间)
|
* 无感刷新:后端返回`accessToken`(访问接口使用的`token`)(用于调用刷新`accessToken`的接口时所需的`token`,的过期时间(比如30天)应大于`accessToken`的过期时间(比如2小时))、`expires`(`accessToken`的过期时间)
|
||||||
* 将`accessToken`、`expires`这两条信息放在key值为authorized-token的cookie里(过期自动销毁)
|
* 将`accessToken`、`expires`这两条信息放在key值为authorized-token的cookie里(过期自动销毁)
|
||||||
* 将`username`、`roles`、`refreshToken`、`expires`这四条信息放在key值为`user-info`的localStorage里(利用`multipleTabsKey`当浏览器完全关闭后自动销毁)
|
* 将`username`、`roles`、`expires`这四条信息放在key值为`user-info`的localStorage里(利用`multipleTabsKey`当浏览器完全关闭后自动销毁)
|
||||||
*/
|
*/
|
||||||
export function setToken(data: DataInfo<Date>) {
|
export function setToken(data: DataInfo<Date>) {
|
||||||
let expires = 0;
|
let expires = 0;
|
||||||
const { accessToken, refreshToken } = data;
|
const { accessToken } = data;
|
||||||
const { isRemembered, loginDay } = useUserStoreHook();
|
const { isRemembered, loginDay } = useUserStoreHook();
|
||||||
expires = new Date(data.expires).getTime(); // 如果后端直接设置时间戳,将此处代码改为expires = data.expires,然后把上面的DataInfo<Date>改成DataInfo<number>即可
|
expires = new Date(data.expires).getTime(); // 如果后端直接设置时间戳,将此处代码改为expires = data.expires,然后把上面的DataInfo<Date>改成DataInfo<number>即可
|
||||||
const cookieString = JSON.stringify({ accessToken, expires });
|
const cookieString = JSON.stringify({ accessToken, expires });
|
||||||
@ -62,11 +62,15 @@ export function setToken(data: DataInfo<Date>) {
|
|||||||
: {}
|
: {}
|
||||||
);
|
);
|
||||||
|
|
||||||
function setUserKey(username: string, roles: Array<string>) {
|
function setUserKey(
|
||||||
|
accessToken: string,
|
||||||
|
username: string,
|
||||||
|
roles: Array<string>
|
||||||
|
) {
|
||||||
useUserStoreHook().SET_USERNAME(username);
|
useUserStoreHook().SET_USERNAME(username);
|
||||||
useUserStoreHook().SET_ROLES(roles);
|
useUserStoreHook().SET_ROLES(roles);
|
||||||
storageLocal().setItem(userKey, {
|
storageLocal().setItem(userKey, {
|
||||||
refreshToken,
|
accessToken,
|
||||||
expires,
|
expires,
|
||||||
username,
|
username,
|
||||||
roles
|
roles
|
||||||
@ -75,13 +79,13 @@ export function setToken(data: DataInfo<Date>) {
|
|||||||
|
|
||||||
if (data.username && data.roles) {
|
if (data.username && data.roles) {
|
||||||
const { username, roles } = data;
|
const { username, roles } = data;
|
||||||
setUserKey(username, roles);
|
setUserKey(accessToken, username, roles);
|
||||||
} else {
|
} else {
|
||||||
const username =
|
const username =
|
||||||
storageLocal().getItem<DataInfo<number>>(userKey)?.username ?? "";
|
storageLocal().getItem<DataInfo<number>>(userKey)?.username ?? "";
|
||||||
const roles =
|
const roles =
|
||||||
storageLocal().getItem<DataInfo<number>>(userKey)?.roles ?? [];
|
storageLocal().getItem<DataInfo<number>>(userKey)?.roles ?? [];
|
||||||
setUserKey(username, roles);
|
setUserKey(accessToken, username, roles);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,6 +12,8 @@ import type {
|
|||||||
import { stringify } from "qs";
|
import { stringify } from "qs";
|
||||||
import NProgress from "../progress";
|
import NProgress from "../progress";
|
||||||
import { getToken, formatToken } from "@/utils/auth";
|
import { getToken, formatToken } from "@/utils/auth";
|
||||||
|
import { message } from "@/utils/message";
|
||||||
|
|
||||||
// 相关配置请参考:www.axios-js.com/zh-cn/docs/#axios-request-config-1
|
// 相关配置请参考:www.axios-js.com/zh-cn/docs/#axios-request-config-1
|
||||||
const defaultConfig: AxiosRequestConfig = {
|
const defaultConfig: AxiosRequestConfig = {
|
||||||
// 请求超时时间
|
// 请求超时时间
|
||||||
@ -91,6 +93,7 @@ class PureHttp {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
error => {
|
error => {
|
||||||
|
message("请求异常!", { type: "error" });
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -116,6 +119,7 @@ class PureHttp {
|
|||||||
return response.data;
|
return response.data;
|
||||||
},
|
},
|
||||||
(error: PureHttpError) => {
|
(error: PureHttpError) => {
|
||||||
|
message("服务异常!", { type: "error" });
|
||||||
const $error = error;
|
const $error = error;
|
||||||
$error.isCancelRequest = Axios.isCancel($error);
|
$error.isCancelRequest = Axios.isCancel($error);
|
||||||
// 关闭进度条动画
|
// 关闭进度条动画
|
||||||
|
14
src/utils/rsaEncrypt.ts
Normal file
14
src/utils/rsaEncrypt.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import JSEncrypt from "jsencrypt";
|
||||||
|
// 密钥对生成 http://web.chacuo.net/netrsakeypair
|
||||||
|
const publicKey =
|
||||||
|
"MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANL378k3RiZHWx5AfJqdH9xRNBmD9wGD\n" +
|
||||||
|
"2iRe41HdTNF8RUhNnHit5NpMNtGL0NPTSSpPjjI1kJfVorRvaQerUgkCAwEAAQ==";
|
||||||
|
|
||||||
|
// 加密
|
||||||
|
export const encrypt = (txt: string) => {
|
||||||
|
const crypt = new JSEncrypt();
|
||||||
|
// 设置公钥
|
||||||
|
crypt.setPublicKey(publicKey);
|
||||||
|
const enc = crypt.encrypt(txt);
|
||||||
|
return enc; // 对需要加密的数据进行加密
|
||||||
|
};
|
@ -68,9 +68,14 @@ const onLogin = async (formEl: FormInstance | undefined) => {
|
|||||||
if (valid) {
|
if (valid) {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
useUserStoreHook()
|
useUserStoreHook()
|
||||||
.loginByUsername({ username: ruleForm.username, password: "admin123" })
|
.loginByUsername({
|
||||||
|
username: ruleForm.username,
|
||||||
|
password: ruleForm.password,
|
||||||
|
code: ruleForm.verifyCode,
|
||||||
|
uuid: imgCode.value
|
||||||
|
})
|
||||||
.then(res => {
|
.then(res => {
|
||||||
if (res.success) {
|
if (res) {
|
||||||
// 获取后端路由
|
// 获取后端路由
|
||||||
return initRouter().then(() => {
|
return initRouter().then(() => {
|
||||||
disabled.value = true;
|
disabled.value = true;
|
||||||
@ -85,6 +90,7 @@ const onLogin = async (formEl: FormInstance | undefined) => {
|
|||||||
})
|
})
|
||||||
.finally(() => (loading.value = false));
|
.finally(() => (loading.value = false));
|
||||||
} else {
|
} else {
|
||||||
|
loading.value = false;
|
||||||
return fields;
|
return fields;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -101,9 +107,6 @@ useEventListener(document, "keypress", ({ code }) => {
|
|||||||
immediateDebounce(ruleFormRef.value);
|
immediateDebounce(ruleFormRef.value);
|
||||||
});
|
});
|
||||||
|
|
||||||
watch(imgCode, value => {
|
|
||||||
useUserStoreHook().SET_VERIFYCODE(value);
|
|
||||||
});
|
|
||||||
watch(checked, bool => {
|
watch(checked, bool => {
|
||||||
useUserStoreHook().SET_ISREMEMBERED(bool);
|
useUserStoreHook().SET_ISREMEMBERED(bool);
|
||||||
});
|
});
|
||||||
|
@ -2,14 +2,13 @@ import { reactive } from "vue";
|
|||||||
import { isPhone } from "@pureadmin/utils";
|
import { isPhone } from "@pureadmin/utils";
|
||||||
import type { FormRules } from "element-plus";
|
import type { FormRules } from "element-plus";
|
||||||
import { $t, transformI18n } from "@/plugins/i18n";
|
import { $t, transformI18n } from "@/plugins/i18n";
|
||||||
import { useUserStoreHook } from "@/store/modules/user";
|
|
||||||
|
|
||||||
/** 6位数字验证码正则 */
|
/** 6位数字验证码正则 */
|
||||||
export const REGEXP_SIX = /^\d{6}$/;
|
export const REGEXP_SIX = /^\d{6}$/;
|
||||||
|
|
||||||
/** 密码正则(密码格式应为8-18位数字、字母、符号的任意两种组合) */
|
/** 密码正则(密码格式应为8-18位数字、字母、符号的任意两种组合) */
|
||||||
export const REGEXP_PWD =
|
export const REGEXP_PWD =
|
||||||
/^(?![0-9]+$)(?![a-z]+$)(?![A-Z]+$)(?!([^(0-9a-zA-Z)]|[()])+$)(?!^.*[\u4E00-\u9FA5].*$)([^(0-9a-zA-Z)]|[()]|[a-z]|[A-Z]|[0-9]){8,18}$/;
|
/^[0-9a-zA-Z!@#$%^&*()_+\-=\[\]{};':"\\|,.<>/?]{5,12}$/;
|
||||||
|
|
||||||
/** 登录校验 */
|
/** 登录校验 */
|
||||||
const loginRules = reactive<FormRules>({
|
const loginRules = reactive<FormRules>({
|
||||||
@ -32,8 +31,6 @@ const loginRules = reactive<FormRules>({
|
|||||||
validator: (rule, value, callback) => {
|
validator: (rule, value, callback) => {
|
||||||
if (value === "") {
|
if (value === "") {
|
||||||
callback(new Error(transformI18n($t("login.verifyCodeReg"))));
|
callback(new Error(transformI18n($t("login.verifyCodeReg"))));
|
||||||
} else if (useUserStoreHook().verifyCode !== value) {
|
|
||||||
callback(new Error(transformI18n($t("login.verifyCodeCorrectReg"))));
|
|
||||||
} else {
|
} else {
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
@ -64,8 +61,6 @@ const phoneRules = reactive<FormRules>({
|
|||||||
validator: (rule, value, callback) => {
|
validator: (rule, value, callback) => {
|
||||||
if (value === "") {
|
if (value === "") {
|
||||||
callback(new Error(transformI18n($t("login.verifyCodeReg"))));
|
callback(new Error(transformI18n($t("login.verifyCodeReg"))));
|
||||||
} else if (!REGEXP_SIX.test(value)) {
|
|
||||||
callback(new Error(transformI18n($t("login.verifyCodeSixReg"))));
|
|
||||||
} else {
|
} else {
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user