1、 What? 什么是权限管理?

具体可参见百度:http://baike.baidu.com/view/2108713.htm

名词备注:

数据级权限:百科内的权限管理一文解释的比较不错,但其中的“数据级权限”有的人看来会觉得有点摸不着头脑。数据级权限,即表示权限与特定数据有联系的权限,比方说,某用户只能创建100个用户。这个100,就是数据级权限的一个指标。

2、 How?怎么样实现权限管理?

2.1、一种烦恼

也许很多程序员会在权限管理中遇到这样的一个问题。

大部分项目都需要权限管理系统,但不同的项目背景中,角色的种类和对应的权限灵活多变。往往需要在维护和调研时花费大量的功夫去分析,而最后由于不同客户方不同层面的领导的意见不一或者不同的决策等问题,造成多次的翻工(也许开始你定好了适合他们的权限机制,但后来又有些不可抗拒因素导致你又要修改项目)。

这样的问题是一种无用功,而且是十分让人烦恼的。

如何去解决怎样的问题?

2.2、权限管理架构图

2.2.1、用户user

保存基本的用户名,密码,角色表id和用户状态。

管理员可以修改用户的角色。

PS:系统最基本的状态至少需要保留一个默认管理员账号。

2.2.2、权限privilege

用来判定(vote)功能及数据级权限管理的依据。

项目创建者内置的权限集合,不给与管理的权限。否则将可能造成项目功能的缺陷。

2.2.3、角色role

决定用户具体包含权限列表。

role_privilege连接role与privilege两个表用来表示关系表连接构造many-to-many关系。

同样的,系统默认状态也必须保留至少一种角色为系统自带的管理,这个角色具备系统中全部的权限。也就是说,该角色不受role_ privilege表所限制,会直接读取privilege中的所有权限集。

2.2.4、权限分类privilege_category

为了更加完善的展现权限分配模块,可以构造一个权限分类。

2.3、用SpringSecurity3实现具体功能

具体SpringSecurity3的配置这里就不详细说明了,可参考网上其他资料。因为本文主要讲述的是如何实现RBAC权限管理模块。

    注:自定义的权限的命名必须以ROLE_ 开头,例如ROLE_USER_CREATE等。

2.3.1、权限与角色误区

使用SpringSecurity3的时候,网上很多的资料都能让你的模块跑起来。但随之而来的是一些误区。

比方说,会把权限和角色两者混淆。比较经典的例子如下:

Collection<GrantedAuthority> auths=new ArrayList<GrantedAuthority>();
GrantedAuthorityImpl roleAdmin=new GrantedAuthorityImpl("ROLE_ADMIN");
GrantedAuthorityImpl roleUser=new GrantedAuthorityImpl("ROLE_USER");
auths.add(roleAdmin);
auths.add(roleUser); 

然后访问权限的配置如下:

<intercept-url pattern="/**" access="ROLE_USER" />

虽然也许看上去没什么问题,但其实存在一定的隐患。因为能访问页面的不是因为他是user,而是因为他有“访问”的权限。

如果后来增加了一个guest的角色,而他能访问系统,但不能含有user的权限。因为user的权限可能有附带很多界面上的功能,但不附上ROLE_USER的话guest又不能访问系统,所以你就不得不修改配置文件中的access。

造成这个的问题的最终原因就是角色和权限混淆了。

2.3.2、权限分配的灵活性

要想最大限度把权限分配变得灵活,角色提供可摘取权限的功能是必不可少的。而针对不同的项目背景,所有的角色和权限也许会出现各种的变化。但其功能还是离不开分配角色和分配权限。

而通过role_privilege表,我们可以在用户登录系统的时候,把该用户角色的权限通过SpringSecurity帮助我们放到用户的权限组内。从而我们可以利用SpringSecurity提供的各种标签,标注访问控制等实现权限功能管理和现实。

例子:

<sec:authorize ifAnyGranted="ROLE_CREATE,ROLE_UPDATE,ROLE_READ,ROLE_DELETE">
<a>用户管理</a>
</sec:authorize>

即用户拥有OLE_CREATE,ROLE_UPDATE,ROLE_READ,ROLE_DELETE任何一个权限的时候才能查看到用户管理按钮。

点进去之后,我们可以再细分对应的权限操作,没有的权限则该功能模块会不出现。

