feat: request token

This commit is contained in:
KUN1007 2023-09-26 23:54:17 +08:00
parent 4c9efffd6d
commit d4bfc53bbf
8 changed files with 91 additions and 71 deletions

View file

@ -4,7 +4,7 @@ import type * as Login from './types/login'
const loginURLs = { const loginURLs = {
login: `/login/login`, login: `/login/login`,
register: `/login/register`, register: `/login/register`,
verificationCode: `/auth/email/send`, verificationCode: `/auth/email/code`,
} }
// 获取用户登录数据 // 获取用户登录数据

View file

@ -25,5 +25,4 @@ export type LoginResponseData = KUNGalgameResponseData<{
name: string name: string
avatar: string avatar: string
token: string token: string
refreshToken: string
}> }>

View file

@ -0,0 +1,26 @@
// 全局消息组件(顶部)
import message from '@/components/alert/Message'
// 导入路由
import router from '@/router'
export function onRequestError(response: Response) {
if (response.status === 401) {
message(
'Login expired, please log in again.',
'登陆过期,请重新登陆',
'error'
)
}
if (response.status === 404) {
message(
'Not Found, request address is incorrect.',
'资源未找到,请求地址出错',
'error'
)
}
if (response.status === 500) {
message('Internal Server Error', '服务器遇到了未处理的错误', 'error')
}
}

View file

