SpringBoot整合Shiro实现基于角色的权限访问控制(RBAC)系统简单设计从零搭建

时间:2023-01-03 12:58:10

SpringBoot整合Shiro实现基于角色的权限访问控制(RBAC)系统简单设计从零搭建

技术栈 : SpringBoot + shiro + jpa + freemark ,因为篇幅原因,这里只贴了部分代码说明,完整项目地址 : https://github.com/EalenXie/shiro-rbac-system

1 . 新建一个项目名为shiro-rbac-system,pom.xml加入基本依赖 :


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
</parent>
<groupId>name.ealen</groupId>
<artifactId>shiro-rbac-system</artifactId>
<version>0.0.1</version>
<name>shiro-rbac-system</name>
<description>SpringBoot整合Shiro实现基于角色的权限访问控制(RBAC)系统简单设计从零搭建</description> <properties>
<java.version>1.8</java.version>
<author>EalenXie</author>
<description>SpringBoot整合Shiro实现基于角色的权限访问控制(RBAC)系统简单设计</description>
</properties> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.31</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

基本的数据对象关系 :

一个用户对应一个或者多个角色。
一个角色对应一个或者多个权限。
一个权限对应能够访问对应的API或url资源。

1 . RBAC基本实体关系,Permission类(权限资源) :


/**
* Created by EalenXie on 2019/3/25 11:15.
* <p>
* 权限许可(Permission) 操作 及其能访问url 权限对应一个url地址
*/
@Entity
@Table(name = "system_shiro_permission")
public class Permission extends BaseEntity {
@Column(unique = true)
private String name; //权限名 唯一
@Column(unique = true)
private String url; //访问地址信息 唯一
private String description; //描述信息
//省略getter/setter
}

2 . Role类(用户角色),一个角色拥有一个或者多个权限 :


/**
* Created by EalenXie on 2019/3/25 11:18.
* <p>
* 角色(Role) 角色下面对应多个权限
*/
@Entity
@Table(name = "system_shiro_role")
public class Role extends BaseEntity { @Column(unique = true)
private String name; //角色名 唯一
private String description; //描述信息
@ManyToMany(fetch= FetchType.EAGER)
private List<Permission> permissions; //一个用户角色对应多个权限
//省略getter/setter
}

3 . User类(用户),一个用户拥有一个或者多个角色 :


/**
* Created by EalenXie on 2019/3/25 11:01.
* <p>
* 用户表(User) 用户下面对应多个角色
*/
@Entity
@Table(name = "system_shiro_user")
public class User extends BaseEntity {
@Column(unique = true)
private String username;//用户名 唯一
private String password;//用户密码
private String passwordSalt;//用户密码加密盐值
@ManyToMany(fetch = FetchType.EAGER)
private List<Role> roles;//用户角色 一个用户可能有一个角色,也可能有 多个角色
//省略getter/setter
}

2 . 基本配置信息 :

1 . 配置应用的基本信息,application.yml :


server:
port: 8082
spring:
application:
name: shiro-rbac-system
resources:
static-locations: classpath:/
freemarker:
template-loader-path: classpath:/templates/
suffix: .html
content-type: text/html
charset: UTF-8
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/yourdatabase?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8&useSSL=true
username: yourname
password: yourpass
jpa:
# show-sql: true
hibernate:
ddl-auto: update
open-in-view: false # 禁用 OSIV <Spring Boot中默认启用了OSIV(Open Session in View)>
http:
encoding:
charset: utf-8
enabled: true

2 . 配置JPA,基本的数据库访问Dao。


public interface PermissionRepository extends JpaRepository<Permission, Integer> {
Permission findByName(String name);
}

public interface RoleRepository extends JpaRepository<Role, Integer> {
Role findByName(String name);
}


public interface UserRepository extends JpaRepository<User, Integer> {
User findByUsername(String username);
}

3 . 配置shiro,基于角色访问控制权限的核心Realm,UserAuthRealm :


