所以我决定尝试权威的用户授权解决方案.我想知道如何policy
在视图中使用帮助器,实例变量可能是nil,如下面的简单情况:
应用程序/视图/项目/ index.html.slim
h1 Projects
(...)
- if policy(@project).create?
= link_to 'New Project', new_project_path
Run Code Online (Sandbox Code Playgroud)
应用程序/控制器/ projects_controller.rb
(...)
def index
@projects = Project.all
end
(...)
Run Code Online (Sandbox Code Playgroud)
应用程序/政策/ project_policy.rb
class ProjectPolicy < Struct.new(:user, :project)
def create?
user.has_role? :admin
end
Run Code Online (Sandbox Code Playgroud)
我想在Projects #index页面上显示一个"New Project"链接,但是我在这个视图中没有@project实例变量,但是收到错误:
Pundit :: Projects#index中的NotDefinedError
无法找到策略NilClassPolicy
错误显然是因为我传递了@project
nil的实例变量,因此有一个NilClass,显然我没有必要授权.
我找到了2个解决这个问题的方法,使它运行正常,但它们似乎都不合适:
policy(@projects[0])
@project = Project.new
(或直接在视图类似于上文:policy(Project.new)
)第一个解决方案将导致@projects数组中的相同错误为空,而第二个解决方案将创建冗余实例变量.所有策略帮助程序需要知道的是我希望在哪个类上强制执行授权逻辑.
有关正确实现方法的任何建议吗?
我使用RailsApps rails-composer创建了rails- devise-pundit starter应用程序.我仍然对铁轨上的红宝石有点新意,而且更新设计,专家和导轨4.
我正在查看代码以了解它是如何工作的.控制器和策略类中有很多地方user.admin?叫做.但我找不到管理员?方法.我希望它在用户模型中,但它不存在.这是用户类:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable, :confirmable,
:recoverable, :rememberable, :trackable, :validatable
enum role: [:user, :vip, :admin]
after_initialize :set_default_role, :if => :new_record?
def set_default_role
self.role ||= :user
end
end
Run Code Online (Sandbox Code Playgroud)
在users_controller.rb的一部分中使用:
def show
@user = User.find(params[:id])
unless current_user.admin?
unless @user == current_user
redirect_to root_path, :alert => "Access denied."
end
end
end
Run Code Online (Sandbox Code Playgroud)
权威或设计是否会以某种方式创建此方法?我已经看到它在专家文档中使用,但它只是以它为例.它没有说明需要创建方法或者它处理它.它是否以某种方式使用角色枚举,其中:admin作为可能的值?如果有人能解释这是如何工作的,我会很感激.
我打算尽快添加使用rolify gem来处理角色,而不是用户类中的角色枚举.也许我会因为某些原因想要制作完全不同的角色名称.我想确保我理解如何保持一切正常.谢谢.
当不允许用户通过权威人员查看具有授权规则的页面时,我收到以下错误:
在此操作中多次调用渲染和/或重定向.请注意,您只能调用渲染或重定向,每次操作最多一次.另请注意,重定向和呈现都不会终止操作的执行,因此如果要在重定向后退出操作,则需要执行类似"redirect_to(...)并返回"的操作.
这是application_controller.rb:
class ApplicationController < ActionController::Base
# Includes Authorization mechanism
include Pundit
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
# Globally rescue Authorization Errors in controller.
# Returning 403 Forbidden if permission is denied
rescue_from Pundit::NotAuthorizedError, with: :permission_denied
# Enforces access right checks for individuals resources
# after_filter :verify_authorized, :except => :index
# Enforces access right checks for collections
# after_filter :verify_policy_scoped, :only …
Run Code Online (Sandbox Code Playgroud) 我在我的封闭系统Ruby on Rails应用程序上使用Pundit gem进行授权(使用Rails 4.1.5和Rspec 3.0)
我已经将我的应用程序策略配置为在未按照Pundit文档中的建议定义用户时引发异常:
class ApplicationPolicy
attr_reader :user, :record
def initialize(user, record)
raise Pundit::NotAuthorizedError, "must be logged in" unless user
@user = user
@record = record
end
end
Run Code Online (Sandbox Code Playgroud)
如何编写一个规范来验证每个Pundit策略是否拒绝零用户?
我做了以下尝试:
RSpec.describe PostPolicy do
it "should raise an exception when users aren't logged in" do
expect(AccountFolderPolicy.new(nil, record)).to raise_error(Pundit::NotAuthorizedError)
end
end
Run Code Online (Sandbox Code Playgroud)
但它出错了
Failure/Error: expect(PostPolicy.new(nil, record)).to raise_error(Pundit::NotAuthorizedError)
Pundit::NotAuthorizedError:
must be logged in
Run Code Online (Sandbox Code Playgroud)
关于如何正确测试这个的任何建议?
我正在我的 Rails 应用程序中运行 Pundit 进行授权。我似乎已经掌握了这一切,但想知道如何将编辑或更新操作限制到某个字段。
例如,用户可以编辑他们的 user.first_name、user.mobile 或 user.birthday 等,但不能编辑他们的 user.role。基本上我的逻辑是,让用户编辑任何装饰性的东西,但不是功能性的。
这些字段应该只能由具有“super_admin”角色的用户进行编辑(我在 user.rb 上使用如下方法进行了设置)。
def super_admin?
role == "super admin"
end
def account?
role == "account"
end
def segment?
role == "segment"
end
def sales?
role == "sale"
end
def regional?
role == "regional"
end
def national?
role == "national"
end
def global?
role == "global"
end
Run Code Online (Sandbox Code Playgroud)
我几乎有一个干净的石板user_policy.rb
文件,其中更新和编辑操作是默认的
def update?
false
end
def edit?
update?
end
Run Code Online (Sandbox Code Playgroud)
也许我对此的想法完全错误,应该只包装一个 user.super_admin?用户显示页面上的角色字段周围的 if 语句,但如果我只是为了安全而使用该策略,这感觉是错误的。
控制器:
class UsersController < ApplicationController
def index
...
authorize User
end
...
Run Code Online (Sandbox Code Playgroud)
政策:
class UserPolicy < ApplicationPolicy
def index
@user.admin?
end
end
Run Code Online (Sandbox Code Playgroud)
考试:
class UsersControllerAuthorizationTest < ActionController::TestCase
tests :users
def user
@user ||= create(:user)
end
test 'should not authorize ordinary users to access the page' do
sign_in user
get :index
assert_response :error
end
end
Run Code Online (Sandbox Code Playgroud)
该应用程序Pundit::NotAuthorizedError (not allowed to index? this User)
按预期失败.但测试说:
Pundit::NotDefinedError: unable to find policy UserPolicy for User
Run Code Online (Sandbox Code Playgroud)
我做错了吗?我可以让它找到政策吗?
UPD必须与rails
'自动加载'有关.调用constantize
上'UserPolicy'
使得它自动加载 …
使用Rails 4.2.4与Devise(3.5.2)和Pundit(1.0.1).Decent_exposure(2.3.2).
我有一个简单的嵌套关联用户和想法:
class User < ActiveRecord::Base
has_many :ideas
...
class Idea < ActiveRecord::Base
belongs_to :user
...
Run Code Online (Sandbox Code Playgroud)
在routes.rb中
devise_for :users
resources :users do
resources :ideas
end
Run Code Online (Sandbox Code Playgroud)
然后我只是试图禁止访问users/1/ideas如果current_user不是Ideas的所有者(在本例中,如果current_user.id!= 1).我无法弄清楚该怎么做.我能够在Index视图中只显示current_user Ideas:
[创意控制器]
def show
authorize idea
end
Run Code Online (Sandbox Code Playgroud)
[思想政策]
def show?
@current_user == @idea.user
end
Run Code Online (Sandbox Code Playgroud)
但是,如何阻止用户只是导航到其他用户的Idea索引页面?我想在Ideas控制器中我应该使用类似的东西:
def index
authorize user
end
Run Code Online (Sandbox Code Playgroud)
但那又怎样?如何向用户政策发送有关Idea集合的信息?或者我应该通过创意政策本身进行授权?
我有一个非常简单的 Pundit 策略,适用于不同的用户角色。我不知道如何在 Rspec 中测试它。具体来说,我不知道如何在访问范围之前告诉范围哪些用户登录。
这是我尝试过的:
let(:records) { policy_scope(Report) }
context 'admin user' do
before(:each) { sign_in(admin_user) }
it { expect(reports.to_a).to match_array([account1_report, account2_report]) }
end
context 'client user' do
before(:each) { sign_in(account2_user) }
it { expect(reports.to_a).to match_array([account2_report]) }
end
Run Code Online (Sandbox Code Playgroud)
当我运行 Rspec 时,我得到:
NoMethodError: undefined method `sign_in' for #<RSpec::ExampleGroups::ReportPolicy::Scope:0x00007f93241c67b8>
Run Code Online (Sandbox Code Playgroud)
我sign_in
在控制器测试中广泛使用,但我想这不适用于策略测试。
Pundit 文档只说:
Pundit 不提供用于测试范围的 DSL。只需像常规 Ruby 类一样对其进行测试即可!
那么...是否有人有针对特定用户测试 Pundit 范围的示例?我如何告诉范围 current_user 是什么?
FWIW,这是我政策的精髓:
class ReportPolicy < ApplicationPolicy
def index?
true
end
class Scope < Scope
def resolve
if user.role …
Run Code Online (Sandbox Code Playgroud) 我有一个客户端模型,其中有_many 联系人
用户是否可以创建、更新或编辑取决于客户端而不是联系人,而销毁取决于联系人本身。
在 ContactPolicy 类中,我可以简单地检查 @contact.client 以查看用户是否可以访问,这很好。
但是,对于 List 方法,我没有一个联系人,而是一个 @client.contacts 列表,因此没有简单的方法可以告诉 Pundit 允许什么。
我不确定 Pundit 应该如何处理这个问题。
请注意,我不想要范围,因为它是是或否取决于客户记录