Авторизація рейок з Pundit

Pundit - це самоцвіт Ruby, який обробляє авторизацію за допомогою дуже простого API.

Пам’ятайте, що авторизація відрізняється від автентифікації - автентифікація - це підтвердження того, що ви є тим, ким ви себе називаєте, а авторизація - підтвердження наявності у вас дозволу на виконання дії.

Pundit знаходиться прямо в таборі авторизації - використовуйте іншу систему автентифікації, наприклад Devise, для обробки автентифікації.

Як ви працюєте з Pundit

Крок 1: Ви створюєте Policyклас, який займається авторизацією доступу до записів певного типу - будь то Blogабо, Potatoабо User.

Крок 2: Ви викликаєте вбудовану authorizeфункцію, передаючи те, до чого намагаєтесь авторизувати доступ.

Крок 3: Pundit знайде відповідний Policyклас і викличе Policyметод, який відповідає імені методу, який ви авторизуєте. Якщо воно повертається істина, ви маєте дозвіл на виконання дії. Якщо ні, це викличе виняток.

Це досить просто. Логіка для конкретних моделей закладена у свій власний клас політики, який чудово підходить для того, щоб тримати речі в порядку. У конкуруючої бібліотеки авторизації cancancan виникли проблеми зі складними дозволами, які виходили з-під контролю.

Потрібні незначні налаштування

Прості конвенції Pundit іноді потрібно доопрацьовувати для підтримки більш складних випадків використання авторизації.

Отримуйте більше інформації в межах Поліси

За замовчуванням Pundit надає два об'єкти для вашого контексту авторизації: Userі Recordавторизований. Цього достатньо, якщо у вас є загальносистемні ролі у вашій системі, наприклад, Adminабо Moderator, але цього недостатньо, коли вам потрібен дозвіл на більш конкретний контекст.

Скажімо, у вас була система, яка підтримувала концепцію Organization, і ви повинні були підтримувати різні ролі в цих організаціях. Загальносистемна авторизація цього не зменшить - ви не хочете, щоб адміністратор організації Potato міг робити щось із організацією Orange, якщо він не є адміністратором обох організацій. При видачі дозволу на цей випадок, вам буде потрібно доступ до 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 - він просто відчуває себе більш ремонтопридатним і перевіряється.

Чи знайшла ця історія корисну? Будь ласка, плескайте, щоб показати свою підтримку!

Якщо ви не вважаєте це корисним, повідомте мені, чому, коментарем !