aurora-article
aurora-article copied to clipboard
nestjs 用户授权
使用 nestjs 完成用户注册、登录和授权的步骤流程,包括使用 bcrypt 密码加密,jwt加密生成 token,以及如何验证 token 使用中间件。
完成注册接口
在注册时使用bcrypt对密码进行加密。
private saltRounds = 10;
private myHash = (password: string): Promise<string> => {
return new Promise((resolve) => {
bcrypt.hash(password, this.saltRounds, function (err, hash) {
if (!err) resolve(hash);
});
});
};
async create(createUserDto: CreateUserDto) {
//防止用户名重复
const user = await this.userModel.findOne({
username: createUserDto.username,
});
if (user) {
return {
statusCode: 403,
message: '用户名已存在',
};
}
const hash = (await this.myHash(createUserDto.password)) as string;
createUserDto.password = hash;
return this.userModel.create(createUserDto);
}
完成登录接口
登录先查询用户名是否存在,然后bcrypt对比密码,密码正确之后使用jsonwebtoken生成登录token,token中存入用户的id即可。
其中 privateKey 单独保存到一个文件里。
前端登录后需要把token存到local中,需要用户授权时需要token中的id。
private myCompare = (password: string, hash: string): Promise<boolean> => {
return new Promise((resolve) => {
bcrypt.compare(password, hash, function (err, result) {
if (!err) resolve(result);
});
});
};
async login(loginUserDto: LoginUserDto) {
const user = await this.userModel.findOne({
username: loginUserDto.username,
});
if (!user) {
return {
statusCode: 403,
message: '用户名不存在',
};
}
//查看密码正确
const passwordIsTrue = await this.myCompare(
loginUserDto.password,
user.password,
);
if (!passwordIsTrue) {
return {
statsuCode: 403,
message: '密码输入错误',
};
}
//生成token
const token = 'Bearer ' + jwt.sign({ id: user._id }, privateKey);
return {
statusCode: 200,
message: {
user,
token,
},
};
}
验证 token
需要用户授权的接口都需要验证token,将授权部分写成中间件。
@Injectable()
export class AuthMiddleware implements NestMiddleware {
constructor(@InjectModel('User') private userModel: Model<UserDocument>) {}
private jwtVerify = (authorization: string) => {
return new Promise((resolve) => {
jwt.verify(authorization, privateKey, (err, res) => {
if (!err) resolve(res);
else resolve(null);
});
});
};
async use(req: any, res: any, next: () => void) {
const authorization = req.headers?.authorization;
if (!authorization) {
throw new HttpException(
'未传入authorization字段的headers',
HttpStatus.FORBIDDEN,
);
}
const tokenInfo: any = await this.jwtVerify(authorization.split(' ').pop());
if (!tokenInfo?.id) {
throw new HttpException('token未授权', HttpStatus.FORBIDDEN);
}
const user = await this.userModel.findOne({ _id: tokenInfo.id });
if (!user) {
throw new HttpException('未授权的用户', HttpStatus.FORBIDDEN);
}
req.user = user;
next();
}
}