feat: 修复退出登录登录信息未失效

This commit is contained in:
2025-09-06 20:42:52 +08:00
parent cd99485c9a
commit f0e1a649ee
7 changed files with 52 additions and 14 deletions

View File

@@ -17,11 +17,17 @@ export class AuthController {
@Post('/login') @Post('/login')
async login(ctx: Context) { async login(ctx: Context) {
if (!ctx.session.isNew) { if (ctx.session.user) {
return ctx.session.user; return ctx.session.user;
} }
const { code } = ctx.request.body as LoginRequestBody; const { code } = ctx.request.body as LoginRequestBody;
const { access_token } = await gitea.getToken(code); const { access_token, refresh_token, expires_in } =
await gitea.getToken(code);
const giteaAuth = {
access_token,
refresh_token,
expires_at: Date.now() + expires_in * 1000,
};
const giteaUser = await gitea.getUserInfo(access_token); const giteaUser = await gitea.getUserInfo(access_token);
log.debug(this.TAG, 'gitea user: %o', giteaUser); log.debug(this.TAG, 'gitea user: %o', giteaUser);
const exist = await prisma.user.findFirst({ const exist = await prisma.user.findFirst({
@@ -61,9 +67,15 @@ export class AuthController {
log.debug(this.TAG, '更新用户信息成功 %o', updatedUser); log.debug(this.TAG, '更新用户信息成功 %o', updatedUser);
ctx.session.user = updatedUser; ctx.session.user = updatedUser;
} }
ctx.session.gitea = giteaAuth;
return ctx.session.user; return ctx.session.user;
} }
@Get('logout')
async logout(ctx: Context) {
ctx.session.user = null;
}
@Get('info') @Get('info')
async info(ctx: Context) { async info(ctx: Context) {
return ctx.session?.user; return ctx.session?.user;

View File

@@ -10,11 +10,10 @@ export class Authorization implements Middleware {
apply(app: Koa) { apply(app: Koa) {
app.use(async (ctx: Koa.Context, next: Koa.Next) => { app.use(async (ctx: Koa.Context, next: Koa.Next) => {
console.log('ctx.path', ctx.path)
if (this.ignoreAuth.includes(ctx.path)) { if (this.ignoreAuth.includes(ctx.path)) {
return next(); return next();
} }
if (ctx.session.isNew) { if (ctx.session.user == null) {
ctx.throw(401, 'Unauthorized'); ctx.throw(401, 'Unauthorized');
} }
await next(); await next();

Binary file not shown.

View File

@@ -10,6 +10,7 @@ import { useState } from 'react';
import Logo from '@assets/images/logo.svg?react'; import Logo from '@assets/images/logo.svg?react';
import { Link, Outlet } from 'react-router'; import { Link, Outlet } from 'react-router';
import { useGlobalStore } from '../../stores/global'; import { useGlobalStore } from '../../stores/global';
import { loginService } from '@pages/login/service';
function Home() { function Home() {
const [collapsed, setCollapsed] = useState(false); const [collapsed, setCollapsed] = useState(false);
@@ -56,18 +57,20 @@ function Home() {
<Layout.Header className="h-14 border-b-gray-100 border-b-[1px]"> <Layout.Header className="h-14 border-b-gray-100 border-b-[1px]">
<div className="flex items-center justify-end px-4 h-full"> <div className="flex items-center justify-end px-4 h-full">
<Dropdown <Dropdown
trigger={'click'}
droplist={ droplist={
<Menu className="px-3"> <Menu className="px-3">
<Menu.Item key="1"> <Menu.Item key="1" onClick={loginService.logout}>
<IconExport /> <IconExport />
<span className="ml-2">退</span> <span className="ml-2">退</span>
</Menu.Item> </Menu.Item>
</Menu> </Menu>
} }
> >
<div className="p-2 rounded-xl cursor-pointer flex items-center hover:bg-[rgba(0,0,0,0.03)]"> <div className="p-2 rounded-xl cursor-pointer flex items-center hover:bg-gray-100">
<Avatar size={28}> <Avatar
size={28}
className="border-gray-300 border-[1px] border-solid"
>
<img <img
alt="avatar" alt="avatar"
src={globalStore.user?.avatar_url.replace('https', 'http')} src={globalStore.user?.avatar_url.replace('https', 'http')}

View File

@@ -1,7 +1,8 @@
import { net } from '@shared'; import { net } from '@shared';
import type { AuthURLResponse } from './types'; import type { AuthURLResponse, AuthLoginResponse } from './types';
import type { NavigateFunction } from 'react-router'; import type { NavigateFunction } from 'react-router';
import { Notification } from '@arco-design/web-react'; import { Message, Notification } from '@arco-design/web-react';
import { useGlobalStore } from '../../stores/global';
class LoginService { class LoginService {
async getAuthUrl() { async getAuthUrl() {
@@ -18,7 +19,7 @@ class LoginService {
} }
async login(authCode: string, navigate: NavigateFunction) { async login(authCode: string, navigate: NavigateFunction) {
const { data, code } = await net.request<AuthURLResponse>({ const { data, code } = await net.request<AuthLoginResponse>({
method: 'POST', method: 'POST',
url: '/api/auth/login', url: '/api/auth/login',
data: { data: {
@@ -26,14 +27,25 @@ class LoginService {
}, },
}); });
if (code === 0) { if (code === 0) {
localStorage.setItem('user', JSON.stringify(data)); useGlobalStore.getState().setUser(data);
navigate('/'); navigate('/');
Notification.success({ Notification.success({
title: '提示', title: '提示',
content: '登录成功' content: '登录成功',
}); });
} }
} }
async logout() {
const { code } = await net.request<AuthURLResponse>({
method: 'GET',
url: '/api/auth/logout',
});
if (code === 0) {
Message.success('登出成功');
window.location.href = '/login';
}
}
} }
export const loginService = new LoginService(); export const loginService = new LoginService();

View File

@@ -1,5 +1,15 @@
import type { APIResponse } from '@shared'; import type { APIResponse } from '@shared';
export interface User {
id: string;
username: string;
email: string;
avatar_url: string;
active: boolean;
}
export type AuthURLResponse = APIResponse<{ export type AuthURLResponse = APIResponse<{
url: string; url: string;
}> }>;
export type AuthLoginResponse = APIResponse<User>;

View File

@@ -11,11 +11,13 @@ interface User {
interface GlobalStore { interface GlobalStore {
user: User | null; user: User | null;
setUser: (user: User) => void;
refreshUser: () => Promise<void>; refreshUser: () => Promise<void>;
} }
export const useGlobalStore = create<GlobalStore>((set) => ({ export const useGlobalStore = create<GlobalStore>((set) => ({
user: null, user: null,
setUser: (user: User) => set({ user }),
async refreshUser() { async refreshUser() {
const { data } = await net.request<APIResponse<User>>({ const { data } = await net.request<APIResponse<User>>({
method: 'GET', method: 'GET',