@Component
public class UserAuthRealm extends AuthorizingRealm { @Resource
private UserRepository userRepository; /**
* 权限核心配置 根据数据库中的该用户 角色 和 权限
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
User user = (User) principals.getPrimaryPrincipal();
for (Role role : user.getRoles()) { //获取 角色
authorizationInfo.addRole(role.getName()); //添加 角色
for (Permission permission : role.getPermissions()) { //获取 权限
authorizationInfo.addStringPermission(permission.getName());//添加 权限
}
}
return authorizationInfo;
} /**
* 用户登陆 凭证信息
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String username = (String) token.getPrincipal();
User user = userRepository.findByUsername(username);
if (user == null) return null;
String credentials = user.getPasswordSalt() + user.getUsername() + user.getPasswordSalt();//自定义加盐 salt + username + salt
return new SimpleAuthenticationInfo(
user, //用户名
user.getPassword(), //密码
ByteSource.Util.bytes(credentials), //加密
getName() //realm name
);
} /**
* 设置 realm的 HashedCredentialsMatcher
*/
@PostConstruct
public void setHashedCredentialsMatcher() {
this.setCredentialsMatcher(hashedCredentialsMatcher());
} /**
* 凭证匹配 : 指定 加密算法,散列次数
*/
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher() {
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
hashedCredentialsMatcher.setHashAlgorithmName("md5");//散列算法:这里使用MD5算法;
hashedCredentialsMatcher.setHashIterations(1024);//散列的次数,比如散列两次,相当于 md5(md5(""));
return hashedCredentialsMatcher;
}
}

4 . shiro核心配置,包含基本过滤器策略,注解支持等。


/**
* Created by EalenXie on 2019/3/25 15:12.
*/
@Configuration
public class ShiroConfig { @Resource
private PermissionRepository permissionRepository; @Resource
private UserAuthRealm userAuthRealm; /**
* 配置 资源访问策略 . web应用程序 shiro核心过滤器配置
*/
@Bean
public ShiroFilterFactoryBean factoryBean(SecurityManager securityManager) {
ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
factoryBean.setSecurityManager(securityManager);
factoryBean.setLoginUrl("/login");//登录页
factoryBean.setSuccessUrl("/index");//首页
factoryBean.setUnauthorizedUrl("/unauthorized");//未授权界面;
factoryBean.setFilterChainDefinitionMap(setFilterChainDefinitionMap()); //配置 拦截过滤器链
return factoryBean;
} /**
* 配置 SecurityManager,可配置一个或多个realm
*/
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(userAuthRealm);
// securityManager.setRealm(xxxxRealm);
return securityManager;
} /**
* 开启shiro 注解支持. 使以下注解能够生效 :
* 需要认证 {@link org.apache.shiro.authz.annotation.RequiresAuthentication RequiresAuthentication}
* 需要用户 {@link org.apache.shiro.authz.annotation.RequiresUser RequiresUser}
* 需要访客 {@link org.apache.shiro.authz.annotation.RequiresGuest RequiresGuest}
* 需要角色 {@link org.apache.shiro.authz.annotation.RequiresRoles RequiresRoles}
* 需要权限 {@link org.apache.shiro.authz.annotation.RequiresPermissions RequiresPermissions}
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
} /**
* 配置 拦截过滤器链. map的键 : 资源地址 ; map的值 : 所有默认Shiro过滤器实例名
* 默认Shiro过滤器实例 参考 : {@link org.apache.shiro.web.filter.mgt.DefaultFilter}
*/
private Map<String, String> setFilterChainDefinitionMap() {
Map<String, String> filterMap = new LinkedHashMap<>();
//注册 数据库中所有的权限 及其对应url
List<Permission> allPermission = permissionRepository.findAll();//数据库中查询所有权限
for (Permission p : allPermission) {
filterMap.put(p.getUrl(), "perms[" + p.getName() + "]"); //拦截器中注册所有的权限
}
filterMap.put("/static/**", "anon"); //公开访问的资源
filterMap.put("/open/api/**", "anon"); //公开接口地址
filterMap.put("/logout", "logout"); //配置登出页,shiro已经帮我们实现了跳转
filterMap.put("/**", "authc"); //所有资源都需要经过验证
return filterMap;
}
}

5 . 用于授权相关注解进行测试的API RestController。AuthorizationApiFacade :


