getjerry / nest-casl

Casl integration for NestJS
MIT License
225 stars 29 forks source link

Allow global usage of `AccessGuard` with exempt routes #979

Open jreidgreer opened 1 month ago

jreidgreer commented 1 month ago

Problem

I prefer to automatically deny all requests unless they're explicitly allowed by permissions & access controls instead of using guards on a per-route basis like this:

@Module({
  imports: [
    CaslModule.forRoot({/* ... */}),
  ],
  controllers: [/* ... */],
  providers: [
    /* ... */
    {
      provide: APP_GUARD,
      useClass: AccessGuard,
    },
  ],
})
export class AppModule implements NestModule {}

I use a @Public() decorator to denote routes that that are explicitly intended for unauthenticated use, but the AccessGuard automatically denies them because of the user check: https://github.com/getjerry/nest-casl/blob/master/src/access.service.ts#L30-L32

Proposed Solution

There are probably a lot of ways to implement this. Here are a few suggestions:

1. Separate decorator to opt-out of the guard:

@Controller("public")
export class PublicDataController {

  @UseAbilityAllowAll()
  @Get("data")
  public async getPublicData() {}
}

2. Extend the interface of the UseAbility guard:

@Controller("public")
export class PublicDataController {

  @UseAbility({
    subject: PublicData,
    action: Actions.read,
    disableUserCheck: true,
  })
  @Get("data")
  public async getPublicData() {}
}

This could allow you to mix public and non-public access control for the same resources, and maintain a simpler external interface. However it would make contract with the Permissions more complicated as user could be undefined.