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,实现权限的管理. 在这之前,假定你已经了解了基于资源的权限管理模型 ...
随机推荐
- 截图自动添加水印图片工具 pickpick设置中文语言
推荐一款截图工具,主要是可以截图自动带水印,效果不错 最近发现我的不少文章被转载的到处都是.乱七八糟,这个功能后续准备做个水印用起来,感觉不错 主角介绍 首先介绍下主角 PickPick
- Elasticsearch 中映射参数doc_values 和 fielddata分析比较
doc_values 默认情况下,大部分字段是索引的,这样让这些字段可被搜索.倒排索引(inverted index)允许查询请求在词项列表中查找搜索项(search term),并立即获得包含该词项 ...
- .Net常见的IOC框架及AOP框架
IOC框架 Unity:微软patterns&practicest团队开发的IOC依赖注入框架,支持AOP横切关注点. MEF(Managed Extensibility Framework) ...
- deepin把vscode设为默认文本应用
一开始我想自己写一个desktop文件放在/usr/share/applications下面,结果在右键菜单里面找不到vscode. [Desktop Entry] Categories=Develo ...
- Vue Stomp+SocketJS 数据报错[Object object]
开头一句mmp tmd换位置了也没个提示!!!! 坑死爹了 <template> <div> <input type="text" v-model=& ...
- Git内部原理浅析
Git独特之处 Git是一个分布式版本控制系统,首先分布式意味着Git不仅仅在服务端有远程仓库,同时会在本地也保留一个完整的本地仓库(.git/文件夹),这种分布式让Git拥有下面几个特点: 1.直接 ...
- Mac下多版本pip共存
Mac下多版本pip共存 来自于官方的解释, pip是python包管理工具, 该工具提供了对python包的查找, 下载, 安装, 卸载等功能python第三方工具包多数依赖于pip进行安装, 如 ...
- 21个React开发神器
摘要: React开发神器. 原文:22 Miraculous Tools for React Developers in 2019 译者:前端小智 下列工具中的重要性与排序无关. 1.Webpack ...
- 基于Anaconda编译caffe+pycaffe+matcaffe in Ubuntu[不用sudo权限]
目录 caffe 编译 环境 github下载caffe源码 依赖 修改源码的编译配置 报错 测试使用 pycaffe caffe matcaffe caffe 编译 环境 Ubuntu16.04 C ...
- C++学习03_引用
基本使用 C++提供了给变量命名的机制,就是引用(Reference).引用是一种复合类型. //语法 数据类型 &name=data 注意,引用在定义时需要添加&,在使用时不能添加& ...