@ -1,17 +1,17 @@
import { Router } from 'vue-router' // 导入 rooter
import { type RouteRecordRaw } from 'vue-router' import { Router, RouteRecordRaw } from 'vue-router'
import { useKUNGalgameUserStore } from '@/store/modules/kungalgamer' // 导入公共路由,无需鉴权
import { WHITE_LIST } from '../router' import { WHITE_LIST } from '../router'
import { storeToRefs } from 'pinia' // 导入获取 token 的函数
import { unref } from 'vue' import { getToken } from '@/utils/cookie'
// 临时使用 // 临时使用
import { asyncRoutes } from '../router' import { asyncRoutes } from '../router'
export const createPermission = (router: Router) => { export const createPermission = (router: Router) => {
router.beforeEach(async (to, from, next) => { router.beforeEach(async (to, from, next) => {
const useStore = useKUNGalgameUserStore() // 获取当前 tokenaccess tokenrefresh 在 服务器端 http only
const { token } = storeToRefs(useStore) const token = getToken()
const getRoute = asyncRoutes const getRoute = asyncRoutes
// 白名单 // 白名单
@ -21,7 +21,7 @@ export const createPermission = (router: Router) => {
} }
// 没有token // 没有token
if (!unref(token)) { if (!token) {
if (!to.meta?.permission && getRoute.length > 0) { if (!to.meta?.permission && getRoute.length > 0) {
next() next()
return return

View file

@ -22,7 +22,6 @@ interface UserState {
name: string name: string
avatar: string avatar: string
token: string token: string
refreshToken: string
} }
// 这里用了 pinia-plugin-persistedstate直接存储 token 即可 // 这里用了 pinia-plugin-persistedstate直接存储 token 即可
@ -35,7 +34,6 @@ export const useKUNGalgameUserStore = defineStore({
name: '', name: '',
avatar: '', avatar: '',
token: '', token: '',
refreshToken: '',
}), }),
getters: {}, getters: {},
actions: { actions: {
@ -45,11 +43,6 @@ export const useKUNGalgameUserStore = defineStore({
this.name = name this.name = name
this.avatar = avatar this.avatar = avatar
}, },
// 设置用户 token
setToken(token: string, refreshToken: string): void {
this.token = token
setToken(refreshToken)
},
// 登陆 // 登陆
login(request: LoginRequestData): Promise<LoginResponseData> { login(request: LoginRequestData): Promise<LoginResponseData> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@ -58,7 +51,7 @@ export const useKUNGalgameUserStore = defineStore({
.then((res) => { .then((res) => {
if (res.data) { if (res.data) {
this.setUserInfo(res.data.uid, res.data.name, res.data.avatar) this.setUserInfo(res.data.uid, res.data.name, res.data.avatar)
this.setToken(res.data.token, res.data.refreshToken) setToken(res.data.token)
} else } else
(error: Error) => { (error: Error) => {
throw new Error('500 Server ERROR', error) throw new Error('500 Server ERROR', error)
@ -90,7 +83,7 @@ export const useKUNGalgameUserStore = defineStore({
.then((res) => { .then((res) => {
if (res.data) { if (res.data) {
this.setUserInfo(res.data.uid, res.data.name, res.data.avatar) this.setUserInfo(res.data.uid, res.data.name, res.data.avatar)
this.setToken(res.data.token, res.data.refreshToken) setToken(res.data.token)
} else } else
(error: Error) => { (error: Error) => {
throw new Error('500 Server ERROR', error) throw new Error('500 Server ERROR', error)

View file

@ -61,8 +61,8 @@ html {
--shadow: 0 1px 2px hsla(0, 0%, 0%, 0.05), 0 1px 4px hsla(0, 0%, 0%, 0.05), --shadow: 0 1px 2px hsla(0, 0%, 0%, 0.05), 0 1px 4px hsla(0, 0%, 0%, 0.05),
0 2px 8px hsla(0, 0%, 0%, 0.05); 0 2px 8px hsla(0, 0%, 0%, 0.05);
--kungalgame-shadow-0: 5px 5px 7px var(--kungalgame-blue-1), --kungalgame-shadow-0: 5px 5px 10px var(--kungalgame-trans-blue-1),
-5px -5px 10px var(--kungalgame-blue-1); -5px -5px 10px var(--kungalgame-trans-blue-1);
--kungalgame-shadow-1: 2px 2px 4px var(--kungalgame-blue-1), --kungalgame-shadow-1: 2px 2px 4px var(--kungalgame-blue-1),
-2px -2px 4px var(--kungalgame-blue-1); -2px -2px 4px var(--kungalgame-blue-1);
--kungalgame-shadow-2: inset 1px 1px 2px var(--kungalgame-blue-1), --kungalgame-shadow-2: inset 1px 1px 2px var(--kungalgame-blue-1),

View file

@ -1,5 +1,7 @@
// 操作 cookie 的函数 // 操作 cookie 的函数
import { getToken } from '@/utils/cookie' import { getToken } from '@/utils/cookie'
// 错误处理函数
import { onRequestError } from '@/error/onRequestError'
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE'
@ -13,22 +15,22 @@ const fetchRequest = async <T>(
url: string, url: string,
options: FetchOptions options: FetchOptions
): Promise<T> => { ): Promise<T> => {
try {
const baseUrl = import.meta.env.VITE_API_BASE_URL const baseUrl = import.meta.env.VITE_API_BASE_URL
const fullUrl = `${baseUrl}${url}` const fullUrl = `${baseUrl}${url}`
const response = await fetch(fullUrl, options) // 在请求头中添加 token
const headers = {
if (!response.ok) { ...options.headers,
throw new Error('Request Error!') Authorization: `Bearer ${getToken()}`,
} }
const response = await fetch(fullUrl, { ...options, headers })
// 处理错误
onRequestError(response)
const data: T = await response.json() const data: T = await response.json()
return data return data
} catch (error) {
console.error('Fetch Error:', error)
throw new Error('Request Error!')
}
} }
const fetchGet = async <T>( const fetchGet = async <T>(

View file

@ -15,42 +15,42 @@ export default defineConfig({
'@': path.resolve(__dirname, './src'), '@': path.resolve(__dirname, './src'),
}, },
}, },
server: { // server: {
/** 是否开启 HTTPS */ // /** 是否开启 HTTPS */
https: false, // https: false,
/** 设置 host: true 才可以使用 Network 的形式,以 IP 访问项目 */ // /** 设置 host: true 才可以使用 Network 的形式,以 IP 访问项目 */
host: true, // host: "0.0.0.0" // host: '127.0.0.1', // host: "0.0.0.0"
/** 端口号 */ // /** 端口号 */
port: 1007, // port: 1007,
/** 是否自动打开浏览器 */ // /** 是否自动打开浏览器 */
open: false, // open: false,
/** 跨域设置允许 */ // /** 跨域设置允许 */
cors: true, // cors: true,
/** 端口被占用时,是否直接退出 */ // /** 端口被占用时,是否直接退出 */
strictPort: true, // strictPort: true,
/** 接口代理 */ // /** 接口代理 */
proxy: {}, // proxy: {},
}, // },
build: { // build: {
/** 打包大小超过 500kb 警告 */ // /** 打包大小超过 500kb 警告 */
chunkSizeWarningLimit: 500, // chunkSizeWarningLimit: 500,
/** Vite 2.6.x 以上需要配置 minify: "terser", terserOptions 才能生效 */ // /** Vite 2.6.x 以上需要配置 minify: "terser", terserOptions 才能生效 */
minify: 'terser', // minify: 'terser',
/** 在打包代码时移除 console.log、debugger 和 注释 */ // /** 在打包代码时移除 console.log、debugger 和 注释 */
terserOptions: { // terserOptions: {
compress: { // compress: {
drop_console: false, // drop_console: false,
drop_debugger: true, // drop_debugger: true,
pure_funcs: ['console.log'], // pure_funcs: ['console.log'],
}, // },
format: { // format: {
/** 删除注释 */ // /** 删除注释 */
comments: false, // comments: false,
}, // },
}, // },
/** 打包后静态资源目录 */ // /** 打包后静态资源目录 */
assetsDir: 'kun', // assetsDir: 'kun',
}, // },
// 消除 i18n 警告 // 消除 i18n 警告
define: { define: {
__VUE_I18N_FULL_INSTALL__: true, __VUE_I18N_FULL_INSTALL__: true,