diff --git a/tone-page-server/src/admin/controller/admin-user.controller.ts b/tone-page-server/src/admin/controller/admin-user.controller.ts index d960816..6c3fd7a 100644 --- a/tone-page-server/src/admin/controller/admin-user.controller.ts +++ b/tone-page-server/src/admin/controller/admin-user.controller.ts @@ -8,6 +8,7 @@ import { Post, Put, Query, + UseGuards, } from '@nestjs/common'; import { ListDto } from '../dto/admin-user/list.dto'; import { CreateDto } from '../dto/admin-user/create.dto'; @@ -15,10 +16,16 @@ import { UserService } from 'src/user/user.service'; import { UpdateDto } from '../dto/admin-user/update.dto'; import { UpdatePasswordDto } from '../dto/admin-user/update-password.dto'; import { RemoveUserDto } from '../dto/admin-user/remove.dto'; +import { RolesGuard } from 'src/common/guard/roles.guard'; +import { Roles } from 'src/common/decorators/role.decorator'; +import { Role } from 'src/auth/role.enum'; +import { AuthGuard } from '@nestjs/passport'; @Controller('admin/user') +@UseGuards(AuthGuard('jwt'), RolesGuard) +@Roles(Role.Admin) export class AdminUserController { - constructor(private readonly userService: UserService) {} + constructor(private readonly userService: UserService) { } @Get() async list(@Query() listDto: ListDto) { diff --git a/tone-page-server/src/admin/controller/web/admin-web-blog.controller.ts b/tone-page-server/src/admin/controller/web/admin-web-blog.controller.ts index 3af673a..9140462 100644 --- a/tone-page-server/src/admin/controller/web/admin-web-blog.controller.ts +++ b/tone-page-server/src/admin/controller/web/admin-web-blog.controller.ts @@ -7,11 +7,18 @@ import { ParseUUIDPipe, Post, Put, + UseGuards, } from '@nestjs/common'; +import { AuthGuard } from '@nestjs/passport'; import { CreateBlogDto } from 'src/admin/dto/admin-web/create-blog.dto'; +import { Role } from 'src/auth/role.enum'; import { BlogService } from 'src/blog/blog.service'; +import { Roles } from 'src/common/decorators/role.decorator'; +import { RolesGuard } from 'src/common/guard/roles.guard'; @Controller('/admin/web/blog') +@UseGuards(AuthGuard('jwt'), RolesGuard) +@Roles(Role.Admin) export class AdminWebBlogController { constructor(private readonly adminWebBlogService: BlogService) {} diff --git a/tone-page-server/src/admin/controller/web/admin-web-resource.controller.ts b/tone-page-server/src/admin/controller/web/admin-web-resource.controller.ts index 7d2cec5..3e5a919 100644 --- a/tone-page-server/src/admin/controller/web/admin-web-resource.controller.ts +++ b/tone-page-server/src/admin/controller/web/admin-web-resource.controller.ts @@ -7,13 +7,20 @@ import { ParseUUIDPipe, Post, Put, + UseGuards, } from '@nestjs/common'; +import { AuthGuard } from '@nestjs/passport'; import { CreateResourceDto } from 'src/admin/dto/admin-web/create-resource.dto'; +import { Role } from 'src/auth/role.enum'; +import { Roles } from 'src/common/decorators/role.decorator'; +import { RolesGuard } from 'src/common/guard/roles.guard'; import { ResourceService } from 'src/resource/resource.service'; @Controller('/admin/web/resource') +@UseGuards(AuthGuard('jwt'), RolesGuard) +@Roles(Role.Admin) export class AdminWebResourceController { - constructor(private readonly resourceService: ResourceService) {} + constructor(private readonly resourceService: ResourceService) { } @Get() async list() { diff --git a/tone-page-server/src/auth/role.enum.ts b/tone-page-server/src/auth/role.enum.ts new file mode 100644 index 0000000..a286eb4 --- /dev/null +++ b/tone-page-server/src/auth/role.enum.ts @@ -0,0 +1,3 @@ +export enum Role { + Admin = 'admin', +} \ No newline at end of file diff --git a/tone-page-server/src/auth/strategies/jwt.strategy.ts b/tone-page-server/src/auth/strategies/jwt.strategy.ts index 11ec8cd..817c184 100644 --- a/tone-page-server/src/auth/strategies/jwt.strategy.ts +++ b/tone-page-server/src/auth/strategies/jwt.strategy.ts @@ -1,12 +1,14 @@ -import { Injectable, UnauthorizedException } from '@nestjs/common'; +import { BadRequestException, Injectable, UnauthorizedException } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import { PassportStrategy } from '@nestjs/passport'; import { ExtractJwt, Strategy } from 'passport-jwt'; import { UserSessionService } from 'src/user/services/user-session.service'; +import { UserService } from 'src/user/user.service'; @Injectable() export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') { constructor( + private readonly userService: UserService, private readonly userSessionService: UserSessionService, private readonly configService: ConfigService, ) { @@ -28,9 +30,14 @@ export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') { throw new UnauthorizedException('登录凭证已过期,请重新登录'); } + const user = await this.userService.findById(userId); + if (!user) { + throw new BadRequestException('用户不存在'); + } + return { - userId, - sessionId, + ...user, + sessionId }; } } diff --git a/tone-page-server/src/common/decorators/permissions.decorator.ts b/tone-page-server/src/common/decorators/permissions.decorator.ts deleted file mode 100644 index ad21bf4..0000000 --- a/tone-page-server/src/common/decorators/permissions.decorator.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { SetMetadata } from '@nestjs/common'; - -export const Permissions = (...permissions: string[]) => - SetMetadata('permissions', permissions); diff --git a/tone-page-server/src/common/decorators/role.decorator.ts b/tone-page-server/src/common/decorators/role.decorator.ts index b037672..ff9ddef 100644 --- a/tone-page-server/src/common/decorators/role.decorator.ts +++ b/tone-page-server/src/common/decorators/role.decorator.ts @@ -1,3 +1,4 @@ import { SetMetadata } from '@nestjs/common'; +import { Role } from 'src/auth/role.enum'; -export const Roles = (...roles: string[]) => SetMetadata('roles', roles); +export const Roles = (...roles: Role[]) => SetMetadata('roles', roles); diff --git a/tone-page-server/src/common/guard/roles.guard.ts b/tone-page-server/src/common/guard/roles.guard.ts index 648d866..6ef59f2 100644 --- a/tone-page-server/src/common/guard/roles.guard.ts +++ b/tone-page-server/src/common/guard/roles.guard.ts @@ -1,5 +1,7 @@ -import { CanActivate, ExecutionContext, Injectable, RequestTimeoutException } from '@nestjs/common'; +import { BadRequestException, CanActivate, ExecutionContext, ForbiddenException, Injectable } from '@nestjs/common'; import { Reflector } from '@nestjs/core'; +import { Role } from 'src/auth/role.enum'; +import { User } from 'src/user/entities/user.entity'; @Injectable() export class RolesGuard implements CanActivate { @@ -8,7 +10,7 @@ export class RolesGuard implements CanActivate { ) { } async canActivate(context: ExecutionContext): Promise { - const requiredRoles = this.reflector.getAllAndOverride('roles', [ + const requiredRoles = this.reflector.getAllAndOverride('roles', [ context.getHandler(), context.getClass(), ]); @@ -16,13 +18,16 @@ export class RolesGuard implements CanActivate { if (!requiredRoles) return true; const request = context.switchToHttp().getRequest(); - const userId = request.user?.userId; + const user = request.user as (User | void); - if (!userId) return false; + if (!user) { + throw new BadRequestException('服务器内部错误'); + } - // 查询用户拥有的有效角色Id TODO + if (!requiredRoles.some(role => user.roles.includes(role))) { + throw new ForbiddenException('权限不足'); + } - // return requiredRoles.some((role) => userRoleNames.includes(role)); - return false; + return true; } } diff --git a/tone-page-server/src/user/entities/user-session.entity.ts b/tone-page-server/src/user/entities/user-session.entity.ts index e15bafe..6c1aede 100644 --- a/tone-page-server/src/user/entities/user-session.entity.ts +++ b/tone-page-server/src/user/entities/user-session.entity.ts @@ -25,3 +25,7 @@ export class UserSession { @DeleteDateColumn({ nullable: true, precision: 3 }) deletedAt: Date; } + +/** + * 考虑是否使用sessionId代替id,以节省存储空间 + */ \ No newline at end of file diff --git a/tone-page-server/src/user/entities/user.entity.ts b/tone-page-server/src/user/entities/user.entity.ts index 217d27d..c5ad7e5 100644 --- a/tone-page-server/src/user/entities/user.entity.ts +++ b/tone-page-server/src/user/entities/user.entity.ts @@ -1,3 +1,4 @@ +import { Role } from 'src/auth/role.enum'; import { BeforeInsert, Column, @@ -84,4 +85,7 @@ export class User { @DeleteDateColumn({ nullable: true, precision: 3 }) deletedAt: Date; + + @Column('simple-array', { default: '' }) + roles: Role[]; } diff --git a/tone-page-server/src/user/user.service.ts b/tone-page-server/src/user/user.service.ts index a7756f4..e52adea 100644 --- a/tone-page-server/src/user/user.service.ts +++ b/tone-page-server/src/user/user.service.ts @@ -18,8 +18,11 @@ export class UserService { constructor( @InjectRepository(User) private readonly userRepository: Repository, - ) {} + ) { } + /** + * @deprecated 尽量不使用该方法 + */ async findOne( options: UserFindOptions | UserFindOptions[], additionalOptions?: { withDeleted?: boolean }, @@ -33,6 +36,14 @@ export class UserService { }); } + async findById(userId: string): Promise { + return this.userRepository.findOne({ + where: { + userId, + } + }); + } + async create(user: Partial): Promise { try { const newUser = this.userRepository.create(user); @@ -114,7 +125,7 @@ export class UserService { if (error.message.includes('IDX_user_phone')) { return '手机号已被使用'; } - return '数据已存在,请检查输入'; + return '该登陆方式异常,请更换其他登陆方式或联系管理员'; } async list(page = 1, pageSize = 20) { diff --git a/tone-page-web/components/nav-user.tsx b/tone-page-web/components/nav-user.tsx index 09c75ce..6502128 100644 --- a/tone-page-web/components/nav-user.tsx +++ b/tone-page-web/components/nav-user.tsx @@ -54,6 +54,7 @@ export function NavUser({ }: {}) { ); if (!isLoading && !error && !user) { + console.log(isLoading, error, user) router.replace('/console/login'); localStorage.removeItem('token'); toast.error('账户状态异常,请重新登录');