2.3.3、权限的包含关系

有的时候,权限还必须有“包含”关系,即若你具备了某权限,则另外的权限你也必定会具备。

比方说,有个角色他有删除用户的权限,但他没有读取用户的权限。这样觉得有没有问题呢?

若用户没有读取用户的权限,连列表都不出来,那他如何实现删除?这样看上去虽然不是系统上的问题。但一个完善的系统,必须去考虑这样的情况发生。

2.3.4、自定义UserDetailsService接口实现类

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.dao.DataAccessException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException; import cn.com.timekey.drugmonitor.business.PrivilegeBus;
import cn.com.timekey.drugmonitor.business.UserBus;
import cn.com.timekey.drugmonitor.log.Log;
import cn.com.timekey.drugmonitor.log.LogFactory;
import cn.com.timekey.drugmonitor.po.Privilege;
import cn.com.timekey.drugmonitor.po.Role;
import cn.com.timekey.drugmonitor.po.RolePrivilege;
import cn.com.timekey.drugmonitor.po.Users; /**
* @author Kenny
*/
public class MyUserDetailsService implements UserDetailsService { private static final Log LOGGER = LogFactory
.getLog(MyUserDetailsService.class); private static final String SYSTEM_ROLE_ID = "1";// 系统默认管理员的id private UserBus userBus;
private PrivilegeBus privilegeBus; public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException, DataAccessException {
if (StringUtils.isBlank(username)) {
throw new UsernameNotFoundException("no such user.", username);
}
Users user = userBus.findByName(username);
if (user == null) {
LOGGER.debug("no such user by " + username);
throw new UsernameNotFoundException("no such user.", username);
} else if (user.getRole() == null) {
LOGGER.debug("no such role by " + username);
throw new UsernameNotFoundException("no such user.", username);
} String adminName = user.getUserName();
String password = user.getUserPassword();
Role role = user.getRole();
@SuppressWarnings("unchecked")
Collection<Privilege> privileges = CollectionUtils.EMPTY_COLLECTION;
// 判断是否为系统默认管理员,若是,则直接获取privilege表中全部权限。
if (StringUtils.equals(role.getRoleId(), SYSTEM_ROLE_ID)) {
privileges = privilegeBus.findAll();
}
Set<RolePrivilege> rolePrivileges = role.getRolePrivileges(); @SuppressWarnings("unchecked")
Collection<GrantedAuthority> authorities = CollectionUtils.EMPTY_COLLECTION;
if (privileges.isEmpty() && rolePrivileges != null
&& !rolePrivileges.isEmpty()) {
privileges = new ArrayList<Privilege>(rolePrivileges.size());
for (RolePrivilege rolePrivilege : rolePrivileges) {
privileges.add(rolePrivilege.getPrivilege());
}
}
if (privileges.isEmpty()) {
LOGGER.warn("user has not any rolePrivileges.");
throw new UsernameNotFoundException("Privilege fail! ", username);
}
// 构造权限组
authorities = generateAuthorities(privileges); boolean isEnable = user.getIsActive();// 如果账号有状态的话,可根据查询结果配置该值。 return new org.springframework.security.core.userdetails.User(
adminName, password, isEnable, true, true, true, authorities);
} /**
* 构造权限组
*
* @param rolePrivileges
* @return
*/
private Collection<GrantedAuthority> generateAuthorities(
Collection<Privilege> privileges) {
List<GrantedAuthority> auth = new ArrayList<GrantedAuthority>(
privileges.size());
for (Privilege rolePrivilege : privileges) {
GrantedAuthority authority = new GrantedAuthorityImpl(
rolePrivilege.getPrivilegeName());
auth.add(authority);
}
return auth;
} public void setUserBus(UserBus userBus) {
this.userBus = userBus;
} public void setPrivilegeBus(PrivilegeBus privilegeBus) {
this.privilegeBus = privilegeBus;
}
}

2.3.5、系统的权限漏洞

出来页面上使用TAG来实现基本的权限功能隐藏与显示外。还必须注意系统内部的权限判断。

使用拦截器保护限制资源

TAG帮我们隐藏了功能的URL,但该URL还是存在的,只要对方知道URL就能直接发请求过来了,从而绕过了权限管理。

