实现多个用户角色

2024-03-07

我使用 state_machine 取得了巨大的成功,并且喜欢它通过几行代码动态创建的类方法。

但是,我不确定如何继续我正在创建的系统。我目前正在开发一个用户具有多种角色的系统。所以这并不像拥有一个状态来自的用户那么简单未证实 to 确认的然后有可能admin.

一个用户现在有很多角色,并且可以是潜在的, a cyclist, a 协调员, a manger, a 论坛管理员, a 商店管理员, a 超级管理员 and a 筹款活动.

所以层次结构是这样的:

超级管理员

论坛管理员, 商店管理员

cyclist, 协调员, manger, 筹款活动

潜在的

然而,一个状态机并不能解决这个问题,因为一个用户完全有可能同时拥有上述所有角色。

我正在实现我自己的类方法,如下所示,以某种程度模拟状态机:

class User < ActiveModel::Base
    has_many :jobs
    has_many :roles, through: :jobs

    def role_array
        self.roles.pluck(:role)
    end

    def has_role?(role)
        role_array.include?(role)
    end

    # checking
    def is_superadmin?
        role_array.include?('superadmin')
    end


    # changing
    def add_role(role)
       self.update_attributes(accepted_at: Time.now) if self.is_only_potential?
       self.user_roles.create(role_id: Role.find_by(role: role).id ) if !self.has_role?(role)
    end

    def remove_role(role)
        self.user_roles.find_by( role_id: Role.find_by(role: role).id ).destroy if self.has_role?(role)
    end

    def make_superadmin!
        add_role('superadmin')
    end

    def denounce_superadmin!
        remove_role('superadmin')
    end

end

这只是有点无聊。所以我的问题是:

1)我做对了吗?您将如何处理具有多个角色的用户?

2)即使我做对了,我也想创建一个 state_machine-esque DSL,所以当我需要创建一个新角色时,比如说“跑步者”,我可以在我的模型中做这样的事情:

class User < ActiveModel::Base
    has_many :jobs
    has_many :roles, through: :jobs

    multiroles initial: :potential do
        roles [:superadmin, :forum_admin, :store_admin, :cyclist, :coordinator, :manager, :fundraiser, :potential]
         # dynamically creates the above methods for getting and setting for all roles
    end

我应该如何创建多角色方法?里面lib?准备好作为我的第一颗宝石打包了吗?

我不知道如何动态创建方法,但我想开始:)

只是一个想法,也许multiroles方法可以动态获取所有角色Roles.all并自动添加以上方法!也许甚至会照顾has_many :jobs has_many :roles, through: :jobs

另外,我应该如何验证这些角色?我目前正在控制器的 before 块中执行此操作:

def only_superadmins
    redirect_to root_url if !current_user.has_role?('superadmin')
end

我的应用程序控制器中也有很多这些方法,only_superadmins, only_cyclists等,我通过以下方式给他们打电话before_method各种子控制器中的方法。

这个可以吗?我应该使用康康舞还是其他什么?

如果我做得正确,我想知道应该如何使用我的 Gem 动态创建这些方法。我正在思考以下几点:

class panel_controller < ApplicationController   
    allowed_roles [:super_admin, :forum_admin, :store_admin]
end

allowed_roles 方法将创建这些方法

def allowed_roles(role_array)
    role_array.each do |role|
         define "only_#{role.to_s}s" do |arg|
            redirect_to root_url if !current_user.has_role?(arg.to_s)
         end
    end
end

这样就会以编程方式创建这些方法:

def only_super_admins
    redirect_to root_url if !current_user.has_role?('super_admin')
end

def only_forum_admins
    redirect_to root_url if !current_user.has_role?('forum_admin')
end


def only_store_admins
    redirect_to root_url if !current_user.has_role?('store_admin')
end

虽然我不明白为什么这行不通,但我觉得这并不算太有效。

Maybe allowed_roles应该看起来像这样:

def allowed_roles(wanted_roles)
    redirect_to root_url unless (current_user.role_array & wanted_roles).empty? # it's ONLY empty when any of the current_user roles exists in the wanted_roles array
end

我真的只是想要一些指示:)

我如何创建宝石来制作allowed_roles控制器可用的方法和multiroles可供用户使用的模型?

Can cancan像这样管理多个角色?我应该只用那个吗?


恢复答案:

为了处理模型的角色,一个不错的选择是使用 gemrolify https://github.com/EppO/rolify。有了它,您可以轻松定义任意数量的角色,并将任意数量的角色与您的用户关联。使用很简单,按照官方文档操作即可here https://github.com/EppO/rolify.

