refactor: 更新核心服务和应用配置
- 更新用户实体和DTO结构 - 重构用户服务逻辑 - 更新登录核心服务 - 调整应用模块配置以适配新的业务模块结构 - 更新应用控制器和服务
This commit is contained in:
@@ -1,8 +1,7 @@
|
|||||||
import { Controller, Get } from '@nestjs/common';
|
import { Controller, Get } from '@nestjs/common';
|
||||||
import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger';
|
import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger';
|
||||||
import { AppService } from './app.service';
|
import { AppService } from './app.service';
|
||||||
import { AppStatusResponseDto } from './dto/app.dto';
|
import { AppStatusResponseDto, ErrorResponseDto } from './business/shared';
|
||||||
import { ErrorResponseDto } from './dto/error_response.dto';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 应用根控制器
|
* 应用根控制器
|
||||||
|
|||||||
@@ -1,14 +1,19 @@
|
|||||||
import { Module } from '@nestjs/common';
|
import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common';
|
||||||
import { ConfigModule } from '@nestjs/config';
|
import { ConfigModule } from '@nestjs/config';
|
||||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||||
|
import { APP_INTERCEPTOR } from '@nestjs/core';
|
||||||
import { AppController } from './app.controller';
|
import { AppController } from './app.controller';
|
||||||
import { AppService } from './app.service';
|
import { AppService } from './app.service';
|
||||||
import { LoggerModule } from './core/utils/logger/logger.module';
|
import { LoggerModule } from './core/utils/logger/logger.module';
|
||||||
import { UsersModule } from './core/db/users/users.module';
|
import { UsersModule } from './core/db/users/users.module';
|
||||||
import { LoginCoreModule } from './core/login_core/login_core.module';
|
import { LoginCoreModule } from './core/login_core/login_core.module';
|
||||||
import { LoginModule } from './business/login/login.module';
|
import { AuthModule } from './business/auth/auth.module';
|
||||||
import { RedisModule } from './core/redis/redis.module';
|
import { RedisModule } from './core/redis/redis.module';
|
||||||
import { AdminModule } from './business/admin/admin.module';
|
import { AdminModule } from './business/admin/admin.module';
|
||||||
|
import { UserMgmtModule } from './business/user-mgmt/user-mgmt.module';
|
||||||
|
import { SecurityModule } from './business/security/security.module';
|
||||||
|
import { MaintenanceMiddleware } from './business/security/middleware/maintenance.middleware';
|
||||||
|
import { ContentTypeMiddleware } from './business/security/middleware/content-type.middleware';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查数据库配置是否完整 by angjustinl 2025-12-17
|
* 检查数据库配置是否完整 by angjustinl 2025-12-17
|
||||||
@@ -61,10 +66,32 @@ function isDatabaseConfigured(): boolean {
|
|||||||
// 根据数据库配置选择用户模块模式
|
// 根据数据库配置选择用户模块模式
|
||||||
isDatabaseConfigured() ? UsersModule.forDatabase() : UsersModule.forMemory(),
|
isDatabaseConfigured() ? UsersModule.forDatabase() : UsersModule.forMemory(),
|
||||||
LoginCoreModule,
|
LoginCoreModule,
|
||||||
LoginModule,
|
AuthModule,
|
||||||
|
UserMgmtModule,
|
||||||
AdminModule,
|
AdminModule,
|
||||||
|
SecurityModule,
|
||||||
],
|
],
|
||||||
controllers: [AppController],
|
controllers: [AppController],
|
||||||
providers: [AppService],
|
providers: [
|
||||||
|
AppService,
|
||||||
|
// 注意:全局拦截器现在由SecurityModule提供
|
||||||
|
],
|
||||||
})
|
})
|
||||||
export class AppModule {}
|
export class AppModule implements NestModule {
|
||||||
|
/**
|
||||||
|
* 配置中间件
|
||||||
|
*
|
||||||
|
* @param consumer 中间件消费者
|
||||||
|
*/
|
||||||
|
configure(consumer: MiddlewareConsumer) {
|
||||||
|
// 1. 维护模式中间件 - 最高优先级
|
||||||
|
consumer
|
||||||
|
.apply(MaintenanceMiddleware)
|
||||||
|
.forRoutes('*');
|
||||||
|
|
||||||
|
// 2. 内容类型检查中间件
|
||||||
|
consumer
|
||||||
|
.apply(ContentTypeMiddleware)
|
||||||
|
.forRoutes('*');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
import { AppStatusResponseDto } from './dto/app.dto';
|
import { AppStatusResponseDto } from './business/shared';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 应用服务类
|
* 应用服务类
|
||||||
|
|||||||
@@ -24,8 +24,10 @@ import {
|
|||||||
Max,
|
Max,
|
||||||
IsOptional,
|
IsOptional,
|
||||||
Length,
|
Length,
|
||||||
IsNotEmpty
|
IsNotEmpty,
|
||||||
|
IsEnum
|
||||||
} from 'class-validator';
|
} from 'class-validator';
|
||||||
|
import { UserStatus } from '../../../business/user-mgmt/enums/user-status.enum';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建用户数据传输对象
|
* 创建用户数据传输对象
|
||||||
@@ -232,4 +234,30 @@ export class CreateUserDto {
|
|||||||
*/
|
*/
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
email_verified?: boolean = false;
|
email_verified?: boolean = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户状态
|
||||||
|
*
|
||||||
|
* 业务规则:
|
||||||
|
* - 可选字段,默认为active(正常状态)
|
||||||
|
* - 控制用户账户的可用性和权限
|
||||||
|
* - 支持多种状态:正常、未激活、锁定、禁用等
|
||||||
|
* - 影响用户登录和API访问权限
|
||||||
|
*
|
||||||
|
* 验证规则:
|
||||||
|
* - 可选字段验证
|
||||||
|
* - 枚举类型验证
|
||||||
|
* - 默认值:active(正常状态)
|
||||||
|
*
|
||||||
|
* 状态说明:
|
||||||
|
* - active: 正常状态,可以正常使用
|
||||||
|
* - inactive: 未激活,需要邮箱验证
|
||||||
|
* - locked: 已锁定,临时禁用
|
||||||
|
* - banned: 已禁用,管理员操作
|
||||||
|
* - deleted: 已删除,软删除状态
|
||||||
|
* - pending: 待审核,需要管理员审核
|
||||||
|
*/
|
||||||
|
@IsOptional()
|
||||||
|
@IsEnum(UserStatus, { message: '用户状态必须是有效的枚举值' })
|
||||||
|
status?: UserStatus = UserStatus.ACTIVE;
|
||||||
}
|
}
|
||||||
@@ -20,6 +20,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Entity, Column, PrimaryGeneratedColumn, CreateDateColumn, UpdateDateColumn } from 'typeorm';
|
import { Entity, Column, PrimaryGeneratedColumn, CreateDateColumn, UpdateDateColumn } from 'typeorm';
|
||||||
|
import { UserStatus } from '../../../business/user-mgmt/enums/user-status.enum';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用户实体类
|
* 用户实体类
|
||||||
@@ -337,6 +338,44 @@ export class Users {
|
|||||||
})
|
})
|
||||||
role: number;
|
role: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户状态
|
||||||
|
*
|
||||||
|
* 数据库设计:
|
||||||
|
* - 类型:VARCHAR(20),存储状态枚举值
|
||||||
|
* - 约束:非空、默认值'active'
|
||||||
|
* - 索引:用于状态查询和统计
|
||||||
|
*
|
||||||
|
* 业务规则:
|
||||||
|
* - 控制用户账户的可用性和权限
|
||||||
|
* - active:正常状态,可以正常使用
|
||||||
|
* - inactive:未激活,需要邮箱验证
|
||||||
|
* - locked:已锁定,临时禁用
|
||||||
|
* - banned:已禁用,管理员操作
|
||||||
|
* - deleted:已删除,软删除状态
|
||||||
|
* - pending:待审核,需要管理员审核
|
||||||
|
*
|
||||||
|
* 安全控制:
|
||||||
|
* - 登录时检查状态权限
|
||||||
|
* - API访问时验证状态
|
||||||
|
* - 状态变更记录审计日志
|
||||||
|
* - 支持批量状态管理
|
||||||
|
*
|
||||||
|
* 应用场景:
|
||||||
|
* - 账户安全管理
|
||||||
|
* - 用户生命周期控制
|
||||||
|
* - 违规用户处理
|
||||||
|
* - 系统维护和升级
|
||||||
|
*/
|
||||||
|
@Column({
|
||||||
|
type: 'varchar',
|
||||||
|
length: 20,
|
||||||
|
nullable: true,
|
||||||
|
default: UserStatus.ACTIVE,
|
||||||
|
comment: '用户状态:active-正常,inactive-未激活,locked-锁定,banned-禁用,deleted-删除,pending-待审核'
|
||||||
|
})
|
||||||
|
status?: UserStatus;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建时间
|
* 创建时间
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import { InjectRepository } from '@nestjs/typeorm';
|
|||||||
import { Repository, FindOptionsWhere } from 'typeorm';
|
import { Repository, FindOptionsWhere } from 'typeorm';
|
||||||
import { Users } from './users.entity';
|
import { Users } from './users.entity';
|
||||||
import { CreateUserDto } from './users.dto';
|
import { CreateUserDto } from './users.dto';
|
||||||
|
import { UserStatus } from '../../../business/user-mgmt/enums/user-status.enum';
|
||||||
import { validate } from 'class-validator';
|
import { validate } from 'class-validator';
|
||||||
import { plainToClass } from 'class-transformer';
|
import { plainToClass } from 'class-transformer';
|
||||||
|
|
||||||
@@ -97,6 +98,7 @@ export class UsersService {
|
|||||||
user.avatar_url = createUserDto.avatar_url || null;
|
user.avatar_url = createUserDto.avatar_url || null;
|
||||||
user.role = createUserDto.role || 1;
|
user.role = createUserDto.role || 1;
|
||||||
user.email_verified = createUserDto.email_verified || false;
|
user.email_verified = createUserDto.email_verified || false;
|
||||||
|
user.status = createUserDto.status || UserStatus.ACTIVE;
|
||||||
|
|
||||||
// 保存到数据库
|
// 保存到数据库
|
||||||
return await this.usersRepository.save(user);
|
return await this.usersRepository.save(user);
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
import { Injectable, ConflictException, NotFoundException, BadRequestException } from '@nestjs/common';
|
import { Injectable, ConflictException, NotFoundException, BadRequestException } from '@nestjs/common';
|
||||||
import { Users } from './users.entity';
|
import { Users } from './users.entity';
|
||||||
import { CreateUserDto } from './users.dto';
|
import { CreateUserDto } from './users.dto';
|
||||||
|
import { UserStatus } from '../../../business/user-mgmt/enums/user-status.enum';
|
||||||
import { validate } from 'class-validator';
|
import { validate } from 'class-validator';
|
||||||
import { plainToClass } from 'class-transformer';
|
import { plainToClass } from 'class-transformer';
|
||||||
|
|
||||||
@@ -98,6 +99,7 @@ export class UsersMemoryService {
|
|||||||
user.avatar_url = createUserDto.avatar_url || null;
|
user.avatar_url = createUserDto.avatar_url || null;
|
||||||
user.role = createUserDto.role || 1;
|
user.role = createUserDto.role || 1;
|
||||||
user.email_verified = createUserDto.email_verified || false;
|
user.email_verified = createUserDto.email_verified || false;
|
||||||
|
user.status = createUserDto.status || UserStatus.ACTIVE;
|
||||||
user.created_at = new Date();
|
user.created_at = new Date();
|
||||||
user.updated_at = new Date();
|
user.updated_at = new Date();
|
||||||
|
|
||||||
|
|||||||
@@ -1,81 +0,0 @@
|
|||||||
import { ExecutionContext, UnauthorizedException } from '@nestjs/common';
|
|
||||||
import { AdminCoreService, AdminAuthPayload } from '../admin_core/admin_core.service';
|
|
||||||
import { AdminGuard } from './admin.guard';
|
|
||||||
|
|
||||||
describe('AdminGuard', () => {
|
|
||||||
const payload: AdminAuthPayload = {
|
|
||||||
adminId: '1',
|
|
||||||
username: 'admin',
|
|
||||||
role: 9,
|
|
||||||
iat: 1,
|
|
||||||
exp: 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
const adminCoreServiceMock: Pick<AdminCoreService, 'verifyToken'> = {
|
|
||||||
verifyToken: jest.fn(),
|
|
||||||
};
|
|
||||||
|
|
||||||
const makeContext = (authorization?: any) => {
|
|
||||||
const req: any = { headers: {} };
|
|
||||||
if (authorization !== undefined) {
|
|
||||||
req.headers['authorization'] = authorization;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ctx: Partial<ExecutionContext> = {
|
|
||||||
switchToHttp: () => ({
|
|
||||||
getRequest: () => req,
|
|
||||||
getResponse: () => ({} as any),
|
|
||||||
getNext: () => ({} as any),
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
|
|
||||||
return { ctx: ctx as ExecutionContext, req };
|
|
||||||
};
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
jest.resetAllMocks();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should allow access with valid admin token', () => {
|
|
||||||
(adminCoreServiceMock.verifyToken as jest.Mock).mockReturnValue(payload);
|
|
||||||
|
|
||||||
const guard = new AdminGuard(adminCoreServiceMock as AdminCoreService);
|
|
||||||
const { ctx, req } = makeContext('Bearer valid');
|
|
||||||
|
|
||||||
expect(guard.canActivate(ctx)).toBe(true);
|
|
||||||
expect(adminCoreServiceMock.verifyToken).toHaveBeenCalledWith('valid');
|
|
||||||
expect(req.admin).toEqual(payload);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should deny access without token', () => {
|
|
||||||
const guard = new AdminGuard(adminCoreServiceMock as AdminCoreService);
|
|
||||||
const { ctx } = makeContext(undefined);
|
|
||||||
|
|
||||||
expect(() => guard.canActivate(ctx)).toThrow(UnauthorizedException);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should deny access with invalid Authorization format', () => {
|
|
||||||
const guard = new AdminGuard(adminCoreServiceMock as AdminCoreService);
|
|
||||||
const { ctx } = makeContext('InvalidFormat');
|
|
||||||
|
|
||||||
expect(() => guard.canActivate(ctx)).toThrow(UnauthorizedException);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should deny access when verifyToken throws (invalid/expired)', () => {
|
|
||||||
(adminCoreServiceMock.verifyToken as jest.Mock).mockImplementation(() => {
|
|
||||||
throw new UnauthorizedException('Token已过期');
|
|
||||||
});
|
|
||||||
|
|
||||||
const guard = new AdminGuard(adminCoreServiceMock as AdminCoreService);
|
|
||||||
const { ctx } = makeContext('Bearer bad');
|
|
||||||
|
|
||||||
expect(() => guard.canActivate(ctx)).toThrow(UnauthorizedException);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should deny access when Authorization header is an array', () => {
|
|
||||||
const guard = new AdminGuard(adminCoreServiceMock as AdminCoreService);
|
|
||||||
const { ctx } = makeContext(['Bearer token']);
|
|
||||||
|
|
||||||
expect(() => guard.canActivate(ctx)).toThrow(UnauthorizedException);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
/**
|
|
||||||
* 管理员鉴权守卫
|
|
||||||
*
|
|
||||||
* 功能描述:
|
|
||||||
* - 保护后台管理接口
|
|
||||||
* - 校验 Authorization: Bearer <admin_token>
|
|
||||||
* - 仅允许 role=9 的管理员访问
|
|
||||||
*
|
|
||||||
* @author jianuo
|
|
||||||
* @version 1.0.0
|
|
||||||
* @since 2025-12-19
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { CanActivate, ExecutionContext, Injectable, UnauthorizedException } from '@nestjs/common';
|
|
||||||
import { Request } from 'express';
|
|
||||||
import { AdminCoreService, AdminAuthPayload } from '../admin_core/admin_core.service';
|
|
||||||
|
|
||||||
export interface AdminRequest extends Request {
|
|
||||||
admin?: AdminAuthPayload;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class AdminGuard implements CanActivate {
|
|
||||||
constructor(private readonly adminCoreService: AdminCoreService) {}
|
|
||||||
|
|
||||||
canActivate(context: ExecutionContext): boolean {
|
|
||||||
const req = context.switchToHttp().getRequest<AdminRequest>();
|
|
||||||
const auth = req.headers['authorization'];
|
|
||||||
|
|
||||||
if (!auth || Array.isArray(auth)) {
|
|
||||||
throw new UnauthorizedException('缺少Authorization头');
|
|
||||||
}
|
|
||||||
|
|
||||||
const [scheme, token] = auth.split(' ');
|
|
||||||
if (scheme !== 'Bearer' || !token) {
|
|
||||||
throw new UnauthorizedException('Authorization格式错误');
|
|
||||||
}
|
|
||||||
|
|
||||||
const payload = this.adminCoreService.verifyToken(token);
|
|
||||||
req.admin = payload;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -7,7 +7,8 @@ import { LoginCoreService } from './login_core.service';
|
|||||||
import { UsersService } from '../db/users/users.service';
|
import { UsersService } from '../db/users/users.service';
|
||||||
import { EmailService } from '../utils/email/email.service';
|
import { EmailService } from '../utils/email/email.service';
|
||||||
import { VerificationService } from '../utils/verification/verification.service';
|
import { VerificationService } from '../utils/verification/verification.service';
|
||||||
import { UnauthorizedException, ConflictException, NotFoundException, BadRequestException } from '@nestjs/common';
|
import { UnauthorizedException, ConflictException, NotFoundException, BadRequestException, ForbiddenException } from '@nestjs/common';
|
||||||
|
import { UserStatus } from '../../business/user-mgmt/enums/user-status.enum';
|
||||||
|
|
||||||
describe('LoginCoreService', () => {
|
describe('LoginCoreService', () => {
|
||||||
let service: LoginCoreService;
|
let service: LoginCoreService;
|
||||||
@@ -26,6 +27,7 @@ describe('LoginCoreService', () => {
|
|||||||
avatar_url: null as string | null,
|
avatar_url: null as string | null,
|
||||||
role: 1,
|
role: 1,
|
||||||
email_verified: false,
|
email_verified: false,
|
||||||
|
status: UserStatus.ACTIVE, // 使用正确的枚举类型
|
||||||
created_at: new Date(),
|
created_at: new Date(),
|
||||||
updated_at: new Date()
|
updated_at: new Date()
|
||||||
};
|
};
|
||||||
@@ -105,7 +107,9 @@ describe('LoginCoreService', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should throw UnauthorizedException for wrong password', async () => {
|
it('should throw UnauthorizedException for wrong password', async () => {
|
||||||
usersService.findByUsername.mockResolvedValue(mockUser);
|
// 创建一个正常状态的用户来测试密码验证
|
||||||
|
const activeUser = { ...mockUser, status: UserStatus.ACTIVE };
|
||||||
|
usersService.findByUsername.mockResolvedValue(activeUser);
|
||||||
jest.spyOn(service as any, 'verifyPassword').mockResolvedValue(false);
|
jest.spyOn(service as any, 'verifyPassword').mockResolvedValue(false);
|
||||||
|
|
||||||
await expect(service.login({
|
await expect(service.login({
|
||||||
@@ -113,6 +117,17 @@ describe('LoginCoreService', () => {
|
|||||||
password: 'wrongpassword'
|
password: 'wrongpassword'
|
||||||
})).rejects.toThrow(UnauthorizedException);
|
})).rejects.toThrow(UnauthorizedException);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should throw ForbiddenException for inactive user', async () => {
|
||||||
|
// 测试非活跃用户状态
|
||||||
|
const inactiveUser = { ...mockUser, status: UserStatus.INACTIVE };
|
||||||
|
usersService.findByUsername.mockResolvedValue(inactiveUser);
|
||||||
|
|
||||||
|
await expect(service.login({
|
||||||
|
identifier: 'testuser',
|
||||||
|
password: 'password123'
|
||||||
|
})).rejects.toThrow(ForbiddenException);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('register', () => {
|
describe('register', () => {
|
||||||
|
|||||||
@@ -16,11 +16,12 @@
|
|||||||
* @since 2025-12-17
|
* @since 2025-12-17
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Injectable, UnauthorizedException, ConflictException, NotFoundException, BadRequestException, Inject } from '@nestjs/common';
|
import { Injectable, UnauthorizedException, ConflictException, NotFoundException, BadRequestException, ForbiddenException, Inject } from '@nestjs/common';
|
||||||
import { Users } from '../db/users/users.entity';
|
import { Users } from '../db/users/users.entity';
|
||||||
import { UsersService } from '../db/users/users.service';
|
import { UsersService } from '../db/users/users.service';
|
||||||
import { EmailService, EmailSendResult } from '../utils/email/email.service';
|
import { EmailService, EmailSendResult } from '../utils/email/email.service';
|
||||||
import { VerificationService, VerificationCodeType } from '../utils/verification/verification.service';
|
import { VerificationService, VerificationCodeType } from '../utils/verification/verification.service';
|
||||||
|
import { UserStatus, canUserLogin, getUserStatusErrorMessage } from '../../business/user-mgmt/enums/user-status.enum';
|
||||||
import * as bcrypt from 'bcrypt';
|
import * as bcrypt from 'bcrypt';
|
||||||
import * as crypto from 'crypto';
|
import * as crypto from 'crypto';
|
||||||
|
|
||||||
@@ -140,6 +141,11 @@ export class LoginCoreService {
|
|||||||
throw new UnauthorizedException('用户名、邮箱或手机号不存在');
|
throw new UnauthorizedException('用户名、邮箱或手机号不存在');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 检查用户状态
|
||||||
|
if (!canUserLogin(user.status)) {
|
||||||
|
throw new ForbiddenException(getUserStatusErrorMessage(user.status));
|
||||||
|
}
|
||||||
|
|
||||||
// 检查是否为OAuth用户(没有密码)
|
// 检查是否为OAuth用户(没有密码)
|
||||||
if (!user.password_hash) {
|
if (!user.password_hash) {
|
||||||
throw new UnauthorizedException('该账户使用第三方登录,请使用对应的登录方式');
|
throw new UnauthorizedException('该账户使用第三方登录,请使用对应的登录方式');
|
||||||
@@ -196,6 +202,7 @@ export class LoginCoreService {
|
|||||||
email,
|
email,
|
||||||
phone,
|
phone,
|
||||||
role: 1, // 默认普通用户
|
role: 1, // 默认普通用户
|
||||||
|
status: UserStatus.ACTIVE, // 默认激活状态
|
||||||
email_verified: email ? true : false // 如果提供了邮箱且验证码验证通过,则标记为已验证
|
email_verified: email ? true : false // 如果提供了邮箱且验证码验证通过,则标记为已验证
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -257,6 +264,7 @@ export class LoginCoreService {
|
|||||||
github_id,
|
github_id,
|
||||||
avatar_url,
|
avatar_url,
|
||||||
role: 1, // 默认普通用户
|
role: 1, // 默认普通用户
|
||||||
|
status: UserStatus.ACTIVE, // GitHub用户直接激活
|
||||||
email_verified: email ? true : false // GitHub邮箱直接验证
|
email_verified: email ? true : false // GitHub邮箱直接验证
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user