前几天,稍微分析了一下RBAC形式的权限管理系统的实现原理,然后我使用Rails做了一个。
先来说一下表间的关系:
users <--> roles roles <--> permissions
很简单,用户和角色是多对多关系,角色和权限也是多对多关系,那么关于权限管理这一块就一共有5张表。
具体的表结构:
还是直接看数据库定义文件吧!
在User这个Model中有以下两个关键的方法:
现在,大致的意思,相信应该说清楚了吧,我对于用户权限的验证就是根据url,准确地说,应该是根据controller名称和action名称来验证的。
那么现在来看看此权限管理系统是如何工作的吧!
在用户登录时,我把用户的id存到session范围中,然后在需要进行权限保护的控制器中加入如下的过滤器:
比如我在后台管理对文章进行管理(Admin::PostController),代码如下:
以上是对于每次请求的权限控制,那么在页面上如何根据登录用户的权限显示相应的权限内容呢?
在后台管理的模块页面中,加入如下的判断语句即可。
以上就是我做这个权限管理系统的基本思想,代码量比较少,思路也蛮请楚的,比较适合小型的项目。
不过我分析了一下这个权限管理系统,它就基于控制器和控制器方法的名称来判断的,而且应该是对使用generate scaffold形式生成的控制器能比较好地起作用。那么这就决定了它有多方面的不足。
1- 如何保护后台管理中的静态页面。
2- 使用不方便,在对permissions进行管理时,要求管理员比较对所用的程序比较熟悉,了解那些controller和action才行(我正在考虑怎么样让程序自动获取后台中的所有控制器和相关方法,并且显示它们的作用)
3- 权限重复比较多。
4- 与系统结合得感觉还是比较紧,我正在考虑如何运行ruby的特性将其变成一个插件(我的目标)
我正在考虑如何改进这些问题,从而做了一个轻量级的好用的权限管理系统。
先来说一下表间的关系:
users <--> roles roles <--> permissions
很简单,用户和角色是多对多关系,角色和权限也是多对多关系,那么关于权限管理这一块就一共有5张表。
具体的表结构:
还是直接看数据库定义文件吧!
ActiveRecord::Schema.define(:version => 20080708074044) do
create_table "permissions", :force => true do |t|
t.string "name"
t.string "action"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "permissions_roles", :id => false, :force => true do |t|
t.integer "permission_id", :limit => 11
t.integer "role_id", :limit => 11
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "posts", :force => true do |t|
t.string "title"
t.text "body"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "roles", :force => true do |t|
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "roles_users", :id => false, :force => true do |t|
t.integer "role_id", :limit => 11
t.integer "user_id", :limit => 11
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "users", :force => true do |t|
t.string "name"
t.string "password"
t.string "email"
t.datetime "created_at"
t.datetime "updated_at"
end
end
在User这个Model中有以下两个关键的方法:
#Get user's all permissions
def permissions
user_permissions = Array.new
for role in self.roles
user_permissions += role.permissions
end
user_permissions.uniq!
user_permissions
end
#Get user's allowed requests uri
def permission_urls
user_urls = Array.new
user_permissions = Array.new
for role in self.roles
user_permissions += role.permissions
end
for user_permission in user_permissions
user_urls << user_permission.action
end
user_urls
end
现在,大致的意思,相信应该说清楚了吧,我对于用户权限的验证就是根据url,准确地说,应该是根据controller名称和action名称来验证的。
那么现在来看看此权限管理系统是如何工作的吧!
在用户登录时,我把用户的id存到session范围中,然后在需要进行权限保护的控制器中加入如下的过滤器:
比如我在后台管理对文章进行管理(Admin::PostController),代码如下:
before_filter :authorize, :only => [:index, :show, :new, :edit, :destroy]
def authorize
unless User.find(session[:user_id]).permission_urls.include?( self.class.controller_path + "/" + self.action_name )
flash[:notice] = "You have not permission to do it!"
redirect_to :controller => "admin/welcome"
end
end
以上是对于每次请求的权限控制,那么在页面上如何根据登录用户的权限显示相应的权限内容呢?
在后台管理的模块页面中,加入如下的判断语句即可。
<% if User.find(session[:user_id]).allowed_to?("admin/posts/index")%>
<li id="posts_item"><%= link_to "Post Manage", admin_posts_path %></li>
<% end %>
以上就是我做这个权限管理系统的基本思想,代码量比较少,思路也蛮请楚的,比较适合小型的项目。
不过我分析了一下这个权限管理系统,它就基于控制器和控制器方法的名称来判断的,而且应该是对使用generate scaffold形式生成的控制器能比较好地起作用。那么这就决定了它有多方面的不足。
1- 如何保护后台管理中的静态页面。
2- 使用不方便,在对permissions进行管理时,要求管理员比较对所用的程序比较熟悉,了解那些controller和action才行(我正在考虑怎么样让程序自动获取后台中的所有控制器和相关方法,并且显示它们的作用)
3- 权限重复比较多。
4- 与系统结合得感觉还是比较紧,我正在考虑如何运行ruby的特性将其变成一个插件(我的目标)
我正在考虑如何改进这些问题,从而做了一个轻量级的好用的权限管理系统。