NestJS入门Authentication认证,TypeORM数据库连接
1.Authentication依赖包安装(passport-jwt)
yarn add @nestjs/passport passport passport-local @types/passport-local @nestjs/jwt passport-jwt @types/passport-jwt --save-dev
2.书写加密类,继承内置类、重写validate方法
// jwt.strategy.ts
import {
Strategy } from 'passport-local';
import {
PassportStrategy } from '@nestjs/passport';
import {
Injectable, UnauthorizedException } from '@nestjs/common';
import {
AuthService } from './auth.service';
/**
* * 我们遵循了之前描述的所有Passport策略。在我们使用passport-local的用例中,没有配置选项,所以我们的构造函数只是调用super(),没有选项对象。
*/
/**
* 把用户信息存储到user中的类,继承内置类PassportStrategy、重写validate方法
*/
@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy, 'encry') {
// 继承PassportStrategy方法抛出的类,传递一个Strategy ,第二个参数是自定义的加密的字符串
constructor(private readonly authService: AuthService) {
// 依赖注入服务
super(); // 并且调用父类的构造函数
}
public async validate(username: string, password: string): Promise<any> {
const user = await this.authService.validateUser(username, password); // (模拟)去数据库 验证是否成功
if (!user) {
throw new UnauthorizedException(); // 抛出未授权异常
}
return user; // validate()方法返回的值自动创建一个对象,并将其分配给Request对象:获取例如:req.user
}
}
validate方法的两个参数,当使用守卫装饰路由后自动在body中注入成形参,然后提供给validate方法内部使用,当验证没有发生错误的情况下,数据在返回的时候被自动注入到request请求对象中,增加了一个user属性,里面包含了返回的数据,类型不限
validate由于继承了内置的类,所以只需要书写守卫装饰器,该方法会被系统自动调用
3.书写认证服务,模拟实现账号密码验证,登录成功生成token
// auth.service.ts
import {
Injectable } from '@nestjs/common';
import {
JwtService } from '@nestjs/jwt'; // 引入jwt
/**
* 验证登录账号密码正确性,并产生token
* @function validateUser 验证登录账号密码正确性
* @function login 产生token
*/
@Injectable()
export class AuthService {
constructor(
// private readonly usersService: UsersService,
private readonly jwtService: JwtService,
) {
}
/**
* 模拟数据库匹配账号密码
* @param username 用户名
* @param pass 密码
*/
public async validateUser(username: string, pass: string): Promise<any> {
// 模拟数据
const user = {
id: '12fDAA267CCFa9932c',
username: 'liu',
password: '1111',
};
// 模拟查询数据库,判断密码什么的是否正确
if (user && user.password === pass) {
const {
password, ...result } = user;
return result; // 然后返回除了密码的数据,给local.strategy.ts那边使用
}
return null;
}
public async login(user: any) {
// 登录,创建一个登录的token并返回
const {
username, id } = user;
const payload = {
username, id };
return {
// 调用内置的nestjs的jwt生成token的对象方法
token: 'Bearer ' + this.jwtService.sign(payload),
};
}
}
JwtService这个jwt内置服务,会提供生成token的对象方法,当然还需要在模块中配置一些对应的才能生效
4.创建一个路由控制器类,用于使用jwt安全认证,登录成功后生成token
// auth.controller.ts
import {
Controller, Request, Post, UseGuards, Get } from '@nestjs/common';
import {
AuthGuard } from '@nestjs/passport';
import {
AuthService } from './auth.service';
/**
* @UseGuards(AuthGuard('local'))我们使用的AuthGuard是@nestjs/passport自动设置
*/
@Controller('/auth')
export class AuthController {
// 前面也提到过的,注入服务,提供给整个路由控制器类使用
public constructor(private readonly authService: AuthService) {
}
/**
* 使用jwt安全认证,登录成功后生成token
*/
@UseGuards(AuthGuard('encry')) // encry 自定义的,默认是local,在local.strategy.ts文件中修改
@Post('/login')
public async login(@Request() req): Promise<{
access_token: string }> {
// 登录验证在authService里面的validateUser进行
return this.authService.login(req.user); // 发送登录请求,获取token
}
}
AuthGuard守卫,内置安全认证的守卫,通过传递的字符串来辨别是验证数据还是token解析
1.默认情况下local字符串是对数据进行一系列操作,执行local.strategy.ts方法的validate
2.而后面使用的jwt字符串就是解析token的操作,会在Authentication字段中提取出token并解析出之前生成token放入的数据
3.默认情况下的这字符串可以修改,例如local.strategy.ts的PassportStrategy方法的第二个参数,就是自定义的字符串,然后使用也就用相应的字符串
这时候访问http://localhost:3000/auth/login是没有用的,因为我们还没配置对应的模块
5.配置模块,用于注册控制器,服务,内置jwt加解密模块
// auth.module.ts
import {
Module } from '@nestjs/common';
import {
JwtModule } from '@nestjs/jwt';
import {
jwtConstants } from './constants';
import {
LocalStrategy } from './local.strategy';
import {
AuthService } from