Autorización de rieles con Pundit

Pundit es una joya de Ruby que maneja la autorización a través de una API muy simple.

Recuerde que la autorización es diferente de la autenticación: la autenticación es verificar que usted es quien dice ser, y la autorización es verificar que tiene permiso para realizar una acción.

Pundit está directamente dentro del campo de la autorización: use otro sistema de autenticación como Devise para manejar la autenticación.

Cómo trabajas con Pundit

Paso 1: crea una Policyclase que se ocupa de autorizar el acceso a un tipo específico de registro, ya sea un Blogo Potatoo User.

Paso 2: Llamas a la función incorporada y authorizepasas a qué estás intentando autorizar el acceso.

Paso 3: Pundit encontrará la Policyclase adecuada y llamará al Policymétodo que coincida con el nombre del método que está autorizando. Si devuelve verdadero, tiene permiso para realizar la acción. Si no, lanzará una excepción.

Es bastante sencillo. La lógica para modelos específicos está encapsulada en su propia clase de política, lo que es excelente para mantener las cosas ordenadas. La biblioteca de autorizaciones de la competencia cancancan tenía problemas con permisos complicados que se salían de control.

Se requieren ajustes menores

Las convenciones simples de Pundit a veces deben modificarse para admitir casos de uso de autorización más complejos.

Acceda a más información desde dentro de una política

De forma predeterminada, Pundit proporciona dos objetos a su contexto de autorización: el Usery el que Recordestá siendo autorizado. Esto es suficiente si tiene roles en todo el sistema en su sistema como Admino Moderator, pero no es suficiente cuando necesita autorización para un contexto más específico.

Digamos que tenía un sistema que apoyaba el concepto de an Organization, y tenía que apoyar diferentes roles dentro de esas organizaciones. La autorización de todo el sistema no es suficiente: no desea que un administrador de Organization Potato pueda hacer cosas con Organization Orange a menos que sea un administrador de ambas organizaciones. Al autorizar este caso, necesitaría acceder a 3 elementos: el User, el Recordy la información del rol del usuario en Organization. El caso ideal sería tener acceso a la organización a la que pertenece el registro, pero hagámoslo más difícil y digamos que no tenemos acceso a eso a través del registro o el usuario.

Pundit brinda la oportunidad de proporcionar un contexto adicional. Al definir una función llamada pundit_user, esto le permite cambiar lo que se considera un user. Si devuelve un objeto con el contexto de autorización de esa función, ese contexto estará disponible para sus políticas.

application_controller.rb

class ApplicationController < ActionController::Base include Pundit
 def pundit_user AuthorizationContext.new(current_user, current_organization) endend

authorization_context.rb

class AuthorizationContext attr_reader :user, :organization
 def initialize(user, organization) @user = user @organization = organization endend

application_policy.rb

class ApplicationPolicy attr_reader :request_organization, :user, :record
 def initialize(authorization_context, record) @user = authorization_context.user @organization = authorization_context.organization @record = record end
 def index? # Your policy has access to @user, @organization, and @record. endend

Sus políticas ahora tendrían acceso a los tres tipos de información; debería poder ver cómo accedería a más información si la necesitara.

Anule la convención y especifique qué política usar

Pundit usa convenciones de nomenclatura para hacer coincidir lo que está tratando de autorizar con la política correcta. La mayoría de las veces esto funciona bien, pero en ciertos casos es posible que deba anular esta convención, como cuando desea autorizar una acción general del tablero que no tiene un modelo asociado. Puede pasar símbolos para especificar qué acción o política usar para la autorización:

#Below will call DashboardPolicy#bake_potato?authorize(:dashboard, :bake_potato?)

Si tiene un modelo con un nombre diferente, también puede anular la policy_classfunción dentro del propio modelo:

class DashboardForAdmins def self.policy_class DashboardPolicy # This forces Pundit to use Dashboard Policy instead of looking # for DashboardForAdminsPolicy endend

Pruebas

La autorización es una de esas cosas que recomiendo encarecidamente tener un conjunto de pruebas automatizado. Configurarlos incorrectamente puede ser catastrófico y, en mi opinión, es una de las cosas más tediosas de probar manualmente. Poder ejecutar un solo comando y saber que no ha cambiado inadvertidamente ninguna regla comercial de autorización es una gran sensación.

Pundit simplifica la autorización de las pruebas.

def test_user_cant_destroy? assert_raises Pundit::NotAuthorizedError do authorize @record, :destroy? endend
def test_user_can_show? authorize @record, :show?end

En general, me gusta Pundit. Solo lo he estado usando por un tiempo, pero ya lo prefiero a cancancan, simplemente se siente más fácil de mantener y verificable.

¿Te resultó útil esta historia? ¡ Aplauda para mostrar tu apoyo!

Si no le resultó útil, hágamelo saber por qué con un comentario .