【问题标题】:Rails authorization architecture using before_action使用 before_action 的 Rails 授权架构
【发布时间】:2014-09-21 10:00:06
【问题描述】:

我是 Ruby 和 Rails 的新手,所以我正在尝试做一些在其他语言上可能很容易但在 Rails 中无法处理的事情:

我在数据库中设计了几个表来匹配每个控制器和动作名称。这样,如果我想为用户管理特殊权限,我只需将正确的操作添加到数据库中的正确控制器,并使用方法check_permissions,我知道用户是否可以执行操作或被重定向到标准的“禁止”页面。

例如,这是我为用户 CRUD 编写的代码:

首先我在应用程序控制器中创建了一个check_permissions 方法,它获取当前操作、用户和控制器,并检查数据库的授权权限:

class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception

  include SessionsHelper

  def self.check_permissions 
    remember_token = User.digest(cookies[:remember_token]) # encripto el token para poder buscarlo en la DB, ya que ahi se guarda encriptado.
    @current_user ||= User.find_by(remember_token: remember_token)

    redirect_to signin_path if (@current_user == nil) or (User.find_by_sql("select * from view_userpermissions where user_id = #{@current_user.id} and pagecontroller='#{self.controller_name}' and accion='#{self.action}' ").count < 1)
  end
  ...
  ...

然后在每个控制器中,我使用before_action :check_permissions 过滤器来重定向用户,以防无权访问所需的内容:

class UsersController < ApplicationController
  before_action :set_user, only: [:show, :edit, :update, :destroy]
  before_action self.comprobar_permisos 

  def index
    @users = User.paginate(page: params[:page])
  end
  ...
  ...

代码流程看起来运行得很好,但问题是在调用 before_action 过滤器时无法识别 rails cookies hash。

我也尝试过使用 session,但结果完全一样。

我首先想到的是,在 Rails 架构中,在执行过滤器的那一刻,会话或 cookie 哈希都不会被实例化,然后当应用程序控制器尝试访问它们时,就会显示错误:

路由错误 UsersController:Class 的未定义局部变量或方法“cookies” Rails.root: C:/Users/daniel.tenzi/proyectos/MicroEstudio 应用程序跟踪 |框架跟踪 |全跟踪 app/controllers/application_controller.rb:11:in `check_permissions' app/controllers/users_controller.rb:3:in `' app/controllers/users_controller.rb:1:in `' 路线 路由从上到下优先匹配 帮手 HTTP 动词 小路 控制器#动作 路径/网址 pagecontrollers_path GET /pagecontrollers(.:format) pagecontrollers#index POST /pagecontrollers(.:format) pagecontrollers#create new_pagecontroller_path GET /pagecontrollers/new(.:format) pagecontrollers#new edit_pagecontroller_path GET /pagecontrollers/:id/edit(.:format) pagecontrollers#edit pagecontroller_path GET /pagecontrollers/:id(.:format) pagecontrollers#show PATCH /pagecontrollers/:id(.:format) pagecontrollers#update PUT /pagecontrollers/:id(.:format) pagecontrollers#update 删除 /pagecontrollers/:id(.:format) pagecontrollers#destroy permissions_path GET /permissions(.:format) 权限#index POST /permissions(.:format) 权限#create new_permission_path GET /permissions/new(.:format) 权限#new edit_permission_path GET /permissions/:id/edit(.:format) 权限#edit permission_path GET /permissions/:id(.:format) 权限#show PATCH /permissions/:id(.:format) 权限#update PUT /permissions/:id(.:format) 权限#update 删除 /permissions/:id(.:format) 权限#destroy groups_path GET /groups(.:format) groups#index POST /groups(.:format) 组#create new_group_path GET /groups/new(.:format) groups#new edit_group_path GET /groups/:id/edit(.:format) groups#edit group_path GET /groups/:id(.:format) groups#show PATCH /groups/:id(.:format) groups#update PUT /groups/:id(.:format) groups#update 删除 /groups/:id(.:format) 组#destroy users_path GET /users(.:format) users#index POST /users(.:format) users#create new_user_path GET /users/new(.:format) users#new edit_user_path GET /users/:id/edit(.:format) users#edit user_path GET /users/:id(.:format) users#show PATCH /users/:id(.:format) users#update PUT /users/:id(.:format) users#update 删除 /users/:id(.:format) users#destroy empresas_path GET /empresas(.:format) empresas#index POST /empresas(.:format) empresas#create new_empresa_path GET /empresas/new(.:format) empresas#new edit_empresa_path GET /empresas/:id/edit(.:format) empresas#edit empresa_path GET /empresas/:id(.:format) empresas#show PATCH /empresas/:id(.:format) empresas#update PUT /empresas/:id(.:format) empresas#update 删除 /empresas/:id(.:format) empresas#destroy session_path POST /sessions(.:format) 会话#create new_session_path GET /sessions/new(.:format) 会话#new session_path 删除 /sessions/:id(.:format) 会话#destroy root_path GET / users#index signup_path GET /signup(.:format) users#new signin_path GET /signin(.:format) 会话#new signout_path 删除 /signout(.:format) 会话#destroy

但如果我的猜测是真的,为什么 Rails 会说routing error

我被困在这里至少一个星期,试图找到任何可以帮助我前进的东西,但还没有运气。

我做错了什么?任何帮助将不胜感激!

PS:我见过像 Cancan 这样的认证框架,但不想使用任何一个,这应该更容易和更灵活。

谢谢!

【问题讨论】:

  • 顺便说一句,...User.find_by_sql("select * from view_userpermissions where user_id = #{@current_user.id} and pagecontroller='#{self.controller_name}' and accion='#{self.action}' ").count &lt; 1) 可以重写为... ViewUsercondition.where(user_id: @current_user.id).where(pagecontroller: self.controller_name).where(accion: self.action),这样更短、更简洁、更易于阅读,并且在您需要时更改数据库技术后仍然有效。
  • 用解决方案更新了我的答案,如果有帮助请告诉我。
  • 喜欢它,谢谢杰森!

标签: ruby-on-rails session cookies authorization before-filter


【解决方案1】:

您在类上调用 cookie,而不是实例。这是因为你的方法被定义为def self.xxx

试试这个:

class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception

  include SessionsHelper

  def check_permissions 
    ...

class UsersController < ApplicationController
  before_action :set_user, only: [:show, :edit, :update, :destroy]
  before_action :check_permissions 

  ...

您试图将 before_action 设置为类方法的结果。查看该方法,这不是一个好主意 - 它是重定向而不是生成一个符号( before_action 期望变成一个实例方法名称)。此外,正如您所发现的,您无权访问类范围内的会话、请求、cookie 等。

另一方面,您不应该将“或”用于条件操作,而应仅用于程序流控制。例如:

if a == 1 || b == 1 # good
if a == 1 or b == 1 # bad

thing = Thing.find(id) and thing.save # good
thing = Thing.find(id) && thing.save # bad

'or' 和 'and' 的优先级低于您的预期,因此可能会搞砸您的条件。

【讨论】:

  • 总是乐于提供帮助。
猜你喜欢
  • 1970-01-01
  • 2019-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多