import { Injectable, CanActivate, ExecutionContext, ForbiddenException, Inject, } from '@nestjs/common'; import { ClientProxy } from '@nestjs/microservices'; import { firstValueFrom } from 'rxjs'; import { Request } from 'express'; @Injectable() export class AuthGuard implements CanActivate { constructor(@Inject('Client') private readonly client: ClientProxy) {} async canActivate(context: ExecutionContext): Promise { const request: Request = context.switchToHttp().getRequest(); // 登录接口 if ('/dmp/auth/signIn' === request.url) { const { username } = request.body; const { allow } = await this.rolePermissionAllow( { username }, request.url, ); if (!allow) throw new ForbiddenException('无权限访问'); return true; } // 获取token的配置 const { tokenKeyInCookie, tokenResignIn, expires } = await firstValueFrom( this.client.send('cert.token.config', []), ); const tokenCipher = request.cookies[tokenKeyInCookie]; if (!tokenCipher) throw new ForbiddenException('您没有执行此操作的权限'); // 1.验证token是否合法 const { tokenValid, payload } = await firstValueFrom( this.client.send('cert.token.decode', tokenCipher), ); if (!tokenValid) throw new ForbiddenException('您没有执行此操作的权限'); // 2.token续签 const { exp } = payload; const tokenExpiredSoon = tokenResignIn * 1000 > exp * 1000 - Date.now(); if (tokenExpiredSoon) { const { username } = payload; const { token: newToken } = await firstValueFrom( this.client.send('cert.token.create', { username }), ); request.res.cookie(tokenKeyInCookie, newToken, { maxAge: expires * 1000, httpOnly: true, }); } // 3.验证角色授权 const { allow } = await this.rolePermissionAllow(payload, request.url); if (!allow) throw new ForbiddenException('无权限访问'); return true; } /** * 用户是否有权限 */ async rolePermissionAllow(payload: { username: string }, requestUrl: string) { const { allow } = await firstValueFrom( this.client.send('cert.role.authorize', { user: payload, url: requestUrl, }), ); return { allow }; } }