/**
* Created by EalenXie on 2019/3/26 16:46.
* 授权相关API 测试
*/
@RestController
public class AuthorizationApiFacade { /**
* 需要 验证 才能访问的api
*/
@RequestMapping("/requiresAuthentication")
@RequiresAuthentication
public Map<String, String> requiresAuthentication() {
Map<String, String> result = new HashMap<>();
result.put("msg", "Require Authentication : 需要认证 测试, 能够访问此接口");
return result;
} /**
* 需要 用户 身份才能访问的api
*/
@RequiresUser
@RequestMapping("/requiresUser")
public Map<String, String> requiresUser() {
Map<String, String> result = new HashMap<>();
result.put("msg", "Require User : 需要用户 测试, 能够访问此接口");
return result;
} /**
* 需要 Guest 身份才能访问的api
*/
@RequiresGuest
@RequestMapping("/requiresGuest")
public Map<String, String> requiresGuest() {
Map<String, String> result = new HashMap<>();
result.put("msg", "Require Guest : 需要认证 测试, 能够访问此接口");
return result;
} /**
* 需要 administrator 角色才能访问的api
*/
@RequiresRoles("administrator")
@RequestMapping("/requiresRoles")
public Map<String, String> requiresRoles() {
Map<String, String> result = new HashMap<>();
result.put("msg", "require Roles : 该用户具有 administrator 角色, 能够访问此接口");
return result;
} /**
* 需要 add 权限才能访问的api
*/
@RequiresPermissions("add")
@RequestMapping("/requiresPermissionsAdd")
public Map<String, String> requiresPermissionsAdd() {
Map<String, String> result = new HashMap<>();
result.put("msg", "require Permissions : 该用户具有 add 权限 , 能够访问此接口");
return result;
} /**
* 需要 delete 权限才能访问的api
*/
@RequiresPermissions("delete")
@RequestMapping("/requiresPermissionsDelete")
public Map<String, String> requiresPermissionsDelete() {
Map<String, String> result = new HashMap<>();
result.put("msg", "require Permissions : 该用户具有 delete 权限 , 能够访问此接口");
return result;
} /**
* 公开接口
*/
@RequestMapping(value = "/open/api/sayHello", method = RequestMethod.POST)
public Map<String, String> sayHello() {
Map<String, String> result = new HashMap<>();
result.put("msg", "这个是公开接口,谁都可以访问");
return result;
}
}

进行测试,用户登陆(zhangsan)测试,zhangsan只具有user角色,只有部分权限。

SpringBoot整合Shiro实现基于角色的权限访问控制(RBAC)系统简单设计从零搭建

登陆成功后,进入到首页。

SpringBoot整合Shiro实现基于角色的权限访问控制(RBAC)系统简单设计从零搭建

访问,/add 则跳转到 新增页面

SpringBoot整合Shiro实现基于角色的权限访问控制(RBAC)系统简单设计从零搭建

访问/delete,因为没有权限会跳转到未授权页面。

SpringBoot整合Shiro实现基于角色的权限访问控制(RBAC)系统简单设计从零搭建

zhangsan只能调用自己拥有角色和权限的api :

SpringBoot整合Shiro实现基于角色的权限访问控制(RBAC)系统简单设计从零搭建

SpringBoot整合Shiro实现基于角色的权限访问控制(RBAC)系统简单设计从零搭建

没有相关角色和权限的api不能调用 :

SpringBoot整合Shiro实现基于角色的权限访问控制(RBAC)系统简单设计从零搭建

