1.1.1 • Published 2 years ago

@cjr-unb/autho v1.1.1

Weekly downloads
-
License
MIT
Repository
github
Last release
2 years ago

@cjr-unb/autho

Módulo para autorização em NestJS construído com CASL e integrado com o Prisma.

Instalação

É necessário ter Nest e o Prisma instalados com pelo menos uma migração executada. Em seguida, execute o comando:

npm install @cjr-unb/autho

Como usar

Definindo Regras

Defina as regras de autorização da sua aplicação numa função de callback do tipo Rules. Essa função recebe o tipo do usuário armazenado no token JWT e um objeto com as propriedades can, cannot e user.

import { Rules } from "@cjr-unb/autho";
import { JwtPayload } from "./auth/dtos/jwt-payload.dto";

export const rules: Rules<JwtPayload> = ({ can, cannot, user }) => {
  // Defina aqui as regras de autorização da sua aplicação. Exemplo:

  if (user.roles.includes("admin")) can("manage", "all");

  can("update", "post", { authorId: user.id });
};

Os nomes das possíveis actions são: manage, create, read, update e delete. Os nomes dos possíveis resources são: all e o nome das entidades do seu banco de dados. Você pode definir actions e resources customizados. Veja a seção Definindo Actions e Resources Customizados.

A definição das regras é feita como descrito na documentação do CASL.

AuthoModule

Adicione o AuthoModule utilizando o método forRoot em um dos módulos da sua aplicação. Os argumentos que o método recebe são:

  • \<JwtPayload>: Tipo do usuário armazenado no token JWT.
  • Options:
    • PrismaModule: Módulo do prisma que deve exportar o PrismaService
    • rules: Função de callback que contém as regras de autenticação. Recebe um objeto com as propriedades can, cannot e user.
    • userProperty?: Nome da propriedade que contém o usuário autenticado no objeto request. Default: user.
    • exceptionIfNotFound?: Tipo de exceção que deve ser lançada caso o recurso não seja encontrado no banco de dados. Os possíveis valores são: 404, 403 e prisma. Default: not found.
    • forbiddenMessage?: Função que recebe o nome da action e do resource que o usuário não tem permissão para acessar e retorna a mensagem que deve ser exibida na exceção. Caso não seja definida, a mensagem "Forbidden resource" será exibida. Default: undefined.
    • numberIdName?: Nome da propriedade que contém o id do recurso no Prisma. Deve ser utilizado quando o id do recurso é um número. Você deve escolher entre numberIdName e stringIdName. Default: id.
    • stringIdName?: Nome da propriedade que contém o id do recurso no Prisma. Deve ser utilizado quando o id do recurso é uma string. Você deve escolher entre numberIdName e stringIdName. Default: undefined.
import { AuthoModule } from "@cjr-unb/autho";
import { JwtPayload } from "./auth/dtos/jwt-payload.dto";
import { Module } from "@nestjs/common";
import { PrismaModule } from "./prisma/prisma.module";
import { rules } from "./auth/auth.rules";

@Module({
  imports: [
    AuthoModule.forRoot<JwtPayload>({
      PrismaModule,
      rules,
    }),
  ],
})
export class AppModule {}

Decorator Ability

Agora você pode utilizar o decorator @Ability em qualquer rota da sua aplicação. O decorator recebe a ação que o usuário está tentando executa, o nome do recurso que ele está tentando acessar e opções adicionais.

import { Ability } from "@cjr-unb/autho";
import { Controller, Get, UseGuards } from "@nestjs/common";
import { AuthGuard } from "@nestjs/passport";

@Controller("post")
export class PostsController {
  @Ability("read", "post")
  @UseGuards(AuthGuard("jwt")) // O guard de autenticação deve ser executado antes do guard de autorização
  @Get()
  findAll() {
    // ...
  }
}

Caso seja necessário consultar o banco de dados para verificar se o usuário tem permissão para acessar o recurso, você pode utilizar a opção useDb. O recurso será buscado através do id passado no parâmetro da rota.

O nome da propriedade que contém o id do recurso no é definido nas opções numberIdName ou stringIdName.

Se na sua rota, o nome da propriedade que contém o id do recurso no for diferente do definido na opção numberIdName ou stringIdName, você pode passar o nome correto na opção param.

Caso o recurso não seja encontrado, o Autho lançará uma exceção do tipo definido na opção exceptionIfNotFound.

import { Ability } from "@cjr-unb/autho";
import { Controller, Get, UseGuards } from "@nestjs/common";
import { AuthGuard } from "@nestjs/passport";

@Controller("post")
export class PostsController {
  @Ability("read", "post", { useDb: true, param: "postId" })
  @UseGuards(AuthGuard("jwt"))
  @Get(":postId")
  findOne() {
    // ...
  }
}

Agora quando um usuário que não tem permissão tentar acessar a rota, uma exceção do tipo ForbiddenException será lançada.

Definindo Actions e Resources Customizados

É possível definir seus próprios actions e resources customizados criando um tipo que contém as propriedades action e resource e passando esse tipo como parâmetro para a função rules, para o AuthoModule, para o decorator Ability e para a função forbiddenMessage caso ela seja definida.

Você pode extender as Actions e Resources padrões através dos tipos DefaultActions e DefaultResources.

import { DefaultActions, DefaultResources } from "@cjr-unb/autho";

export type CustomOptions = {
  actions: "operate" | DefaultActions;
  resources: "calculator" | DefaultResources;
};

Na função rules:

import { Rules } from "@cjr-unb/autho";
import { JwtPayload } from "./auth/dtos/jwt-payload.dto";
import { CustomOptions } from "./custom-options";

export const rules: Rules<JwtPayload, CustomOptions> = ({
  can,
  cannot,
  user,
}) => {
  if (user.roles.includes("admin")) can("operate", "calculator");
};

No AuthoModule:

import { AuthoModule } from "@cjr-unb/autho";
import { JwtPayload } from "./auth/dtos/jwt-payload.dto";
import { Module } from "@nestjs/common";
import { PrismaModule } from "./prisma/prisma.module";
import { rules } from "./auth/auth.rules";
import { CustomOptions } from "./custom-options";

@Module({
  imports: [
    AuthoModule.forRoot<JwtPayload, CustomOptions>({
      PrismaModule,
      rules,
    }),
  ],
})
export class AppModule {}

No decorator Ability:

import { Ability } from "@cjr-unb/autho";
import { Controller, Get, UseGuards } from "@nestjs/common";
import { AuthGuard } from "@nestjs/passport";
import { CustomOptions } from "./custom-options";

@Controller("calculator")
export class CalculatorController {
  @Ability<CustomOptions>("operate", "calculator")
  @UseGuards(AuthGuard("jwt"))
  @Get()
  operate() {
    // ...
  }
}

Limitações

Atualmente, para o funcionamento correto do Autho, é necessário que em todas as models do Prisma o nome da coluna que contém a PK sejam iguais.

Além disso, o Autho não tem suporte para definição de aliases para as actions.

1.1.1

2 years ago

1.1.0

2 years ago

1.0.3

2 years ago

1.0.2

2 years ago

1.0.1

2 years ago

1.0.0

2 years ago