CanCan https://github.com/ryanb/cancan(或其后继者康康康 https://github.com/cancancommunity/cancancan) 用于处理权限。您将在文件中定义具有每个角色(使用 rolify 定义)的用户有权执行的操作app/models/ability.rb。然后,在控制器或视图中,您只需验证用户是否有权对资源执行操作。例如,在您的控制器中您验证授权,例如@comment = Comment.new(params); authorize! :create, @comment,并且在您看来,您验证了授权,例如if can? :create, Comment。参考官方文档here https://github.com/ryanb/cancan了解如何设置和使用 CanCan。

将这些应用到您的具体问题:

添加罗利弗 (gem "rolify") 和康康 (gem "cancan") gem 到您的 Gemfile。

执行rails shell命令rails g rolify Role User创建一个名为 Role 的新类(或使用您喜欢的名称),并在现有的 User 类中添加一些类方法。由于新类 Role 会将表 Role 添加到您的数据库中,因此您必须运行rake db:migrate(当使用 ActiveRecord 时)。

Add resourcify到用户将访问的任何类。例如:

class Forum < ActiveRecord::Base
  resourcify
end

完成这些步骤后,您的 User 类将配备以下方法add_role, remove_role and has_role您可以使用它们添加任意数量的角色:

user.add_role :superadmin
user.add_role :fundraiser

user.has_role? :superadmin
# >> true
user.has_role? :fundraiser
# >> true

您甚至可以将角色范围限定为一个资源或实例:

user.add_role :cyclist, Forum
user.add_role :coordinator, Forum.first

user.has_role? :cyclist, Forum
# >> true
user.has_role? :cyclist, Store
# >> false
user.has_role? :coordinator, Forum.first
# >> true
user.has_role? :coordinator, Forum.second
# >> false

所以你可以这样编写你的 User 类:

class User < ActiveModel::Base
  rolify
  has_many :jobs

  # checking
  def is_superadmin?
      self.has_role?('superadmin')
  end

  # changing
  def add_new_role(role)
     self.update_attributes(accepted_at: Time.now) if self.is_only_potential?
     self.add_role(role)
  end

  def make_superadmin!
      add_new_role('superadmin')
  end

  def denounce_superadmin!
      remove_role('superadmin')
  end
end

要验证这些角色,您可以使用 CanCan。执行rails shell命令rails g cancan:ability生成文件app/models/ability.rb您将在其中定义您的角色的权限。

class Ability
  include CanCan::Ability

  def initialize(user)
    user ||= User.new # guest user

    if user.has_role? :superadmin
      can :manage, All  # can manage (Read, Create, Update, Destroy, ...) everything
    elsif user.has_role? :forum_admin
      can :manage, Forum  # can manage (Read, Create, Update, Destroy, ...) any Forum
    elsif user.has_role? :store_admin
      can :manage, Store do |store|  # Can manage only its own store
        store.try(:user) == user
      end
    elsif user.has_role? :forum_member
      can :create, Post do |post|
        if post.forum.members.include? user
          true
        end
      end
      can :destroy, Post do |post|
        post.try(:user) == user
      end
      can :update, Post do |post|
        post.try(:user) == user
      end
    elsif ...

    else # Users without role
      can :read, All
    end
  end
end

在你的控制器中你可以调用authorize!方法。例如:

# app/controllers/posts_controller.rb
def create
  @post = Post.new(params[:post])
  @post.user = current_user
  authorize! :create, @post
  if @post.save
    redirect_to @post
  else
    render :action => 'new'
  end
end

或者,您可以在控制器的开头包含以下内容,并且在每个操作之前自动加载和授权(或不授权)资源:

class PostController < ApplicationController
  load_and_authorize_resource :post

  ...

def create
  authorize! :create, @post
  if @post.save
    redirect_to @post
  else
    render :action => 'new'
  end
end

观看本教程:RailsCast http://railscasts.com/episodes/192-authorization-with-cancan开始使用 CanCan。

我希望这可以帮助指导您解决问题。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

实现多个用户角色 的相关文章