我们可以使用拦截器进一步处理请求权限的问题。具体可以在<http auto-config>代码块中配置,如:

<intercept-url pattern="/createUser.do" access="ROLE_USER_CREATE" />

 <intercept-url pattern="/listUser.do" access="ROLE_USER_READ" />
<intercept-url pattern="/**" access="ROLE_LOGIN" />

解释:

访问/createUser.do资源必须有ROLE_USER_CREATE权限。

访问/listUser.do资源必须有ROLE_USER_READ。

访问任何资源都必须有ROLE_LOGIN才行。(也可以用IS_AUTHENTICATED_REMEMBERED)

使用标注保护方法调用

有的时候,程序员在编码中会出现疏忽,导致引用错方法。或者在编码时,没有考虑到权限的问题造成一些跨权限的漏洞。

比方说,某个功能因为疏忽,没在拦截器上配置权限拦截,或者功能定义了两个URL入口,而只有其中一个在拦截器上配置了(一个也许是系统旧的遗留入口)。

这样的情况下就会带来权限漏洞,有不良目的人就可以使用这些漏洞来攻击系统,但最重要的还是造成客户损失。

要更进一步的加强“保险”,我们还可以使用标注在代码里面声明拥有某种权限才能调用特定的方法(也可以使用AOP声明的方式,但个人更加喜欢标注的形式,但标注的话相对于会硬编码些)。

使用标注时,记得要在添加上下面代码才生效喔!

<global-method-security secured-annotations="enabled">
</global-method-security>

例子如:

import org.springframework.security.access.annotation.Secured;

public interface AccountBusiness {

   @Secured("ROLE_USER_CREATE")
public void save(User user); @Secured("ROLE_USER_DELETE")
public void delete(String id); }

3、 Gain 我们的收获

我们再不用去考虑系统中不同角色的有什么权限的问题了,因为权限分配十分灵活化。程序员不必纠结不同项目中,什么角色应该具备哪些权限而烦恼了,但我们必须配置好一套完善的权限列表来满足用户的分配需求。虽然不完美,但减少了很多的烦恼。

角色与权限分配的功能由客户或者业务人员自己来决定。我们只要提供好足够满足对方需求的权限范围就可以了。权限缺少的时候,我们可以增加,但这些工作不至于是无用功。

4、 遗留问题

1.用户登录时,必须重新从数据库里面拿角色对应的权限集,资源消耗是否有点多?

就这个问题而言,我是觉得没必要计较这些资源消耗的,因为权限集再怎么多也不会超过50条吧。

而权限管理系统,一般并发量也不会大的了。如果真的纠结这样的消耗,也可以放用static map用来实现角色与权限集的获取,但记得用上观察者模式。因为权限集是可以被修改的,不用观察者的话就会出现得到过期的权限集了。

2.虽然考虑到数据级的权限管理问题,但目前还是没有提供这样的案例。

3.Group用户组还不在此架构范围内。

