Разрешение за релси с Pundit

Pundit е скъпоценен камък на Ruby, който обработва оторизацията чрез много прост API.

Не забравяйте, че упълномощаването се различава от удостоверяването - удостоверяването е удостоверяване, че сте това, което казвате, че сте, а упълномощаването потвърждава, че имате разрешение да извършите действие.

Pundit е точно в рамките на разрешителния лагер - използвайте друга система за удостоверяване като Devise, за да обработвате удостоверяването.

Как работите с Pundit

Стъпка 1: Вие създавате Policyклас, който се занимава с разрешаване на достъп до определен тип запис - независимо дали това е Blogили Potatoили User.

Стъпка 2: Извиквате вградената authorizeфункция, предавайки това, до което се опитвате да разрешите достъп.

Стъпка 3: Pundit ще намери подходящия Policyклас и ще извика Policyметода, който съответства на името на метода, който упълномощавате. Ако се върне истина, имате разрешение да извършите действието. Ако не, ще изведе изключение.

Това е доста лесно. Логиката за конкретни модели е капсулирана в собствения си клас на политика, което е чудесно за поддържане на нещата. Конкуриращата се библиотека за оторизация cancan може да има проблеми със сложни разрешения, които излизат извън контрол.

Необходими са малки ощипвания

Простите конвенции на Pundit понякога трябва да бъдат променени, за да поддържат по-сложни случаи на използване на оторизация.

Достъп до повече информация от една Политика

По подразбиране Pundit предоставя два обекта на вашия контекст на оторизация: Userи Recordоторизираният. Това е достатъчно, ако имате общосистемни роли във вашата система като Adminили Moderator, но не е достатъчно, когато имате нужда от упълномощаване за по-специфичен контекст.

Да приемем, че сте имали система, която поддържа концепцията за Organizationи трябва да поддържате различни роли в тези организации. Упълномощаването за цялата система няма да го намали - не искате администраторът на Организационния картоф да може да прави неща с Организационния оранжев, освен ако не е администратор и на двете организации. При разрешаването на този случай, ще трябва достъп до 3 елемента: за Userтова Record, както и информация ролята на потребителя в Organization. Идеалният случай би бил да имаме достъп до организацията, към която принадлежи записът, но нека го направим по-труден и да кажем, че нямаме достъп до него чрез записа или потребителя.

Pundit предоставя възможност за предоставяне на допълнителен контекст. Чрез дефиниране на функция, която се нарича pundit_user, това ви позволява да промените това, което се счита за a user. Ако върнете обект с оторизационен контекст от тази функция, този контекст ще бъде достъпен за вашите политики.

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

Политиките ви вече ще имат достъп до трите вида информация - би трябвало да можете да видите как бихте получили достъп до повече информация, ако имате нужда от нея.

Заменете конвенцията и посочете коя политика да използвате

Pundit използва конвенциите за именуване, за да съчетае това, което се опитвате да упълномощите, с правилната политика. През повечето време това работи добре, но в някои случаи може да се наложи да замените тази конвенция, например когато искате да разрешите общо действие на таблото за управление, което няма свързан модел. Можете да предадете символи, за да посочите кое действие или политика да използвате за упълномощаване:

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

Ако имате модел, който е именуван по различен начин, можете също да замените policy_classфункцията в самия модел:

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

Тестване

Упълномощаването е едно от нещата, които силно препоръчвам да имате автоматизиран тестов пакет. Неправилното им настройване може да се окаже катастрофално и според мен това е едно от най-досадни неща за ръчно тестване. Да можеш да изпълниш една команда и да знаеш, че неволно не си променил каквито и да било бизнес правила за оторизация е страхотно усещане.

Pundit улеснява тестването много лесно.

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

Като цяло харесвам Pundit. Използвам го само за кратко, но вече го предпочитам пред cancancan - той просто се чувства по-поддържаем и проверяем.

Смятате ли, че тази история е полезна? Моля, пляскайте, за да покажете подкрепата си!

Ако не сте намерили това за полезно, моля да ме уведомите защо с коментар !