09101122
This commit is contained in:
parent
5630af88ba
commit
6e95554e0c
|
@ -10,9 +10,14 @@ import { AuthModule } from './auth/auth.module';
|
||||||
import { ScheduleModule } from '@nestjs/schedule';
|
import { ScheduleModule } from '@nestjs/schedule';
|
||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
import { TasksModule } from './tasks/tasks.module';
|
import { TasksModule } from './tasks/tasks.module';
|
||||||
|
import { JwtModule } from '@nestjs/jwt';
|
||||||
|
import { env } from './env';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [ScheduleModule.forRoot(), TrpcModule, RedisModule, QueueModule, TransformModule, AuthModule, TasksModule],
|
imports: [ScheduleModule.forRoot(), JwtModule.register({
|
||||||
|
global: true,
|
||||||
|
secret: env.JWT_SECRET
|
||||||
|
}), TrpcModule, RedisModule, QueueModule, TransformModule, AuthModule, TasksModule],
|
||||||
providers: [RedisService, SocketGateway, ConfigService],
|
providers: [RedisService, SocketGateway, ConfigService],
|
||||||
})
|
})
|
||||||
export class AppModule { }
|
export class AppModule { }
|
||||||
|
|
|
@ -12,8 +12,6 @@ export class AuthController {
|
||||||
@Get("user-profile")
|
@Get("user-profile")
|
||||||
async getUserProfile(@Req() request: Request) {
|
async getUserProfile(@Req() request: Request) {
|
||||||
const user: JwtPayload = (request as any).user
|
const user: JwtPayload = (request as any).user
|
||||||
console.log(user)
|
|
||||||
// console.log(request)
|
|
||||||
return this.authService.getUserProfile(user)
|
return this.authService.getUserProfile(user)
|
||||||
}
|
}
|
||||||
@Post('login')
|
@Post('login')
|
||||||
|
|
|
@ -15,7 +15,7 @@ export class AuthGuard implements CanActivate {
|
||||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||||
const request = context.switchToHttp().getRequest();
|
const request = context.switchToHttp().getRequest();
|
||||||
const token = this.extractTokenFromHeader(request);
|
const token = this.extractTokenFromHeader(request);
|
||||||
console.log(token)
|
|
||||||
if (!token) {
|
if (!token) {
|
||||||
throw new UnauthorizedException();
|
throw new UnauthorizedException();
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ export class AuthGuard implements CanActivate {
|
||||||
secret: env.JWT_SECRET
|
secret: env.JWT_SECRET
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// 💡 We're assigning the payload to the request object here
|
// 💡 We're assigning the payload to the request object here
|
||||||
// so that we can access it in our route handlers
|
// so that we can access it in our route handlers
|
||||||
request['user'] = payload;
|
request['user'] = payload;
|
||||||
|
@ -36,7 +36,7 @@ export class AuthGuard implements CanActivate {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private extractTokenFromHeader(request: Request): string | undefined {
|
extractTokenFromHeader(request: Request): string | undefined {
|
||||||
const [type, token] = request.headers.authorization?.split(' ') ?? [];
|
const [type, token] = request.headers.authorization?.split(' ') ?? [];
|
||||||
return type === 'Bearer' ? token : undefined;
|
return type === 'Bearer' ? token : undefined;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,11 +9,6 @@ import { DepartmentService } from '@server/models/department/department.service'
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
providers: [AuthService, StaffService, RoleMapService, DepartmentService],
|
providers: [AuthService, StaffService, RoleMapService, DepartmentService],
|
||||||
imports: [JwtModule.register({
|
|
||||||
global: true,
|
|
||||||
secret: env.JWT_SECRET,
|
|
||||||
signOptions: { expiresIn: '60s' },
|
|
||||||
}),],
|
|
||||||
controllers: [AuthController],
|
controllers: [AuthController],
|
||||||
exports: [AuthService]
|
exports: [AuthService]
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
import { Test, TestingModule } from '@nestjs/testing';
|
|
||||||
import { TrpcService } from './trpc.service';
|
|
||||||
|
|
||||||
describe('TrpcService', () => {
|
|
||||||
let service: TrpcService;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
const module: TestingModule = await Test.createTestingModule({
|
|
||||||
providers: [TrpcService],
|
|
||||||
}).compile();
|
|
||||||
|
|
||||||
service = module.get<TrpcService>(TrpcService);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be defined', () => {
|
|
||||||
expect(service).toBeDefined();
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable, Logger } from '@nestjs/common';
|
||||||
import { initTRPC, TRPCError } from '@trpc/server';
|
import { initTRPC, TRPCError } from '@trpc/server';
|
||||||
import superjson from 'superjson-cjs';
|
import superjson from 'superjson-cjs';
|
||||||
import * as trpcExpress from '@trpc/server/adapters/express';
|
import * as trpcExpress from '@trpc/server/adapters/express';
|
||||||
|
@ -9,7 +9,7 @@ import { JwtService } from '@nestjs/jwt';
|
||||||
type Context = Awaited<ReturnType<TrpcService['createContext']>>;
|
type Context = Awaited<ReturnType<TrpcService['createContext']>>;
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class TrpcService {
|
export class TrpcService {
|
||||||
constructor(private readonly jwtService: JwtService) { }
|
|
||||||
async createContext({
|
async createContext({
|
||||||
req,
|
req,
|
||||||
res,
|
res,
|
||||||
|
@ -17,10 +17,11 @@ export class TrpcService {
|
||||||
const token = req.headers.authorization?.split(' ')[1];
|
const token = req.headers.authorization?.split(' ')[1];
|
||||||
let tokenData: JwtPayload | undefined = undefined;
|
let tokenData: JwtPayload | undefined = undefined;
|
||||||
let staff: Staff | undefined = undefined;
|
let staff: Staff | undefined = undefined;
|
||||||
|
console.log(token)
|
||||||
if (token) {
|
if (token) {
|
||||||
try {
|
try {
|
||||||
// Verify JWT token and extract tokenData
|
const jwtService = new JwtService()
|
||||||
tokenData = await this.jwtService.verifyAsync(token, { secret: env.JWT_SECRET }) as JwtPayload;
|
tokenData = await jwtService.verifyAsync(token, { secret: env.JWT_SECRET }) as JwtPayload;
|
||||||
if (tokenData) {
|
if (tokenData) {
|
||||||
// Fetch staff details from the database using tokenData.id
|
// Fetch staff details from the database using tokenData.id
|
||||||
staff = await db.staff.findUnique({ where: { id: tokenData.sub } });
|
staff = await db.staff.findUnique({ where: { id: tokenData.sub } });
|
||||||
|
@ -35,7 +36,7 @@ export class TrpcService {
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
staff,
|
staff
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
trpc = initTRPC.context<Context>().create({
|
trpc = initTRPC.context<Context>().create({
|
||||||
|
|
|
@ -6,13 +6,16 @@ import QueryProvider from './providers/query-provider'
|
||||||
import { router } from './routes';
|
import { router } from './routes';
|
||||||
import { AuthProvider } from './providers/auth-provider';
|
import { AuthProvider } from './providers/auth-provider';
|
||||||
import ThemeProvider from './providers/theme-provider';
|
import ThemeProvider from './providers/theme-provider';
|
||||||
|
import { App as AntdApp } from 'antd';
|
||||||
function App() {
|
function App() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AuthProvider>
|
<AuthProvider>
|
||||||
<QueryProvider>
|
<QueryProvider>
|
||||||
<ThemeProvider>
|
<ThemeProvider>
|
||||||
<RouterProvider router={router}></RouterProvider>
|
<AntdApp>
|
||||||
|
<RouterProvider router={router}></RouterProvider>
|
||||||
|
</AntdApp>
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
</QueryProvider>
|
</QueryProvider>
|
||||||
</AuthProvider>
|
</AuthProvider>
|
||||||
|
|
|
@ -8,29 +8,28 @@ import SineWave from '../components/presentation/animation/sine-wave';
|
||||||
const LoginPage: React.FC = () => {
|
const LoginPage: React.FC = () => {
|
||||||
const [showLogin, setShowLogin] = useState(true);
|
const [showLogin, setShowLogin] = useState(true);
|
||||||
const [registerLoading, setRegisterLoading] = useState(false);
|
const [registerLoading, setRegisterLoading] = useState(false);
|
||||||
const { login, isAuthenticated } = useAuth();
|
const { login, isAuthenticated, signup } = useAuth();
|
||||||
const loginFormRef = useRef<any>(null);
|
const loginFormRef = useRef<any>(null);
|
||||||
const registerFormRef = useRef<any>(null);
|
const registerFormRef = useRef<any>(null);
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const onFinishLogin = async (values: any) => {
|
const onFinishLogin = async (values: any) => {
|
||||||
try {
|
try {
|
||||||
const { username, password } = values;
|
const { username, password } = values;
|
||||||
await login(username, password);
|
await login(username, password);
|
||||||
message.success('登录成功!');
|
message.success('登录成功!');
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
message.warning('用户名或密码错误!');
|
message.error('用户名或密码错误!');
|
||||||
console.error(err);
|
console.error(err);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const onFinishRegister = async (values: any) => {
|
const onFinishRegister = async (values: any) => {
|
||||||
setRegisterLoading(true);
|
setRegisterLoading(true);
|
||||||
|
const { username, password, phoneNumber } = values;
|
||||||
try {
|
try {
|
||||||
// await wp.RegisterUser().create({
|
await signup(username, password, phoneNumber);
|
||||||
// ...values,
|
|
||||||
// custom_data: { org_unit: values.org_unit },
|
|
||||||
// });
|
|
||||||
message.success('注册成功!');
|
message.success('注册成功!');
|
||||||
setShowLogin(true);
|
setShowLogin(true);
|
||||||
loginFormRef.current.submit();
|
loginFormRef.current.submit();
|
||||||
|
@ -51,13 +50,10 @@ const LoginPage: React.FC = () => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex justify-center items-center h-screen w-full bg-layout">
|
<div className="flex justify-center items-center h-screen w-full bg-layout">
|
||||||
<div className="flex items-center transition-all overflow-hidden bg-container rounded-xl" style={{ width: 800, height: 600, padding: 0 }}>
|
<div className="flex items-center transition-all overflow-hidden bg-container rounded-xl " style={{ width: 800, height: 600 }}>
|
||||||
<div className="flex-1 py-10 px-10">
|
<div className="flex-1 py-10 px-10">
|
||||||
{showLogin ? (
|
{showLogin ? (
|
||||||
<>
|
<>
|
||||||
<Link to="/" className="text-gray-400 text-sm hover:text-primary hover:cursor-pointer">
|
|
||||||
返回首页
|
|
||||||
</Link>
|
|
||||||
<div className="text-center text-2xl text-primary select-none">
|
<div className="text-center text-2xl text-primary select-none">
|
||||||
<span className="px-2">登录</span>
|
<span className="px-2">登录</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -77,33 +73,28 @@ const LoginPage: React.FC = () => {
|
||||||
</Form>
|
</Form>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<div >
|
||||||
<div
|
|
||||||
onClick={() => setShowLogin(true)}
|
|
||||||
className="text-sm text-gray-400 hover:cursor-pointer hover:text-primary"
|
|
||||||
>
|
|
||||||
返回登录
|
|
||||||
</div>
|
|
||||||
<div className="text-center text-2xl text-primary">注册</div>
|
<div className="text-center text-2xl text-primary">注册</div>
|
||||||
<Form requiredMark="optional" ref={registerFormRef} onFinish={onFinishRegister} layout="vertical" size="large">
|
<Form requiredMark="optional" ref={registerFormRef} onFinish={onFinishRegister} layout="vertical" size="large">
|
||||||
<Form.Item name="username" label="用户名" rules={[
|
<Form.Item name="username" label="用户名" rules={[
|
||||||
{ required: true, message: '请输入用户名' },
|
{ required: true, message: '请输入用户名' },
|
||||||
{ min: 3, max: 15, message: '用户名长度在 3 到 15 个字符' }
|
{ min: 3, max: 15, message: '用户名长度在 3 到 15 个字符' }
|
||||||
]}>
|
]}>
|
||||||
<Input placeholder="输入用户名" />
|
<Input />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
<Form.Item name="phoneNumber" label="手机号" rules={[
|
||||||
<Form.Item name="deptId" label="单位" rules={[{ required: true, message: '请选择单位' }]}>
|
{ required: false },
|
||||||
<DepartmentSelect />
|
{ pattern: /^1[3-9]\d{9}$/, message: '请输入有效的手机号' }
|
||||||
|
]}>
|
||||||
|
<Input />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item name="password" label="密码" rules={[
|
<Form.Item name="password" label="密码" rules={[
|
||||||
{ required: true, message: '请输入密码' },
|
{ required: true, message: '请输入密码' },
|
||||||
{ min: 6, message: '密码长度不能小于 6 位' }
|
{ min: 6, message: '密码长度不能小于 6 位' }
|
||||||
]}>
|
]}>
|
||||||
<Input.Password placeholder="输入密码" />
|
<Input.Password />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item name="repeatPass" label="确认密码" dependencies={['password']} hasFeedback rules={[
|
<Form.Item name="repeatPass" label="确认密码" dependencies={['password']} hasFeedback rules={[
|
||||||
{ required: true, message: '请再次输入密码' },
|
{ required: true, message: '请再次输入密码' },
|
||||||
({ getFieldValue }) => ({
|
({ getFieldValue }) => ({
|
||||||
|
@ -115,7 +106,7 @@ const LoginPage: React.FC = () => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
]}>
|
]}>
|
||||||
<Input.Password placeholder="确认密码" />
|
<Input.Password />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<div className="flex items-center justify-center">
|
<div className="flex items-center justify-center">
|
||||||
|
@ -124,7 +115,7 @@ const LoginPage: React.FC = () => {
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</Form>
|
</Form>
|
||||||
</>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className={`transition-all h-full flex-1 text-white p-10 flex items-center justify-center bg-primary`}>
|
<div className={`transition-all h-full flex-1 text-white p-10 flex items-center justify-center bg-primary`}>
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
import { useAuth } from "@web/src/providers/auth-provider"
|
||||||
|
|
||||||
export default function MainPage() {
|
export default function MainPage() {
|
||||||
return <>hello,world</>
|
const { user } = useAuth()
|
||||||
|
return <>hello,{user?.username}</>
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ interface AuthContextProps {
|
||||||
user: UserProfile | null;
|
user: UserProfile | null;
|
||||||
login: (username: string, password: string) => Promise<void>;
|
login: (username: string, password: string) => Promise<void>;
|
||||||
logout: () => Promise<void>;
|
logout: () => Promise<void>;
|
||||||
|
signup: (username: string, password: string, phoneNumber?: string) => Promise<void>;
|
||||||
refreshAccessToken: () => Promise<void>;
|
refreshAccessToken: () => Promise<void>;
|
||||||
initializeAuth: () => void;
|
initializeAuth: () => void;
|
||||||
startTokenRefreshInterval: () => void;
|
startTokenRefreshInterval: () => void;
|
||||||
|
@ -102,6 +103,28 @@ export function AuthProvider({ children }: AuthProviderProps) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const signup = async (username: string, password: string, phoneNumber?: string): Promise<void> => {
|
||||||
|
try {
|
||||||
|
setIsLoading(true);
|
||||||
|
const response = await apiClient.post(`/auth/signup`, { username, password, phoneNumber });
|
||||||
|
// const { access_token, refresh_token, access_token_expires_at, refresh_token_expires_at } = response.data;
|
||||||
|
// localStorage.setItem('access_token', access_token);
|
||||||
|
// localStorage.setItem('refresh_token', refresh_token);
|
||||||
|
// localStorage.setItem('access_token_expires_at', access_token_expires_at);
|
||||||
|
// localStorage.setItem('refresh_token_expires_at', refresh_token_expires_at);
|
||||||
|
// setAccessToken(access_token);
|
||||||
|
// setRefreshToken(refresh_token);
|
||||||
|
// setIsAuthenticated(true);
|
||||||
|
// startTokenRefreshInterval();
|
||||||
|
// fetchUserProfile();
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Signup failed", err);
|
||||||
|
throw new Error("Signup failed");
|
||||||
|
} finally {
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const logout = async (): Promise<void> => {
|
const logout = async (): Promise<void> => {
|
||||||
try {
|
try {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
|
@ -154,6 +177,7 @@ export function AuthProvider({ children }: AuthProviderProps) {
|
||||||
user,
|
user,
|
||||||
login,
|
login,
|
||||||
logout,
|
logout,
|
||||||
|
signup,
|
||||||
refreshAccessToken,
|
refreshAccessToken,
|
||||||
initializeAuth,
|
initializeAuth,
|
||||||
startTokenRefreshInterval,
|
startTokenRefreshInterval,
|
||||||
|
|
Loading…
Reference in New Issue