SpringBoot集成Spring Security(5)——权限控制
在第一篇中,我们说过,用户<–>角色<–>权限三层中,暂时不考虑权限,在这一篇,是时候把它完成了。
为了方便演示,这里的权限只是对角色赋予权限,也就是说同一个角色的用户,权限是一样的。当然了,你也可以精细化到为每一个用户设置权限,但是这不在本篇的探讨范围,有兴趣可以自己实验,原理都是一样的。
源码地址:https://github.com/jitwxs/blog_sample
文章目录
一、数据准备
- 1.1 创建 sys_permission 表
- 1.2 创建 POJO、Mapper、Service
- 1.3 修改接口
二、PermissionEvaluator
三、运行程序
一、数据准备
1.1 创建 sys_permission 表
让我们先创建一张权限表,名为 sys_permission:
CREATE TABLE `sys_permission` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`url` varchar(255) DEFAULT NULL,
`role_id` int(11) DEFAULT NULL,
`permission` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `fk_roleId` (`role_id`),
CONSTRAINT `fk_roleId` FOREIGN KEY (`role_id`) REFERENCES `sys_role` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
内容就是两条数据,url+role_id+permission 唯一标识了一个角色访问某一 url 时的权限,其中权限暂定为 c、r、u、d,即增删改查。
1.2 创建 POJO、Mapper、Service
(1)pojo
package jit.wxs.entity; import java.io.Serializable;
import java.util.Arrays;
import java.util.List; /**
* 权限实体类
* @author jitwxs
* @since 2018/5/15 18:11
*/
public class SysPermission implements Serializable {
static final long serialVersionUID = 1L; private Integer id; private String url; private Integer roleId; private String permission; private List permissions; // 省略除permissions外的getter/setter public List getPermissions() {
return Arrays.asList(this.permission.trim().split(","));
} public void setPermissions(List permissions) {
this.permissions = permissions;
}
}
这里需要注意的时相比于数据库,多了一个 permissions 属性,该字段将 permission 按逗号分割为了 list。
(2)mapper
import jit.wxs.entity.SysPermission;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select; import java.util.List; @Mapper
public interface SysPermissionMapper {
@Select("SELECT * FROM sys_permission WHERE role_id=#{roleId}")
List<SysPermission> listByRoleId(Integer roleId);
}
(3)Service
package jit.wxs.service; import jit.wxs.entity.SysPermission;
import jit.wxs.mapper.SysPermissionMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import java.util.List; @Service
public class SysPermissionService {
@Autowired
private SysPermissionMapper permissionMapper; /**
* 获取指定角色所有权限
*/
public List<SysPermission> listByRoleId(Integer roleId) {
return permissionMapper.listByRoleId(roleId);
}
}
Service中 有一个方法,根据 roleId 获取所有的 SysPermission
1.3 修改接口
@Controller
public class LoginController {
... @RequestMapping("/admin")
@ResponseBody
@PreAuthorize("hasPermission('/admin','r')")
public String printAdminR() {
return "如果你看见这句话,说明你访问/admin路径具有r权限";
} @RequestMapping("/admin/c")
@ResponseBody
@PreAuthorize("hasPermission('/admin','c')")
public String printAdminC() {
return "如果你看见这句话,说明你访问/admin路径具有c权限";
}
}
让我们修改下我们要访问的接口,@PreAuthorize("hasPermission('/admin','r')")是关键,参数1指明了访问该接口需要的url,参数2指明了访问该接口需要的权限。
二、PermissionEvaluator
我们需要自定义对 hasPermission() 方法的处理,就需要自定义 PermissionEvaluator,创建类 CustomPermissionEvaluator,实现 PermissionEvaluator 接口。
import jit.wxs.entity.SysPermission;
import jit.wxs.service.SysPermissionService;
import jit.wxs.service.SysRoleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Component; import java.io.Serializable;
import java.util.Collection;
import java.util.List; @Component
public class CustomPermissionEvaluator implements PermissionEvaluator {
@Autowired
private SysPermissionService permissionService;
@Autowired
private SysRoleService roleService; @Override
public boolean hasPermission(Authentication authentication, Object targetUrl, Object targetPermission) { /**
* authentication.getPrincipal()返回的是字符串而不是User对象 -》主要是因为构造Token的参数出错了,
* 在《SpringBoot集成Spring Security(4)——自定义表单登录》中,
* 实现AuthenticationProvider接口的authenticate()方法的返回值应该改成
* return new UsernamePasswordAuthenticationToken(userDetails, inputPassword, userDetails.getAuthorities());
* 就是将inputName改成userDetails(就是用户对象)
*/
// 获得loadUserByUsername()方法的结果
// User user = (User)authentication.getPrincipal();
// 获得loadUserByUsername()中注入的角色
// Collection<GrantedAuthority> authorities = user.getAuthorities();
//也可以使用authentication.getAuthorities()方法来获取对象
Collection<GrantedAuthority> authorities = (Collection<GrantedAuthority>) authentication.getAuthorities(); // 遍历用户所有角色
for(GrantedAuthority authority : authorities) {
String roleName = authority.getAuthority();
Integer roleId = roleService.selectByName(roleName).getId();
// 得到角色所有的权限
List<SysPermission> permissionList = permissionService.listByRoleId(roleId); // 遍历permissionList
for(SysPermission sysPermission : permissionList) {
// 获取权限集
List permissions = sysPermission.getPermissions();
// 如果访问的Url和权限用户符合的话,返回true
if(targetUrl.equals(sysPermission.getUrl())
&& permissions.contains(targetPermission)) {
return true;
}
} } return false;
} @Override
public boolean hasPermission(Authentication authentication, Serializable serializable, String s, Object o) {
return false;
}
}
在 hasPermission() 方法中,参数 1 代表用户的权限身份,参数 2 参数 3 分别和 @PreAuthorize("hasPermission('/admin','r')") 中的参数对应,即访问 url 和权限。
思路如下:
- 通过 Authentication 取出登录用户的所有 Role
- 遍历每一个 Role,获取到每个Role的所有 Permission
- 遍历每一个 Permission,只要有一个 Permission 的 url 和传入的url相同,且该 Permission 中包含传入的权限,返回 true
- 如果遍历都结束,还没有找到,返回false
下面就是在 WebSecurityConfig 中注册 CustomPermissionEvaluator:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
...
/**
* 注入自定义PermissionEvaluator
*/
@Bean
public DefaultWebSecurityExpressionHandler webSecurityExpressionHandler(){//方法名称webSecurityExpressionHandler如果和SpringSecurity原本的方法名有冲突,可以更换该名称
DefaultWebSecurityExpressionHandler handler = new DefaultWebSecurityExpressionHandler();
handler.setPermissionEvaluator(new CustomPermissionEvaluator());
return handler;
}
...
}
三、运行程序
当我使用角色为 ROLE_USER 的用户仍然能访问,因为该用户访问 /admin 路径具有 r 权限:
---------------------
作者:Jitwxs
来源:CSDN
原文:https://blog.csdn.net/yuanlaijike/article/details/80327880
SpringBoot集成Spring Security(5)——权限控制的更多相关文章
- SpringBoot集成Spring Security入门体验
一.前言 Spring Security 和 Apache Shiro 都是安全框架,为Java应用程序提供身份认证和授权. 二者区别 Spring Security:重量级安全框架 Apache S ...
- request.getRemoteUser() Spring Security做权限控制后
一. request.getRemoteUser();//获取当前缓存的用户,比如Spring Security做权限控制后就会将用户登录名缓存到这里 request.getRemoteAddr(); ...
- SpringBoot集成Spring Security(7)——认证流程
文章目录 一.认证流程 二.多个请求共享认证信息 三.获取用户认证信息 在前面的六章中,介绍了 Spring Security 的基础使用,在继续深入向下的学习前,有必要理解清楚 Spring Sec ...
- SpringBoot集成Spring Security(6)——登录管理
文章目录 一.自定义认证成功.失败处理 1.1 CustomAuthenticationSuccessHandler 1.2 CustomAuthenticationFailureHandler 1. ...
- SpringBoot集成Spring Security(4)——自定义表单登录
通过前面三篇文章,你应该大致了解了 Spring Security 的流程.你应该发现了,真正的 login 请求是由 Spring Security 帮我们处理的,那么我们如何实现自定义表单登录呢, ...
- SpringBoot集成Spring Security(2)——自动登录
在上一章:SpringBoot集成Spring Security(1)——入门程序中,我们实现了入门程序,本篇为该程序加上自动登录的功能. 文章目录 一.修改login.html二.两种实现方式 2. ...
- SpringBoot集成Spring Security
1.Spring Security介绍 Spring security,是一个强大的和高度可定制的身份验证和访问控制框架.它是确保基于Spring的应用程序的标准 --来自官方参考手册 Spring ...
- SpringBoot 集成Spring security
Spring security作为一种安全框架,使用简单,能够很轻松的集成到springboot项目中,下面讲一下如何在SpringBoot中集成Spring Security.使用gradle项目管 ...
- springBoot整合spring security实现权限管理(单体应用版)--筑基初期
写在前面 在前面的学习当中,我们对spring security有了一个小小的认识,接下来我们整合目前的主流框架springBoot,实现权限的管理. 在这之前,假定你已经了解了基于资源的权限管理模型 ...
随机推荐
- Vue.js安装及环境搭建
Vue.js环境搭建-Windows版 步骤一:安装node.js 在搭建vue的开发环境之前,需要先下载node.js,vue的运行是要依赖于node的npm的管理工具来实现,node可以在官网或者 ...
- 正式开放 | 阿里云 10 亿级镜像服务正式支持 Helm Charts,云原生交付再加速!
作者 | 阿里巴巴高级开发工程师 谢于宁(予栖) 2018 年 6 月,Helm 正式加入了 CNCF 孵化项目: 2018 年 8 月,据 CNCF 的调研表明,有百分之六十八的开发者选择了 Hel ...
- 【UOJ#61】【UR #5】怎样更有力气(最小生成树)
[UOJ#61][UR #5]怎样更有力气(最小生成树) 题面 UOJ 题解 最最最暴力的想法是把所有边给处理出来然后跑\(MST\). 考虑边权的情况,显然离线考虑,把么一天按照\(w_i\)进行排 ...
- Spring源码系列 — BeanDefinition
一.前言 回顾 在Spring源码系列第二篇中介绍了Environment组件,后续又介绍Spring中Resource的抽象,但是对于上下文的启动过程详解并未继续.经过一个星期的准备,梳理了Spri ...
- SqlServer 创建数据库两种方式
一个SqlServer 数据库实例大概可以创建三万多个数据库. 创建数据库的第一种方式:SqlServer Management Studio管理工具进行可视化创建. 1).打开数据库管理工具,在&q ...
- ASP.NET Core系列:读取配置文件
1. 控制台应用 新建一个控制台应用,添加两个Package: Install-Package Microsoft.Extensions.Configuration Install-Package M ...
- Git 合并单个文件
有两个分支 # git branch -a * branchA branchB remotes/origin/branchC A分支合并B分支单个文件 注意是本地分支,还是远程分支 # git che ...
- unlink remove
int unlink(const char *pathname); 删除一个文件的目录项并减少它的链接数 unlink()会删除参数pathname指定的文件.如果该文件名为最后连接点,但有其他进程打 ...
- AI 图像识别的测试
随着AI 的浪潮发展,AI 的应用场景越来越广泛,其中计算机视觉更是运用到我们生活中的方方面面.作为一个测试人员,需要紧跟上 AI 的步伐,快速从传统业务测试,转型到 AI 的测试上来.而人脸识别作为 ...
- 团队展示&选题 (白衣天使队)
作业详见此地址: https://www.cnblogs.com/bbplus/p/11735449.html