SpringBoot整合Shiro实现基于角色的权限访问控制(RBAC)系统简单设计从零搭建的更多相关文章

  1. RBAC基于角色的权限访问控制

      RBAC是什么,能解决什么难题?ThinkPHP中RBAC实现体系安全拦截器认证管理器访问决策管理运行身份管理器ThinkPHP中RBAC认证流程权限管理的具体实现过程RBAC相关的数据库介绍Th ...

  2. RABC&lpar;Role-Based Access Control&rpar; 基于角色的权限访问控制

    基于角色的权限访问控制(Role-Based Access Control),通过角色绑定权限,然后给用户划分角色.在web应用中,可以将权限理解为url,一个权限对应一个url. 使用thinkph ...

  3. devops-jenkins基于角色的权限管理RBAC

    一. devops-jenkins基于角色的权限管理RBAC 1 安装角色的rbac角色管理  1.1) 点击系统管理 1.2) 选择插件管理 1.3) 选择可选插件,输入role搜索 1.4) 选择 ...

  4. springboot整合security实现基于url的权限控制

    权限控制基本上是任何一个web项目都要有的,为此spring为我们提供security模块来实现权限控制,网上找了很多资料,但是提供的demo代码都不能完全满足我的需求,因此自己整理了一版. 在上代码 ...

  5. RBAC&lpar;Role-Based Access Control&comma;基于角色的权限访问控制&rpar;—权限管理设计

    RBAC模型的核心是在用户和权限之间引入了角色的概念,将用户和权限进行解耦,采用用户确定角色,角色分配权限,进而间接达到给用户分配角色的目的 这样采用的方式优点在于 (1)降低管理成本--由于一个角色 ...

  6. ASP&period;NET MVC 基于角色的权限控制系统的示例教程

    上一次在 .NET MVC 用户权限管理示例教程中讲解了ASP.NET MVC 通过AuthorizeAttribute类的OnAuthorization方法讲解了粗粒度控制权限的方法,接下来讲解基于 ...

  7. ASP&period;net MVC 基于角色的权限控制系统的实现

    一.引言 我们都知道ASP.net mvc权限控制都是实现AuthorizeAttribute类的OnAuthorization方法. 下面是最常见的实现方式: public class Custom ...

  8. spring boot shiro redis整合基于角色和权限的安全管理-Java编程

    一.概述 本博客主要讲解spring boot整合Apache的shiro框架,实现基于角色的安全访问控制或者基于权限的访问安全控制,其中还使用到分布式缓存redis进行用户认证信息的缓存,减少数据库 ...

  9. SpringBoot整合Shiro权限框架实战

    什么是ACL和RBAC ACL Access Control list:访问控制列表 优点:简单易用,开发便捷 缺点:用户和权限直接挂钩,导致在授予时的复杂性,比较分散,不便于管理 例子:常见的文件系 ...

随机推荐

  1. CSS魔法堂:&quot&semi;那不是bug,是你不懂我&excl;&quot&semi; by inline-block

    前言  每当来个需要既要水平排版又要设置固定高宽时,我就会想起display:inline-block,还有为了支持IE5.5/6/7的hack*display:inline;*zoom:1;.然后发 ...

  2. DFTX 笔试

    char aa[8] = "abcd"; printf("%d",strlen(aa));  4 printf("%d",sizeof(aa ...

  3. volatile关键字解析

    转载:http://www.cnblogs.com/dolphin0520/p/3920373.html volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受 ...

  4. UVa 247 Calling Circles【传递闭包】

    题意:给出n个人的m次电话,问最后构成多少个环,找出所有的环 自己想的是:用map来储存人名,每个人名映射成一个数字编号,再用并查集,求出有多少块连通块,输出 可是map不熟,写不出来,而且用并查集输 ...

  5. Open quote is expected for attribute &quot&semi;&lbrace;1&rcub;&quot&semi; associated with an element type &quot&semi;name&quot&semi;&period;

    xml属性必须用引号“”,不能缺少.

  6. windows appfabric samples

    http://www.microsoft.com/en-us/download/details.aspx?id=19603 http://msdn.microsoft.com/zh-cn/librar ...

  7. mysql 修改max&lowbar;allowed&lowbar;packet

    -- 查询max_allowed_packetshow VARIABLES like '%max_allowed_packet%'; 修改 my.ini 或 my.cnf [mysqld] max_a ...

  8. 找工作笔试面试那些事儿&lpar;8&rpar;---常问的CC&plus;&plus;基础题

    这一部分是C/C++程序员在面试的时候会被问到的一些题目的汇总.来源于基本笔试面试书籍,可能有一部分题比较老,但是这也算是基础中的基础,就归纳归纳放上来了.大牛们看到一笑而过就好,普通人看看要是能补上 ...

  9. C&plus;&plus; 对象成员函数(非静态方法)

    1.神奇的inline语法与语义 inline语义C99和C++98都有.之前在单源文件编写的时候一直没有发现问题,但是一考虑到多文件的链接,就发现矛盾了. 一些inline的原则: 1. inlin ...

  10. js object数据类型

    1.object数据类型,[可以]认为JavaScript中*数据类型.在JavaScript绝大多数 高级类型对象都是object类型 2.如何创建一个object类型对象 1) 通过调用Obje ...