基于数据库的RBAC数据模型的权限控制

我们开发一个系统,必然面临权限控制的问题,不同的用户具有不同的访问、操作、数据权限。形成理论的权限控制模型有:自主访问控制(DAC: Discretionary Access Control)、强制访问控制(MAC: Mandatory Access Control)、基于属性的权限验证(ABAC: Attribute-Based Access
Control)等。最常被开发者使用也是相对易用、通用的就是RBAC权限模型(Role-Based Access
Control)

1、RBAC权限模型简介

RBAC权限模型(Role-Based Access Control)即:基于角色的权限控制。模型中有几个关键的术语:

  • 用户:系统接口及访问的操作者
  • 权限:能够访问某接口或者做某操作的授权资格
  • 角色:具有一类相同操作权限的总称 

RBAC权限模型核心授权逻辑如下:

  • 某用户是什么角色?
  • 某角色具有什么权限?
  • 通过角色对应的权限推导出用户的权限 

2、RBAC的演化进程

2.1、用户与权限直接关联

想到权限控制,人们最先想到的一定是用户与权限直接关联的模式,简单地说就是:某个用户具有某些权限。如图: 

  • 张三具有所有权限他可能是一个超级管理员.
  • 李四,王五 具有添加商品和审核商品的权限有可能是一个普通业务员 

这种模型能够清晰的表达用户与权限之间的关系,足够简单。但同时也存在问题:

  • 现在用户是张三、李四,王五以后随着人员增加,每一个用户都需要重新授权
  • 操作人员的他的权限发生变更后,需要对每个一个用户重新授予新的权限 

2.2、用户与角色关联

这样只需要维护角色和权限之间的关系就可以了. 如果业务员的权限发生变更, 只需要变动业务员角色和权限之前的关系进行维护就可以了. 用户和权限就分离开来了. 如下图 

3、基于RBAC设计权限表结构

  • 一个用户有一个或多个角色
  • 一个角色包含多个用户
  • 一个角色有多种权限
  • 一个权限属于多个角色 

4、基于Spring Security 实现RBAC权限管理

4.1、动态查询数据库中用户对应的权限

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.lagou.domain.Permission;
import org.apache.ibatis.annotations.Select;

import java.util.List;


public interface PermissionMapper extends BaseMapper<Permission> {
    /**
     * 根据用户ID查询权限
     *
     * @param id
     * @return
     */
    @Select("SELECT p.*  FROM t_permission p,t_role_permission rp,t_role r,t_user_role ur,t_user u " +
            "WHERE p.id = rp.PID AND rp.RID = r.id AND r.id = ur.RID AND ur.UID = u.id AND u.id =#{id}")
    List<Permission> findByUserId(Integer id);
}

4.2、给登录用户授权 

这个是在实现UserDetailsService接口,在重写的loadUserByUsername的方法中

Collection<GrantedAuthority> authorities = new ArrayList<>(); // 权限的集合,先声明一个权限集合, 因为构造方法里面不能传入null
// 基于数据库查询用户对应的权限
List<Permission> permissionList = permissionService.findByUserId(user.getId());
    for (Permission permission : permissionList) {
// 授权
         authorities.add(new SimpleGrantedAuthority(permission.getPermissionTag()));
      }

4.3、设置访问权限

这个是在我们自定义类SecurityConfig继承了WebSecurityConfigurerAdapter接口,在其重写方法中设置,void configure(HttpSecurity http)

// 查询数据库所有权限列表
        List<Permission> list = permissionService.list();
        for (Permission permission : list) {
            http.authorizeRequests().antMatchers(permission.getPermissionUrl())
                    // 添加请求权限
                    .hasAuthority(permission.getPermissionTag());
        }

之所以使用hasAuthority而不是使用hasRole是因为hasRole会在权限的前面加上"ROLE_".

5、基于页面端标签的权限控制

在jsp页面或者thymeleaf模板页面中我们可以使用spring security提供的权限标签来进行权限控制.要想使用thymeleaf为SpringSecurity提供的标签属性,首先需要引入thymeleaf-extras-springsecurity依赖支持。

5.1、在pom 文件中的引入springsecurity的标签依赖thymeleaf-extras-springsecurity5。

<!--添加thymeleaf为SpringSecurity提供的标签依赖 -->
        <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-springsecurity5</artifactId>
            <version>3.0.4.RELEASE</version>
        </dependency>

5.2、在html文件里面申明使用

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/extras/spring-security">

5.3、常用SpringSecurity的标签属性介绍

判断用户是否已经登陆认证,引号内的参数必须是isAuthenticated()。
sec:authorize="isAuthenticated()"

获得当前用户的用户名,引号内的参数必须是name。
sec:authentication=“name”


判断当前用户是否拥有指定的权限。引号内的参数为权限的名称。
sec:authorize=“hasRole(‘role’)”

5.4、SpringSecurity标签的使用

<div class="leftnav">
    <div class="leftnav-title">
        <div sec:authorize="isAuthenticated()"> <!--有权限时,为true,则会显示-->
            <span sec:authentication="name"></span>
            <img src="images/y.jpg" class="radius-circle rotate-hover" height="50" alt=""/>
        </div>
    </div>
    <div sec:authorize="hasAuthority('user:findAll')">  <!--有权限时,为true,则会显示-->
        <h2><span class="icon-user"></span>系统管理</h2>
        <ul style="display:block">
            <li><a href="/user/findAll" target="right"><span class="icon-caretright"></span>用户管理</a></li>
            <li><a href="javascript:void(0)" onclick="toCors()" target="right">
            <span class="icon-caret-right"></span>跨域测试</a></li>
        </ul>
    </div>
    <div sec:authorize="hasAuthority('product:findAll')">   <!--有权限时,为true,则会显示-->
        <h2><span class="icon-pencil-square-o"></span>数据管理</h2>
        <ul>
            <li><a href="/product/findAll" target="right"><span class="iconcaret-right"></span>商品管理</a></li>
        </ul>
    </div>
</div>

6、记录bug

当我们开启CSRF防护后,我们点击项目中的登录按钮,会报404错误,这是因为logout登出功能的方法必须为post请求,并且我们还要携带

<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"/>这里面的参数。这样才能登出成功,而不会报错。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

悠然予夏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值