随机推荐

  • 使用 JQuery 触发 HTML 5 颜色选择器的点击

    在 JQuery 中 我们可以通过以下方式触发任何给定元素的 点击 selector trigger click 尽管当元素是 HTML 5 颜色选择器并且 CSS 将 display 属性设置为 none 时 我很难这样做 通常 如果输入
  • 如何在jquery中移动鼠标上的文本?

    如何使鼠标悬停时链接向左移动 我希望鼠标移开时文本移回 用jquery可以吗 请帮忙 谢谢 无论 CSS 是否在 jQuery 中 您都会使用 CSS 不知道为什么要使用 jQuery 但无论如何 这里有一个示例 a href Move m
  • Android Studio中EditText与其Id的关系?

    请仔细阅读我的问题 我在学习Activity LifeCycle 我只有一个EditText and a TextView在我的 XML 布局中具有某些id 当我旋转屏幕时 似乎没有任何变化 因为旋转不影响EditText 但是当我删除id
  • Android 任务亲和力解释

    属性具体是什么taskAffinity用于 我已经经历了文档 http developer android com guide topics manifest activity element html aff但我不太明白 谁能用通俗易懂的
  • git add、commit 和 push 命令合二为一?

    有什么办法可以将这三个命令合二为一吗 git add git commit a m commit do not need commit message either git push 有时我只更改一个字母 CSS 填充或其他内容 尽管如此
  • 如果应用程序被杀死,应用程序处于后台时收到的远程通知不会点击“didReceiveRemoteNotification - fetchCompletionHandler”方法?

    我们实现了以下方法来接收远程通知 并启用了 项目功能下的后台获取和远程通知 即使应用程序位于前台或后台 方法也会命中 但是 如果应用程序被杀死 在后台收到通知 则不会调用以下方法 如何解决这个问题 void application UIAp
  • 尝试使用 Maven 导入 o​​racle jdbc7 驱动程序时出错

    我无法使用 Maven 导入 jdbc7 oracle 驱动程序 我按照教程中的方式执行了所有操作甲骨文博客 https blogs oracle com dev2dev entry how to get oracle jdbc pom但我
  • 从日志文件中解析文本和 JSON 并将它们保存在一起

    我有一个包含文本字符串和 json 的 log 文件 例如 A whole bunch of irrelevant text 2022 12 15 12 45 06 run 1 user james json value 30 error
  • 如何修复“无法通知构建侦听器”错误?

    打开我的电脑时出现此错误 并打开Android Studio Gradle 构建花费的时间比正常情况要长 当它最终构建时出现了这个错误 这可能是由于将我的工作从 PC 错误地提交到我的笔记本电脑 通过 GitHub 造成的 但我不确定我是新
  • Spring 集成 TCP。获取已连接客户端的连接ID

    我在这里遇到动态 TCP 连接方法的问题 Spring IP 动态 FTP 示例 https github com spring projects spring integration samples tree master advance
  • 从sql返回多个值到标签

    我有标签
  • IIS 8.5 中的 HttpModule 未加载

    我用 C 为 IIS 8 5 编写了一个简单的托管 HttpModule 并将其安装到全局程序集缓存中 CLR 版本 4 0 30319 IIS 检测到它存在 并且我已将其作为应用程序主机级别的模块安装 不幸的是 它似乎根本没有被执行 我们
  • 利用 Bootstrap Carousel“slide”事件和 .next 类

    所以我遇到了一个小问题 类似于我前几天发布的这个问题 http bit ly 11JpbdY http bit ly 11JpbdY 在加载时隐藏的一段内容上使用 SlabText 这次 我试图让slabText 更新滑块中某些内容的显示
  • 可以将活动的 Microsoft Word 窗口转换为 WPF 窗口吗?

    我创建了一个 Microsoft Word 2010 vsto 加载项 当用户单击功能区按钮时 它会显示许多自定义 Wpf 窗口对话框 我遇到的问题是 如果单击任务栏中的 Word 图标 自定义对话框会在 Word 实例后面消失 经过一番谷
  • R 中 model.matrix 中有序因子的列名称

    我使用创建了一个设计矩阵model matrix功能 如果我使用有序因子数据 我得到L Q and C列名称中的后缀 这些后缀的含义是什么以及它们如何映射到因子水平 帮助文件为model matrix对于这个问题还不清楚 head mode
  • 如何让 VS 2008 停止强制命名空间缩进?

    我从来都不太喜欢大多数编辑器处理名称空间的方式 他们总是强迫你添加额外的东西无意义压痕级别 例如 我在一个页面中有很多代码 我更喜欢将其格式化为 namespace mycode class myclass void function fo
  • golang:在 Windows 上运行 pdf 文件的默认应用程序

    我想使用默认应用程序在文件系统中打开 PDF 文件 我怎样才能做到这一点 在命令行中 我只需编写 pdf 文件的文件名 应用程序就会打开 包含请求的文件 当我尝试使用时exec Command 我收到一个错误 毫不奇怪 exec foo p
  • v-model 不支持输入类型=“文件”

    我不能使用v model对于文件输入 Vue 说我必须使用v on change 好的 我可以使用v on change 但是如何将输入文件的 内容 绑定到data财产 假设我想将它绑定到一个组件中this file export defa
  • 片段中的片段不刷新

    这是我的应用程序 带有片段 左侧有一个ListView 您可以在其中进行选择 如果您选择了右侧之一 则加载一个片段并将选项卡添加到 ActionBar 有这样的代码 import java util ArrayList import and
  • 实现多个用户角色

    我使用 state machine 取得了巨大的成功 并且喜欢它通过几行代码动态创建的类方法 但是 我不确定如何继续我正在创建的系统 我目前正在开发一个用户具有多种角色的系统 所以这并不像拥有一个状态来自的用户那么简单未证实 to 确认的然