使用SpringSecurity3实现RBAC权限管理的更多相关文章

  1. RBAC权限管理模型 产品经理 设计

    RBAC权限管理模型:基本模型及角色模型解析及举例 | 人人都是产品经理http://www.woshipm.com/pd/440765.html RBAC权限管理 - PainsOnline的专栏 ...

  2. Spring Security实现RBAC权限管理

    Spring Security实现RBAC权限管理 一.简介 在企业应用中,认证和授权是非常重要的一部分内容,业界最出名的两个框架就是大名鼎鼎的 Shiro和Spring Security.由于Spr ...

  3. yii2 rbac权限管理学习笔记

    下面介绍一个 yii2 的 Rbac 权限管理设置,闲话少说,直接上代码, 1.首先我们要在组件里面配置一下 Rbac ,如下所示(common/config/main-local.php或者main ...

  4. vue基于d2-admin的RBAC权限管理解决方案

    前两篇关于vue权限路由文章的填坑,说了一堆理论,是时候操作一波了. vue权限路由实现方式总结 vue权限路由实现方式总结二 选择d2-admin是因为element-ui的相关开源项目里,d2-a ...

  5. ThinkPHP中RBAC权限管理的简单应用

    RBAC英文全称(Role-Based Access Controller)即基于角色的权限访问控制,简单来讲,一个用户可以拥有若干角色,每一个角色拥有若干权限.这样,就构造成“用户-角色-权限”的授 ...

  6. PHP中RBAC权限管理

    1.RBAC概念和原理          RBAC:全称叫做Role-Based Access Control,中文翻译叫做基于角色的访问控制.其主要的作用是实现项目的权限控制.            ...

  7. 基于RBAC权限管理的后台管理系统

    在摸爬滚打中渐渐理解了RBAC权限管理是个什么玩意. RBAC的基本概念: **RBAC认为权限授权实际上是Who.What.How的问题.在RBAC模型中,who.what.how构成了访问权限三元 ...

  8. spring boot:spring security用mysql数据库实现RBAC权限管理(spring boot 2.3.1)

    一,用数据库实现权限管理要注意哪些环节? 1,需要生成spring security中user类的派生类,用来保存用户id和昵称等信息, 避免页面上显示用户昵称时需要查数据库 2,如果需要在页面上显示 ...

  9. RBAC权限管理

    RBAC(Role-Based Access Control,基于角色的访问控制),就是用户通过角色与权限进行关联. 简单地说,一个用户拥有若干角色,每一个角色拥有若干权限. 这样,就构造成“用户-角 ...

  10. Yii2-admin RBAC权限管理的实现

    原文地址:http://www.open-open.com/lib/view/open1434638805348.html   http://wlzyan.blog.163.com/blog/stat ...

随机推荐

  1. three.js添加3d模型

    three官方的几何体也就那么几个,想要生成各种各样的模型,其难度十分之大,这时引入外部模型也不失为一种选择.具体引入办法如下. 导入依赖 点击查看代码 import * as THREE from ...

  2. Figma 学习笔记 – Color

    大纲 Figma 的颜色是通过 FIll 实现的 (Fill 还有其它功能比如 fill 图片) 整体大概长这样, 我们一个一个看 颜色和 opacity

  3. Hugging Face NLP课程学习记录 - 2. 使用 Hugging Face Transformers

    Hugging Face NLP课程学习记录 - 2. 使用 Hugging Face Transformers 说明: 首次发表日期:2024-09-19 官网: https://huggingfa ...

  4. 【赵渝强老师】Kubernetes的探针

    Kubernetes提供了探针(Probe)对容器的健康性进行检测.实际上我们不仅仅要对容器进行健康检测,还要对容器内布置的应用进行健康性检测. Probe有以下两种类型: livenessProbe ...

  5. android系统启动流程- ServiceManager进程启动流程

    *注:基于Android11源码 ServiceManager进程是在init进程创建的,所以我们从init进程的main()开始分析: // 文件路径: system/core/init/main. ...

  6. ARM64 SMP多核启动(下)- PSCI

    4.支持psci情况 上面说了pin-table的多核启动方式,看似很繁琐,实际上并不复杂,无外乎主处理器唤醒从处理器到指定地址上去执行指令,说他简单是相对于功能来说的,因为他只是实现了从处理器的启动 ...

  7. 时隔半年 DotNetGuide 已突破了 6.6K + Star,持续更新,欢迎更多小伙伴PR投稿!

    前言 记得今年5月份的时候 DotNetGuide GitHub才突破5k Star,经过持续不断地输出时隔半年 DotNetGuide 已突破了 6.6K + Star!并且由我创建的DotNetG ...

  8. OpenFunction 0.6.0 发布: FaaS 可观测性、HTTP 同步函数能力增强及更多特性

    OpenFunction 是一个开源的云原生 FaaS(Function as a Service,函数即服务)平台,旨在帮助开发者专注于业务逻辑的研发.在过去的几个月里,OpenFunction 社 ...

  9. 原子操作类Atomic

    原子操作的基本数据类型 基本类型的原子操作主要有这些: AtomicBoolean:以原子更新的方式更新 boolean: AtomicInteger:以原子更新的方式更新 Integer; Atom ...

  10. 想玩Steam游戏,但配置太低?ToDesk云电脑一招搞定!

    在游戏爱好者的世界里,汇集了许多游戏大作的Steam平台无疑是一座宝库.但对于许多玩家来说,拥有一颗渴望畅玩游戏的心,却常常被低配置的电脑设备所束缚.尤其是面对硬件要求极高的3A大作时,低配置的电脑往 ...