שלושה יתרונות של ניהול הרשאות מבוסס Policy
ניהול הרשאות במערכת זה המנגנון שמאפשר לנו מרגע שמשתמש התחבר להבין מה מותר לאותו משתמש לעשות. באנגלית זה נקרא Authorization ובדרך כלל אנחנו מפרידים את מנגנון ניהול ההרשאות ממנגנון ההזדהות (Authentication). ההזדהות מאפשרת לי להגיד שמי שנכנס הרגע הוא משתמש X וניהול ההרשאות זה מה שמאפשר לי להגיד שלמשתמש X מותר להיכנס לדף מסוים.
במנגנון ניהול ההרשאות אנחנו מוצאים שתי גישות מרכזיות (עם ספריות קוד תואמות). הגישה הראשונה היא ניהול הרשאות מבוסס משתמש. פה יש לנו ב Rails את cancancan וב JavaScript/Typescript את casl. בגישה זאת אנחנו מתחילים את התוכנית בלקחת אוביקט משתמש ו"להדביק" לו הרשאות:
import { defineAbility } from '@casl/ability';
export default (user) => defineAbility((can) => {
can('read', 'Article');
if (user.isLoggedIn) {
can('update', 'Article', { authorId: user.id });
can('create', 'Comment');
can('update', 'Comment', { authorId: user.id });
}
});
הרבה פעמים אני מחלק את קטע הקוד הזה לפונקציות ותהיה לי פונקציה אחת שמטפלת במשתמש מסוג "גולש רגיל" פונקציה אחרת ל"גולש מחובר" פונקציה שלישית ל"מנוי" ורביעית ל"מנהל האתר". בכל פונקציה אני מדביק למשתמש את ההרשאות המתאימות.
פה באתר למשל אני משתמש בספריה כזאת בקוד ריילס ויש לי הרשאות כמו:
def guest_user(user)
can :read, BlogPost do |post|
post.published_at <= Time.now
end
can :read, Lesson, free: true
end
גישה כזאת עובדת מאוד טוב בתחילת הפרויקט או בפרויקטים קטנים, כל עוד כל ההרשאות נכנסות בקובץ אחד.
גישה שנייה לניהול הרשאות היא ניהול מבוסס מדיניות. בגישה זו אני מגדיר Policy לגישה ל"דבר" מסוים ובתוך המדיניות אני מגדיר מי רשאי לעשות מה עם אותו דבר. זאת הגישה שאנחנו פוגשים בספריות ריילס כמו pundit ו action_policy
, פאנדיט גם זמינה ב JavaScript. הנה קטע מתוך התיעוד של action_policy
כדי שנראה את ההבדל:
class PostPolicy < ApplicationPolicy
# everyone can see any post
def show?
true
end
def update?
# `user` is a performing subject,
# `record` is a target object (post we want to update)
user.admin? || (user.id == record.user_id)
end
end
או ב JavaScript מתוך התיעוד של pundit:
import { Policy } from 'pundit'
export default class PostPolicy extends Policy {
constructor(user, record) {
super(user, record)
this.setup.apply(this)
}
edit() {
return this.user.id === this.record.userId
}
destroy() {
return this.user.isAdmin
}
}
שלושה יתרונות מהירים של מדיניות הרשאות מבוססת מודלים הם:
כל ההרשאות של מודל מסוים מרוכזות במקום אחד.
אפשר לשתף Policy בין כמה מודלים.
ניהול שינויים - אם אני רוצה לקבוע ממחר שתוכן מסוג מסוים כבר לא חופשי בגישה הראשונה אני צריך לשנות בשני מקומות (גם בפונקציה שמגדירה הרשאות לאורחים וגם בפונקציה שמגדירה הרשאות למשתמשים רשומים). בגישה השנייה מספיק לעדכן את פונקציית הצפייה ב Policy שמתאים לדבר אותו אני מזיז.