Rails权限验证工具Pundit

    xiaoxiao2025-09-02  181

    在人们开始使用Rails 4之后, cancan的复杂以及兼容性修复不及时而遭人诟病,大家将目光投向了新的工具 Pundit

    Pundit是一个纯ruby的gem,用于权限验证。

    基本思路

    Pundit针对当前模型对象,以及操作,会去相应的模型的policy中寻找操作验证的方法,继而实现验证。

    也就是说,只要是任何一个class,需要对他的实例进行验证,只要将验证规则写在对应的policy中即可。

    安装及初始化

    # Gemfile gem `pundit`

    $ bundle install

    rails g pundit:install 生成默认的policy文件,路径为app/policies/application_policy.rb。

    在ApplicationController里添加:

    class ApplicationController < ActionController::Base # ... include Pundit # ... end

    添加验证

    如果要针对Article模型的实例,进行权限验证,则继续执行:

    rails generate pundit:policy article => 生成 app/policies/article_policy.rb。

    # app/policies/article_policy.rb class ArticlePolicy < ApplicationPolicy class Scope < Struct.new(:user, :scope) def resolve scope end end end

    假设在articles_controller里有这么一段:

    def update @article = Article.find(params[:id]) # 我们要在这里验证 current_user对这个@atilce是否有权限 @article.update_atttributes(article_arrtibutes) end

    我们在ArticlePolicy添加一个方法,来验证用户是否有这个权限。方法的命名习惯于以问好结尾。

    # app/policies/article_policy.rb class ArticlePolicy < ApplicationPolicy class Scope < Struct.new(:user, :scope) def resolve scope end end def update? record.creator_id == user.id end end

    这其中 uesr和 record来自于ApplicationPolicy。

    class ApplicationPolicy attr_reader :user, :record def initialize(user, record) @user = user @record = record end end

    然后在ArticlesContoller里加入验证:

    def update @article = Article.find(params[:id]) authorize @article, :update? @article.update_atttributes(article_arrtibutes) end

    由于action_name和验证方法的名字相同,所以可以简单写成:

    def update @article = Article.find(params[:id]) authorize @article @article.update_atttributes(article_arrtibutes) end

    这时,我们已经有了权限验证,当用户不具备权限的时候rails会抛出错误;不过我们要做的还没有结束,我们需要捕获这个错误并进行相关处理。

    我们的application_controller应该变成这样:

    class ApplicationController < ActionController::Base # ... include Pundit rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized private def user_not_authorized redirect_to root_url, :alert => "You don't have permission to those resources." end end

    这样就可以在用户不具备权限时,跳转至root_url并给出相应提示了。

    测试

    参考这里: Testing Pundit Policies with RSpec

    接下来我们对刚才的操作进行测试,以rspec为例:

    首先,在spec_helper加入:

    require 'pundit/rspec'

    然后,生成测试文件,置于spec/policies/article_policy_spec.rb

    require 'spec_helper' describe ArticlePolicy do subject { ArticlePolicy.new(user, article) } let(:article) { create :article } context 'for a guest' do let(:user) { nil } it { should_not allow(:update) } end context 'for the write ' do let(:user) { article.creator } it { should allow(:index) } end context 'for an other writer' do let(:user) { create :user } it { should_not allow(:update) } end end

    注意:这里的allow方法并非Pundit提供,而是我们自定义的matcher:

    # spec/support/pundit_matcher.rb RSpec::Matchers.define :allow do |action| match do |policy| policy.public_send("#{action}?") end failure_message_for_should do |policy| "#{policy.class} does not permit #{action} on #{policy.record} for #{policy.user.inspect}." end failure_message_for_should_not do |policy| "#{policy.class} does not forbid #{action} on #{policy.record} for #{policy.user.inspect}." end end

    Tags:

    Posted on: 2014-07-16

    转载请注明原文地址: https://ju.6miu.com/read-1302226.html
    最新回复(0)