feat: refactor and improve the request client and support refreshToken (#4157)

* feat: refreshToken

* chore: store refreshToken

* chore: generate token using jsonwebtoken

* chore: set refreshToken in httpOnly cookie

* perf: authHeader verify

* chore: add add response interceptor

* chore: test refresh

* chore: handle logout

* chore: type

* chore: update pnpm-lock.yaml

* chore: remove test code

* chore: add todo comment

* chore: update pnpm-lock.yaml

* chore: remove default interceptors

* chore: copy codes

* chore: handle refreshToken invalid

* chore: add refreshToken preference

* chore: typo

* chore: refresh token逻辑调整

* refactor: interceptor presets

* chore: copy codes

* fix: ci errors

* chore: add missing await

* feat: 完善refresh-token逻辑及文档

* fix: ci error

* chore: filename

---------

Co-authored-by: vince <vince292007@gmail.com>
This commit is contained in:
Li Kui
2024-08-19 22:59:42 +08:00
committed by GitHub
parent f8485e8861
commit 01d60336a6
40 changed files with 1055 additions and 523 deletions

View File

@@ -1,15 +1,14 @@
export default eventHandler((event) => {
const token = getHeader(event, 'Authorization');
import { verifyAccessToken } from '~/utils/jwt-utils';
import { unAuthorizedResponse } from '~/utils/response';
if (!token) {
setResponseStatus(event, 401);
return useResponseError('UnauthorizedException', 'Unauthorized Exception');
export default eventHandler((event) => {
const userinfo = verifyAccessToken(event);
if (!userinfo) {
return unAuthorizedResponse(event);
}
const username = Buffer.from(token, 'base64').toString('utf8');
const codes =
MOCK_CODES.find((item) => item.username === username)?.codes ?? [];
MOCK_CODES.find((item) => item.username === userinfo.username)?.codes ?? [];
return useResponseSuccess(codes);
});

View File

@@ -1,20 +1,36 @@
import {
clearRefreshTokenCookie,
setRefreshTokenCookie,
} from '~/utils/cookie-utils';
import { generateAccessToken, generateRefreshToken } from '~/utils/jwt-utils';
import { forbiddenResponse } from '~/utils/response';
export default defineEventHandler(async (event) => {
const { password, username } = await readBody(event);
if (!password || !username) {
setResponseStatus(event, 400);
return useResponseError(
'BadRequestException',
'Username and password are required',
);
}
const findUser = MOCK_USERS.find(
(item) => item.username === username && item.password === password,
);
if (!findUser) {
setResponseStatus(event, 403);
return useResponseError('UnauthorizedException', '用户名或密码错误');
clearRefreshTokenCookie(event);
return forbiddenResponse(event);
}
const accessToken = Buffer.from(username).toString('base64');
const accessToken = generateAccessToken(findUser);
const refreshToken = generateRefreshToken(findUser);
setRefreshTokenCookie(event, refreshToken);
return useResponseSuccess({
...findUser,
accessToken,
// TODO: refresh token
refreshToken: accessToken,
});
});

View File

@@ -0,0 +1,15 @@
import {
clearRefreshTokenCookie,
getRefreshTokenFromCookie,
} from '~/utils/cookie-utils';
export default defineEventHandler(async (event) => {
const refreshToken = getRefreshTokenFromCookie(event);
if (!refreshToken) {
return useResponseSuccess('');
}
clearRefreshTokenCookie(event);
return useResponseSuccess('');
});

View File

@@ -0,0 +1,33 @@
import {
clearRefreshTokenCookie,
getRefreshTokenFromCookie,
setRefreshTokenCookie,
} from '~/utils/cookie-utils';
import { verifyRefreshToken } from '~/utils/jwt-utils';
import { forbiddenResponse } from '~/utils/response';
export default defineEventHandler(async (event) => {
const refreshToken = getRefreshTokenFromCookie(event);
if (!refreshToken) {
return forbiddenResponse(event);
}
clearRefreshTokenCookie(event);
const userinfo = verifyRefreshToken(refreshToken);
if (!userinfo) {
return forbiddenResponse(event);
}
const findUser = MOCK_USERS.find(
(item) => item.username === userinfo.username,
);
if (!findUser) {
return forbiddenResponse(event);
}
const accessToken = generateAccessToken(findUser);
setRefreshTokenCookie(event, refreshToken);
return accessToken;
});

View File

@@ -1,14 +1,13 @@
export default eventHandler((event) => {
const token = getHeader(event, 'Authorization');
import { verifyAccessToken } from '~/utils/jwt-utils';
import { unAuthorizedResponse } from '~/utils/response';
if (!token) {
setResponseStatus(event, 401);
return useResponseError('UnauthorizedException', 'Unauthorized Exception');
export default eventHandler((event) => {
const userinfo = verifyAccessToken(event);
if (!userinfo) {
return unAuthorizedResponse(event);
}
const username = Buffer.from(token, 'base64').toString('utf8');
const menus =
MOCK_MENUS.find((item) => item.username === username)?.menus ?? [];
MOCK_MENUS.find((item) => item.username === userinfo.username)?.menus ?? [];
return useResponseSuccess(menus);
});

View File

@@ -1,14 +1,11 @@
import { verifyAccessToken } from '~/utils/jwt-utils';
import { unAuthorizedResponse } from '~/utils/response';
export default eventHandler((event) => {
const token = getHeader(event, 'Authorization');
if (!token) {
setResponseStatus(event, 401);
return useResponseError('UnauthorizedException', 'Unauthorized Exception');
const userinfo = verifyAccessToken(event);
if (!userinfo) {
return unAuthorizedResponse(event);
}
const username = Buffer.from(token, 'base64').toString('utf8');
const user = MOCK_USERS.find((item) => item.username === username);
const { password: _pwd, ...userInfo } = user;
return useResponseSuccess(userInfo);
return useResponseSuccess(userinfo);
});