- Nest.js从零开始学习
- Nest.js概述
- 环境搭建
- 基本概念
- 依赖注入(Dependency Injection)
- 中间件与管道
- 路由与请求处理
- Nest.js 框架异常处理
- Nest.js 框架数据库操作
- Nest.js 框架认证与授权
- Nest.js 框架 WebSockets 与实时通信
- Nest.js 框架 GraphQL 支持
- Nest.js 框架微服务架构
- Nest.js 框架测试
- Nest.js 框架性能优化与安全
- Nest.js 项目实战:创建一个完整的用户管理应用
Nest.js 框架认证与授权
class Nest.js,Jwt在现代 Web 应用中,认证与授权是确保安全性的关键部分。Nest.js 提供了强大的工具来实现这些功能,尤其是通过 JWT(JSON Web Token)认证机制、Guards 和策略。本文将详细介绍如何在 Nest.js 中实现 JWT 认证与授权,并结合具体示例进行讲解。
1. JWT 认证机制概述
JWT 是一种开放标准(RFC 7519),用于在各方之间以 JSON 对象的方式安全地传输信息。JWT 由三部分组成:头部(Header)、有效载荷(Payload)和签名(Signature)。通过 JWT,用户可以在登录后获得一个令牌,该令牌在后续请求中作为身份凭证。
2. 安装相关依赖
首先,我们需要安装一些必要的依赖,包括 @nestjs/jwt
和 passport
相关的包。
npm install @nestjs/passport passport passport-jwt @nestjs/jwt bcrypt
3. 创建认证模块
3.1 创建用户实体
我们首先需要一个用户实体,用于数据库存储用户信息。在 users
文件夹中创建 user.entity.ts
:
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column()
username: string;
@Column()
password: string;
}
3.2 创建用户服务
在 users.service.ts
中实现用户注册和查找功能:
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './user.entity';
import * as bcrypt from 'bcrypt';
@Injectable()
export class UsersService {
constructor(
@InjectRepository(User)
private usersRepository: Repository<User>,
) {}
async create(username: string, password: string): Promise<User> {
const hashedPassword = await bcrypt.hash(password, 10);
const user = this.usersRepository.create({ username, password: hashedPassword });
return this.usersRepository.save(user);
}
async findOne(username: string): Promise<User | undefined> {
return this.usersRepository.findOneBy({ username });
}
}
3.3 创建认证模块
接下来,创建一个认证模块 auth.module.ts
:
import { Module } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt';
import { AuthService } from './auth.service';
import { UsersModule } from '../users/users.module';
import { AuthController } from './auth.controller';
import { JwtStrategy } from './jwt.strategy';
@Module({
imports: [
UsersModule,
JwtModule.register({
secret: 'your_secret_key', // 应用的密钥,生产中应放在环境变量中
signOptions: { expiresIn: '60s' }, // 令牌过期时间
}),
],
providers: [AuthService, JwtStrategy],
controllers: [AuthController],
})
export class AuthModule {}
3.4 创建认证服务
在 auth.service.ts
中实现用户登录和 JWT 生成:
import { Injectable } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { UsersService } from '../users/users.service';
import { User } from '../users/user.entity';
@Injectable()
export class AuthService {
constructor(
private usersService: UsersService,
private jwtService: JwtService,
) {}
async validateUser(username: string, password: string): Promise<any> {
const user = await this.usersService.findOne(username);
if (user && (await bcrypt.compare(password, user.password))) {
const { password, ...result } = user; // 去掉密码
return result;
}
return null;
}
async login(user: User) {
const payload = { username: user.username, sub: user.id };
return {
access_token: this.jwtService.sign(payload),
};
}
}
3.5 创建认证控制器
在 auth.controller.ts
中定义登录接口:
import { Controller, Post, Body } from '@nestjs/common';
import { AuthService } from './auth.service';
import { UsersService } from '../users/users.service';
@Controller('auth')
export class AuthController {
constructor(
private authService: AuthService,
private usersService: UsersService,
) {}
@Post('register')
async register(@Body() body: { username: string; password: string }) {
return this.usersService.create(body.username, body.password);
}
@Post('login')
async login(@Body() body: { username: string; password: string }) {
const user = await this.authService.validateUser(body.username, body.password);
if (!user) {
throw new Error('Invalid credentials');
}
return this.authService.login(user);
}
}
4. Guards 与策略
Guards 用于实现请求的授权逻辑,可以通过实现 CanActivate
接口来定义。策略用于验证用户身份。
4.1 创建 JWT 策略
在 jwt.strategy.ts
中定义 JWT 策略:
import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { Strategy, ExtractJwt } from 'passport-jwt';
import { UsersService } from '../users/users.service';
import { User } from '../users/user.entity';
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(private usersService: UsersService) {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: 'your_secret_key', // 与 JwtModule 中的密钥相同
});
}
async validate(payload: any): Promise<User> {
return this.usersService.findOne(payload.username);
}
}
4.2 创建 Auth Guard
Nest.js 提供了 @UseGuards()
装饰器来使用 Guard。可以在控制器中对特定路由使用。
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {
canActivate(context: ExecutionContext) {
return super.canActivate(context);
}
}
4.3 使用 Guard
在需要保护的控制器中使用 JWT Guard:
import { Controller, Get, UseGuards } from '@nestjs/common';
import { JwtAuthGuard } from './jwt-auth.guard';
@Controller('profile')
export class ProfileController {
@UseGuards(JwtAuthGuard)
@Get()
getProfile() {
return { message: 'This is your profile' };
}
}
5. 完整模块示例
最后,将所有模块整合在 app.module.ts
中:
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AuthModule } from './auth/auth.module';
import { UsersModule } from './users/users.module';
import { ProfileController } from './auth/profile.controller';
@Module({
imports: [
TypeOrmModule.forRoot({
type: 'postgres',
host: 'localhost',
port: 5432,
username: 'your_username',
password: 'your_password',
database: 'your_database',
entities: [__dirname + '/**/*.entity{.ts,.js}'],
synchronize: true,
}),
UsersModule,
AuthModule,
],
controllers: [ProfileController],
})
export class AppModule {}
6. 总结
通过上述步骤,我们实现了在 Nest.js 中使用 JWT 进行用户认证与授权的完整流程。我们创建了用户实体、服务和控制器,并通过 JWT 策略和 Guards 保护了特定路由。这种方式不仅提高了安全性,还通过模块化的设计提高了代码的可维护性和可扩展性。
- 用户注册与登录:使用 bcrypt 加密密码并生成 JWT 令牌。
- 保护路由:通过 Guards 和策略确保只有认证用户可以访问特定资源。
Nest.js 的认证与授权机制灵活而强大,可以根据具体需求进行扩展和定制,适应各种复杂的应用场景。