Issue
I have a controller with a route that I want to protect with Guards. I have these three gards: IsAuthentifiedGuard, HasRoleGuard and IsSafeGuard and I want at least one of these two conditions to be valid:
- IsAuthentifiedGuard and HasRoleGuard are OK
- IsSafeGuard is OK
For example, if the user is authentified AND has an enough role, it should be OK but if not but the call is "safe" I also want it to be OK.
My OrGuard:
@Injectable()
export class OrGuard implements CanActivate {
constructor(private readonly orGuards: CanActivate[][]) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const orGuardsPromises = await Promise.all(
this.orGuards.map(async andGuards => {
const andGuardPromises = await Promise.all(
andGuards.map(async guard => {
return guard.canActivate(context)
}),
)
return andGuardPromises.every(canActivate => canActivate === true)
}),
)
return orGuardsPromises.some(canActivate => canActivate === true)
}
}
And my controller:
@Controller('my_route')
export class MyController {
@Post('/')
@UseGuards(new OrGuard([[new IsAuthentifiedGuard(), new HasRoleGuard()], [new IsSafeGuard()]]))
async myRoute() {}
}
But I've a problem with the guards that require dependencies. For example if HasRoleGuard requires a ConfigService in constructor, this doesn't work.
An other way would be to use my or guard as following:
@UseGuards(OrGuard)
@SetMetadata('orGuards', [[IsAuthentifiedGuard, HasRoleGuard], [IsSafeGuard]])
But in my guard, I don't succeed to instanciate these guards from their class name with all the dependencies they need.
What can you suggest?
Solution
What you're looking to do is possible with @nest-lab/or-guard
. You'll need to register your guards as providers (just adding them to the providers array is fine) and you'll want to create a custom provider for the AndGuard
so that it can later be referenced by the OrGuard
. Something like this should do for you:
@Module({
providers: [
IsAuthentifiedGuard,
HasRoleGuard,
IsSafeGuard,
{
provide: 'AndGuard',
useClass: AndGuard([IsAuthenticatedGuard, HasRoleGuard]),
},
...
]
})
And then you can use @UseGuards(OrGuard(['AndGuard', IsSafeGuard]))
and it should work just fine. You can view the tests for some more inspiration on how it works if you'd like
Answered By - Jay McDoniel
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.