add automatic login

This commit is contained in:
landaiqing
2024-08-14 20:04:57 +08:00
parent 48d2f61223
commit cab3b1ee96
18 changed files with 136 additions and 63 deletions

1
components.d.ts vendored
View File

@@ -29,6 +29,7 @@ declare module 'vue' {
BoxDog: typeof import('./src/components/BoxDog/BoxDog.vue')['default']
DynamicTitle: typeof import('./src/components/DynamicTitle/DynamicTitle.vue')['default']
ForgetPage: typeof import('./src/views/Forget/ForgetPage.vue')['default']
LandingPage: typeof import('./src/views/Landing/LandingPage.vue')['default']
LockOutlined: typeof import('@ant-design/icons-vue')['LockOutlined']
LoginFooter: typeof import('./src/views/Login/LoginFooter.vue')['default']
LoginPage: typeof import('./src/views/Login/LoginPage.vue')['default']

View File

@@ -5,11 +5,17 @@ import {PhoneLogin} from "@/types/user";
* 获取用户信息
*/
export const getUserInfo = () => {
return service.Get('/api/auth/user/List', {
return service.Get('/api/auth/user/list', {
meta: {
ignoreToken: false
},
cacheFor: 1000 * 60
cacheFor: {
// 设置缓存模式为持久化模式
mode: 'restore',
// 缓存时间
expire: 1000 * 10,
tag: 'v1'
}
});
};
@@ -18,10 +24,9 @@ export const getUserInfo = () => {
* @param refreshToken
*/
export const refreshToken = (refreshToken: string) => {
return service.Get('/api/auth/token/refresh', {
params: {
refresh_token: refreshToken
},
return service.Post('/api/token/refresh', {
refresh_token: refreshToken
}, {
meta: {
authRole: 'refreshToken',
ignoreToken: false

View File

@@ -38,6 +38,7 @@ export default {
sendCaptchaError: "captcha sending failed, please try again later",
loginSuccess: "login success",
loginError: "login failed!",
},
error: {
networkError: 'Network error, please try again later',
@@ -55,5 +56,8 @@ export default {
other: 'connect error',
authTokenError: "auth token error, please try again later",
authTokenExpired: "auth token expired, please login again",
loginExpired: "login expired, please try again",
pleaseLogin: "please login first",
}
};

View File

@@ -57,6 +57,7 @@ export default {
other: '连接出错',
authTokenError: "认证失败,请重新登录!",
authTokenExpired: "认证过期,请重新登录!",
loginExpired: "登录已过期!,请重新登录!",
pleaseLogin: "请先登录!",
}
};

View File

@@ -0,0 +1,11 @@
export default [
{
path: '/',
name: 'index',
component: () => import('@/views/Landing/LandingPage.vue'),
meta: {
requiresAuth: false,
title: '首页'
}
}
];

View File

@@ -7,5 +7,23 @@ export default [
requiresAuth: false,
title: '登录页'
}
},
{
path: '/qrlogin',
name: 'qrlogin',
component: () => import('@/views/QRLogin/QRLogin.vue'),
meta: {
requiresAuth: false,
title: '扫码登录'
}
},
{
path: '/resetpass',
name: 'resetpass',
component: () => import('@/views/Forget/ForgetPage.vue'),
meta: {
requiresAuth: false,
title: '重置密码'
}
}
];

View File

@@ -1,11 +0,0 @@
export default [
{
path: '/qrlogin',
name: 'qrlogin',
component: () => import('@/views/QRLogin/QRLogin.vue'),
meta: {
requiresAuth: false,
title: '扫码登录'
}
}
];

View File

@@ -1,11 +0,0 @@
export default [
{
path: '/resetpass',
name: 'resetpass',
component: () => import('@/views/Forget/ForgetPage.vue'),
meta: {
requiresAuth: false,
title: '重置密码'
}
}
];

View File

@@ -4,7 +4,7 @@ export default [
name: 'test',
component: () => import('@/views/TestTheme.vue'),
meta: {
requiresAuth: false,
requiresAuth: true,
title: '测试'
}
}

View File

@@ -4,7 +4,7 @@ export default [
name: 'test2',
component: () => import('@/views/TestI18n.vue'),
meta: {
requiresAuth: false,
requiresAuth: true,
title: '测试'
}
}

View File

@@ -6,17 +6,15 @@ import test from "@/router/modules/test.ts";
import test2 from "@/router/modules/testI18n.ts";
import useStore from "@/store";
import {message} from "ant-design-vue";
import {close, start} from '@/utils/nprogress/nprogress.ts';
import qrlogin from "@/router/modules/qrlogin.ts";
import resetpass from "@/router/modules/resetpass.ts";
import {close, start} from '@/components/Nprogress/nprogress.ts';
import notFound from "@/router/modules/notFound.ts";
import landing from "@/router/modules/landing.ts";
const routes: Array<RouteRecordRaw> = [
...login,
...qrlogin,
...resetpass,
...notFound,
...landing,
...test,
...test2,
{
@@ -35,14 +33,14 @@ router.beforeEach((to, from, next) => {
start();
if (to.meta.requiresAuth) {
const user = useStore().user;
const token: string | undefined = user.getUser()?.token;
const userId: string | undefined = user.getUser()?.userId;
if (token !== undefined && userId !== undefined) {
const token: string | undefined = user.user.refreshToken;
const userId: string | undefined = user.user.userId;
if (token !== "" && userId !== "") {
next();
} else {
message.warn('请先登录').then();
next({
path: '/',
path: '/login',
query: {redirect: to.fullPath}
});
}

View File

@@ -1,10 +1,20 @@
import {useAuthStore} from '@/store/modules/userStore.ts';
import {useThemeStore} from "@/store/modules/themeStore.ts";
import {langStore} from "@/store/modules/langStore.ts";
import {useAuthSessionStore} from "@/store/modules/userSessionStore.ts";
export default function useStore() {
// 是否自动登录 默认自动化登录
function isAutoLogin() {
const result: string | null = localStorage.getItem('auto_login');
if (result) {
return result === 'true';
}
return true;
}
return {
user: useAuthStore(),
user: isAutoLogin() ? useAuthStore() : useAuthSessionStore(), // 自动登录时使用 useAuthStore否则使用 useAuthSessionStore
theme: useThemeStore(),
lang: langStore()
};

View File

@@ -0,0 +1,27 @@
import {defineStore} from 'pinia';
import {reactive} from 'vue';
export const useAuthSessionStore = defineStore(
'user',
() => {
const user: any = reactive({
accessToken: '',
userId: '',
refreshToken: '',
expiresAt: 0,
});
return {
user,
};
},
{
// 开启数据持久化
persist: {
key: 'user',
storage: sessionStorage,
paths: ['user'],
}
}
);

1
src/types/user.d.ts vendored
View File

@@ -1,4 +1,3 @@
export interface AccountLogin {
account?: string
password?: string;

View File

@@ -22,25 +22,18 @@ const {onAuthRequired, onResponseRefreshToken} = createServerTokenAuthentication
// 当token过期时触发在此函数中触发刷新token
handler: async () => {
try {
const user = useStore().user;
const res: any = await refreshToken(user.user?.refreshToken || '');
if (res.code === 0 && res.data) {
const {uid, access_token, refresh_token, expires_at} = res.data;
user.user.userId = uid;
user.user.accessToken = access_token;
user.user.refreshToken = refresh_token;
user.user.expiresAt = expires_at;
}
// else {
// message.error(res.message);
// await router.push('/login');
// }
} catch (error) {
// token刷新失败跳转回登录页
message.error(i18n.global.t('error.authTokenError')).then();
// 刷新token
const user = useStore().user;
const res: any = await refreshToken(user.user?.refreshToken || '');
if (res.code === 0 && res.data) {
const {access_token, refresh_token, uid} = res.data;
user.user.accessToken = access_token;
user.user.refreshToken = refresh_token;
user.user.uid = uid;
} else {
message.error(i18n.global.t('error.loginExpired'));
localStorage.removeItem('user');
await router.push('/login');
throw error;
}
}
}

View File

@@ -0,0 +1,17 @@
<script lang="ts">
import {defineComponent} from 'vue';
export default defineComponent({
name: "LandingPage"
});
</script>
<template>
<div>
<h1>Welcome to our website!</h1>
</div>
</template>
<style scoped>
</style>

View File

@@ -54,7 +54,10 @@
</AFormItem>
<AFormItem>
<AFlex :vertical="false" justify="space-between">
<ACheckbox>{{ t("login.autoLogin") }}</ACheckbox>
<ACheckbox @change="(e: any)=>{
autoLoginChang(e.target.checked);
}" v-model:checked="autoLoginChecked">{{ t("login.autoLogin") }}
</ACheckbox>
</AFlex>
</AFormItem>
@@ -100,7 +103,10 @@
</AFormItem>
<AFormItem>
<AFlex :vertical="false" justify="space-between">
<ACheckbox>{{ t("login.autoLogin") }}</ACheckbox>
<ACheckbox v-model:checked="autoLoginChecked" @change="(e: any)=>{
autoLoginChang(e.target.checked);
}">{{ t("login.autoLogin") }}
</ACheckbox>
<a @click="()=>{
router.push('/resetpass')
}">{{ t("login.forgotPassword") }}</a>
@@ -162,6 +168,7 @@ const phoneLoginFormRef = ref<any>();
const showRotateCaptcha = ref<boolean>(false);
const captchaData = reactive({angle: 0, image: "", thumb: "", key: ""});
const captchaErrorCount = ref<number>(0);
const autoLoginChecked = ref<boolean>(localStorage.getItem('auto_login') === 'true');
const rotateEvent = {
confirm: (angle: number) => {
checkCaptcha(angle);
@@ -209,7 +216,7 @@ const rules: Record<string, Rule[]> = {
captcha: [
{
required: true, message: t('login.captchaValidate'), trigger: 'change'
}
},
]
};
@@ -379,6 +386,10 @@ async function sendMessageByPhone(): Promise<boolean> {
return false;
}
}
async function autoLoginChang(checkedValue: boolean) {
return localStorage.setItem('auto_login', String(checkedValue));
}
</script>
<style src="./index.scss" scoped>
@import "@/assets/styles/global.scss";