我想利用AuthGuard
装饰,以及护照JWT战略,documentation以下。
在文档中一切都很正常。但是我现在想保护与包含在JWT一个范围的路由。因此,这里是我的应用程序生成的基本JWT有效载荷:
{
"user": {
"id": "20189c4f-1183-4216-8b48-333ddb825de8",
"username": "[email protected]"
},
"scope": [
"manage_server"
],
"iat": 1534766258,
"exp": 1534771258,
"iss": "15f2463d-8810-44f9-a908-801872ded159",
"sub": "20189c4f-1183-4216-8b48-333ddb825de8",
"jti": "078047bc-fc1f-4c35-8abe-72834f7bcc44"
}
这里是由AuthGuard
装饰被把守的基本路线的保护:
@Get('protected')
@UseGuards(AuthGuard('jwt'))
async protected(): Promise<string> {
return 'Hello Protected World';
}
我想补充的选择和限制路线,以具有manager_server
范围到他们的智威汤逊的人访问。所以读完AuthGuard
码的一点点后,我认为我能写的东西,如:
@Get('protected')
@UseGuards(AuthGuard('jwt', {
scope: 'manage_server'
}))
async protected(): Promise<string> {
return 'Hello Protected World';
}
不过,我不能在文档中看到,我可以利用这个选项。
我认为增加一个选项参数的validate
的JWTStrategy
功能可以使的伎俩,但事实并非如此。这里是我的validate
功能(包含在jwt.strategy.ts
文件):
async validate(payload: JwtPayload, done: ((err: any, value: any) => void)) {
const user = await this.authService.validateUser(payload);
if (!user) {
return done(new UnauthorizedException(), false);
}
done(null, user);
}
非常感谢您的帮助,不要犹豫,问我要更多的信息的评论,如果你需要这样。
当你看AuthGuard的code,这似乎是options.callback
功能是唯一可能的定制。
我想,不是写自己AuthGuard
支持范围检查,它是清洁剂有ScopesGuard
(或RolesGuard
)有自己的decorater像@Scopes('manage_server')
代替。对于这一点,你可以遵循RolesGuard
,也只检查在请求中docs属性下的智威汤逊有效载荷的属性user
例子。
创建@Scopes()
装饰:
export const Scopes = (...scopes: string[]) => ReflectMetadata('scopes', scopes);
创建ScopesGuard
:
@Injectable()
export class ScopesGuard implements CanActivate {
constructor(private readonly reflector: Reflector) {}
canActivate(context: ExecutionContext): boolean {
const scopes = this.reflector.get<string[]>('scopes', context.getHandler());
if (!scopes) {
return true;
}
const request = context.switchToHttp().getRequest();
const user = request.user;
const hasScope = () => user.scopes.some((scope) => scopes.includes(scope));
return user && user.scopes && hasScope();
}
}
使用ScopesGuard作为所有路线的全局后卫(没有给出范围时返回true):
@Module({
providers: [
{
provide: APP_GUARD,
useClass: ScopesGuard,
},
],
})
export class ApplicationModule {}
然后用它在端点上:
@Get('protected')
@UseGuards(AuthGuard('jwt'))
@Scopes('manage_server')
async protected(): Promise<string> {
return 'Hello Protected World';
}
我尝试了稍微不同的方法,通过扩展AuthGuard后卫。我希望保持使用不同护照战略的能力,所以我包括一个mixin。给予反馈。
在您的智威汤逊的战略,你可以简单地返回JwtPaylozd使用户有一个作用域属性。然后自定义AuthGuard看起来是这样的:
import { UnauthorizedException, mixin } from "@nestjs/common";
import { AuthGuard } from "@nestjs/passport";
export function AuthScopes(scopes: string[], type?: string | string[]) {
return mixin(class ScopesAuth extends AuthGuard(type) {
protected readonly scopes = scopes;
handleRequest(err, user, info, context) {
if (err || !user) {
throw err || new UnauthorizedException();
}
if(!this.scopes.some(s => user.scopes.split(' ').includes(s)))
{
throw new UnauthorizedException(`JWT does not possess one of the required scopes (${this.scopes.join(',')})`);
}
return user;
}
});
}
然后,您可以使用此守护像这样:
@Get('protected')
@UseGuards(AuthScopes(['secret:read'], 'jwt'))
async protected(): Promise<string> {
return 'Hello Protected World';
}
“智威汤逊表示策略。