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,实现权限的管理. 在这之前,假定你已经了解了基于资源的权限管理模型 ...
随机推荐
- Oracle 查询练习
非常经典的一些日常醒脑练习内容!! 如有更高效的写法欢迎赐教! .已知Oracle的Scott用户中提供了三个测试数据库表,名称分别为dept,emp和salgrade.使用SQL语言完成以下操作 ) ...
- 网格弹簧质点系统模拟(Spring-Mass System by Fast Method)附源码(转载)
转载: https://www.cnblogs.com/shushen/p/5311828.html 弹簧质点模型的求解方法包括显式欧拉积分和隐式欧拉积分等方法,其中显式欧拉积分求解快速,但积分步长 ...
- .net post请求webservice
class Program { static void Main(string[] args) { , name = "jxp" }); var a = HttpHelper.Po ...
- NET 已知excel表格前面26个是a到z,27是aa28是ab,以此类推,N是多少
问题: 已知excel表格前面26个是a到z,27是aa28是ab,以此类推,N是多少 代码: /// <summary> /// 已知excel表格前面26个是a到z,27是aa28是a ...
- The connection string name is missing for the MySqlSiteMapProvider
在ASP.NET-WebForm程序中,添加SiteMapPath控件时出现问题,如下图所示: 解决办法:找到上图源文件指向的machine.config配置文件,将siteMap节点注释即可.
- putty连接centos慢
用的vmware下的centos minimal镜像,开发时,用putty连接很慢,一分多钟, 解决方案: 禁用GSSAPI认证有两个方式:客户端和服务端 直接配置你ssh客户端的文件/etc/ssh ...
- Struts2框架简单介绍
如需,了解Struts2详情,请点击,传送门 工作原理 在Struts2 框架中的处理大概分为以下步骤: 1.客户端初始化一个指向servlet容器(例如Tomcat)的请求. 2.这个请求经过一系列 ...
- Linux管道及重定向
Linux管道及重定向 对shell有一定了解的人都知道,管道和重定向是 Linux 中非常实用的 IPC 机制.在shell中,我们通常使用符合'|'来表示管道,符号'>'和'<'表示重 ...
- Redis事务控制
Redis事务控制 1.Redis事务控制的相关命令汇总 命令名 作用 MULTI 表示开始收集命令,后面所有命令都不是马上执行,而是加入到一个队列中. EXEC 执行MULTI后面命令队列中的所有命 ...
- React入门(二)
组件的生命周期 概念:在组件创建.到加载到页面运行.以及组件被销毁的过程中伴随的事件.组件的生命周期是指在组件的特定时期触发的事件. 组件的生命周期分为三个部分: 组件创建阶段:只执行一次 compo ...