1.加密工具函数
import * as crypto from 'crypto';
/**
* Make salt
*/
export function makeSalt(): string {
return crypto.randomBytes(3).toString('base64');
}
/**
* Encrypt password
* @param password 密码
* @param salt 密码盐
*/
export function encryptPassword(password: string, salt: string): string {
if (!password || !salt) {
return '';
}
const tempSalt = Buffer.from(salt, 'base64');
return (
// 10000 代表迭代次数 16代表长度
crypto.pbkdf2Sync(password, tempSalt, 10000, 16, 'sha1').toString('base64')
);
}
2.查询用户信息
// src/logical/user/user.service.ts
import { Injectable } from '@nestjs/common';
import * as Sequelize from 'sequelize'; // 引入 Sequelize 库
import sequelize from '../../database/sequelize'; // 引入 Sequelize 实例
@Injectable()
export class UserService {
/**
* 查询是否有该用户
* @param username 用户名
*/
async findOne(username: string): Promise<any | undefined> {
const sql = `
SELECT
user_id userId, account_name username, real_name realName, passwd
password,
passwd_salt salt, mobile, role
FROM
admin_user
WHERE
account_name = '${username}'
`; // 一段平淡无奇的 SQL 查询语句
try {
const user = (
await sequelize.query(sql, {
type: Sequelize.QueryTypes.SELECT, // 查询方式
raw: true, // 是否使用数组组装的方式展示结果
logging: true, // 是否将 SQL 语句打印到控制台
})
)[0];
// 若查不到用户,则 user === undefined
return user;
} catch (error) {
console.error(error);
return void 0;
}
}
3.注册用户
import { Injectable } from '@nestjs/common';
import * as Sequelize from 'sequelize'; // 引入 Sequelize 库
import sequelize from '../../database/sequelize'; // 引入 Sequelize 实例
import { makeSalt, encryptPassword } from '../../utils/cryptogram'; // 引入加密函数
@Injectable()
export class UserService {
/**
* 查询是否有该用户
* @param username 用户名
*/
async findOne(username: string): Promise<any | undefined> {}
/**
* 注册
* @param requestBody 请求体
*/
async register(requestBody: any): Promise<any> {
const { accountName, realName, password, repassword, mobile } = requestBody;
if (password !== repassword) {
return {
code: 400,
msg: '两次密码输入不一致',
};
}
const user = await this.findOne(accountName);
if (user) {
return {
code: 400,
msg: '用户已存在',
};
}
const salt = makeSalt(); // 制作密码盐
const hashPwd = encryptPassword(password, salt); // 加密密码
const registerSQL = `
INSERT INTO admin_user
(account_name, real_name, passwd, passwd_salt, mobile, user_status,
role, create_by)
VALUES
('${accountName}', '${realName}', '${hashPwd}', '${salt}', '${mobile}',
1, 3, 0)
`;
try {
await sequelize.query(registerSQL, { logging: false });
return {
code: 200,
msg: 'Success',
};
} catch (error) {
return {
code: 503,
msg: `Service error: ${error}`,
};
}
}
}
4.路由访问
// src/logical/user/user.controller.ts
import { Controller, Post, Body } from '@nestjs/common';
import { UserService } from './user.service';
@Controller('user')
export class UserController {
constructor(private readonly usersService: UserService) { }
// @Post('find-one')
// findOne(@Body() body: any) {
// return this.usersService.findOne(body.username);
// }
@Post('register')
async register(@Body() body: any) {
return await this.usersService.register(body);
}
}
5.安装jwt,jwt登录使用
yarn add passport passport-jwt passport-local @nestjs/passport @nestjs/jwt -S
nest g service auth logical
nest g module auth logical
// src/logical/auth/constats.ts
export const jwtConstants = {
secret: 'shinobi7414', // 秘钥
};
// src/logical/auth/jwt.strategy.ts
import { ExtractJwt, Strategy } from 'passport-jwt';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable } from '@nestjs/common';
import { jwtConstants } from './constants';
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor() {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: jwtConstants.secret,
});
}
// JWT验证 - Step 4: 被守卫调用
async validate(payload: any) {
console.log(`JWT验证 - Step 4: 被守卫调用`);
return {
userId: payload.sub,
username: payload.username,
realName: payload.realName,
role: payload.role,
};
}
}
// src/logical/auth/auth.service.ts
import { Injectable } from '@nestjs/common';
import { UserService } from '../user/user.service';
import { JwtService } from '@nestjs/jwt';
import { encryptPassword } from '../../utils/cryptogram';
@Injectable()
export class AuthService {
constructor(
private readonly usersService: UserService,
private readonly jwtService: JwtService,
) { }
// JWT验证 - Step 2: 校验用户信息
async validateUser(username: string, password: string): Promise<any> {
console.log('JWT验证 - Step 2: 校验用户信息');
const user = await this.usersService.findOne(username);
if (user) {
const hashedPassword = user.password;
const salt = user.salt;
// 通过密码盐,加密传参,再与数据库里的比较,判断是否相等
const hashPassword = encryptPassword(password, salt);
if (hashedPassword === hashPassword) {
// 密码正确
return {
code: 1,
user,
};
} else {
// 密码错误
return {
code: 2,
user: null,
};
}
}
// 查无此人
return {
code: 3,
user: null,
};
}
async certificate(user: any) {
const payload = {
username: user.username,
sub: user.userId,
realName: user.realName,
role: user.role,
};
console.log('JWT验证 - Step 3: 处理 jwt 签证');
try {
const token = this.jwtService.sign(payload);
return {
code: 200,
data: {
token,
},
msg: `登录成功`,
};
} catch (error) {
return {
code: 600,
msg: `账号或密码错误`,
};
}
}
}
// src/logical/auth/local.strategy.ts
import { Strategy } from 'passport-local';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { AuthService } from './auth.service';
@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
constructor(private readonly authService: AuthService) {
super();
}
async validate(username: string, password: string): Promise<any> {
const user = await this.authService.validateUser(username, password);
if (!user) {
throw new UnauthorizedException();
}
return user;
}
}
// src/logical/auth/auth.module.ts
import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { LocalStrategy } from './local.strategy';
import { JwtStrategy } from './jwt.strategy';
import { UserModule } from '../user/user.module';
import { PassportModule } from '@nestjs/passport';
import { JwtModule } from '@nestjs/jwt';
import { jwtConstants } from './constants';
@Module({
imports: [
PassportModule.register({ defaultStrategy: 'jwt' }),
JwtModule.register({
secret: jwtConstants.secret,
signOptions: { expiresIn: '8h' }, // token 过期时效
}),
UserModule,
],
providers: [AuthService, LocalStrategy, JwtStrategy],
exports: [AuthService],
})
export class AuthModule { }
// src/app.module.ts