在程序的执行过程中,有时有这么一种需求,需要动态的更新某些角色的权限或某些人对应的权限,当前在线的用户拥有这个角色或拥有这个权限时,在不退出系统的情况下,需要动态的改变的他所拥有的权限。

需求:张三 登录了系统拥有 ROLE_ADMIN,和ROLE_USER 的权限,但是ROLE_ADMIN的权限太强了,不应该给张三,后台管理人员应该可以取消张三的ROLE_ADMIN的权限,那么在张三还在线且没有退出系统的情况下应该不可以继续访问ROLE_ADMIN的权限的资源。

解决思路:

1、监听系统中所有的在线用户,需要监听session的创建和销毁事件

2、spring secuirty在登录成功后为了防止session的固化攻击会改变sessionId的值,因此需要监听spring security发布的 SessionFixationProtectionEvent事件

3、当我们系统中的资源发生了改变时,需要发布自己的一个资源改变事件,在此事件中修改当前在线用户的权限。

大致步骤如下:

一、拿到系统中所有的在线用户对象

|-  将 HttpSessionEventPublisher 注册成一个listener,注册之后就可以监听到session的创建和销毁事件

/**
* 注册Servlet Listener,用于发布Session的创建和销毁事件
*/
@Bean
public ServletListenerRegistrationBean httpSessionEventPublisher() {
ServletListenerRegistrationBean<HttpSessionEventPublisher> registration = new ServletListenerRegistrationBean<>();
registration.setListener(new HttpSessionEventPublisher());
return registration;
}

|- 监听session的创建事件(HttpSessionCreatedEvent),在这一步需要保存session对象

/**
* 监听session创建对象
*/
@Component
@Slf4j
class HttpSessionCreatedEventListener implements ApplicationListener<HttpSessionCreatedEvent> { @Override
public void onApplicationEvent(HttpSessionCreatedEvent event) {
log.info("新建session:{}", event.getSession().getId());
try {
// 保存 session
} catch (Exception e) {
log.info(String.format("添加session:[%s]出现异常.", event.getSession().getId()), e);
}
}
}

|- 监听session的销毁事件(HttpSessionDestroyedEvent),此事件主要是移除没有的session对象

/**
* 监听session失效事件
*/
@Component
@Slf4j
class SessionDestroyedEventListener implements ApplicationListener<HttpSessionDestroyedEvent> { @Override
public void onApplicationEvent(HttpSessionDestroyedEvent event) {
log.info("失效session:{}", event.getSession().getId());
try {
// 移除session
} catch (Exception e) {
log.error(String.format("失效session:[%s]发生异常.", event.getId()), e);
}
}
}

|- 保存系统中所有的session对象

二、监听SessionFixationProtectionEvent事件,这个主要是spring security为了防止session的固化攻击,在用户登录成功后,会修改用户的sessionId的值,并发布此事件,需要在此监听,不然上一步保存的session中的sessionId的值是有问题的。

注:可以查看org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter#sessionStrategy这个

/**
* @author huan.fu
* Spring security 登录成功后,防止session的固化攻击,会将旧的sessionId销毁,重新生成一个新的sessionId,
* 因此此处需要做一下处理
*/
@Component
class SessionFixationProtectionEventListener implements ApplicationListener<SessionFixationProtectionEvent> {
@Override
public void onApplicationEvent(SessionFixationProtectionEvent event) {
String oldSessionId = event.getOldSessionId();
String newSessionId = event.getNewSessionId();
// 更改sessionId的值
}
}

三、当系统中的资源发生改变时,修改当前在线用户的资源

有了上面2步的基础,可以获取到当前所有在线的用户对象,当我们自己系统中的资源发生了改变的时候,比如给用户增加了一个新的角色,删除了用户的一个角色,或者给角色新增加或删除了资源时,我们就可以对当前当前用户做一些处理(比如过滤没有这个权限的用户,当session还是新建的时候的处理等),来动态更新用户的权限。

获取当前用户信息:

1、从session中获取:

SecurityContext securityContext = (SecurityContext) session.getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY);
Object principal = securityContext.getAuthentication().getPrincipal();

2、重新加载当前用户的资源

/**
* 重新加载用户的权限
*
* @param session
*/
private void reloadUserAuthority(HttpSession session) { // 新的权限
List<GrantedAuthority> authorityList = AuthorityUtils.createAuthorityList(new String[]{"从数据库中查询出来"}); SecurityContext securityContext = (SecurityContext) session.getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY);
Authentication authentication = securityContext.getAuthentication();
SecurityUser principal = (SecurityUser) authentication.getPrincipal();
principal.setAuthorities(authorityList); // 重新new一个token,因为Authentication中的权限是不可变的.
UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(
principal, authentication.getCredentials(),
authorityList);
result.setDetails(authentication.getDetails());
securityContext.setAuthentication(result);
}

到此,应该就可以实现动态的修改在线用户的权限信息了。

注意:上面的代码有些是不全的,但是大致思路是这样的。

spring security中动态更新用户的权限的更多相关文章

  1. 在realm中动态查询用户的权限&角色

    @Controller @Scope("prototype") @Namespace("/") @ParentPackage("struts-defa ...

  2. 项目一:第十三天 1、菜单数据管理 2、权限数据管理 3、角色数据管理 4、用户数据管理 5、在realm中动态查询用户权限,角色 6、Shiro中整合ehcache缓存权限数据

    1 课程计划 菜单数据管理 权限数据管理 角色数据管理 用户数据管理 在realm中动态查询用户权限,角色 Shiro中整合ehcache缓存权限数据         2 菜单数据添加 2.1 使用c ...

  3. Spring Security之动态配置资源权限

    在Spring Security中实现通过数据库动态配置url资源权限,需要通过配置验证过滤器来实现资源权限的加载.验证.系统启动时,到数据库加载系统资源权限列表,当有请求访问时,通过对比系统资源权限 ...

  4. SpringBoot Spring Security 核心组件 认证流程 用户权限信息获取详细讲解

    前言 Spring Security 是一个安全框架, 可以简单地认为 Spring Security 是放在用户和 Spring 应用之间的一个安全屏障, 每一个 web 请求都先要经过 Sprin ...

  5. spring security实现动态配置url权限的两种方法

    缘起 标准的RABC, 权限需要支持动态配置,spring security默认是在代码里约定好权限,真实的业务场景通常需要可以支持动态配置角色访问权限,即在运行时去配置url对应的访问角色. 基于s ...

  6. [收藏]Spring Security中的ACL

    ACL即访问控制列表(Access Controller List),它是用来做细粒度权限控制所用的一种权限模型.对ACL最简单的描述就是两个业务员,每个人只能查看操作自己签的合同,而不能看到对方的合 ...

  7. 基于spring security 实现前后端分离项目权限控制

    前后端分离的项目,前端有菜单(menu),后端有API(backendApi),一个menu对应的页面有N个API接口来支持,本文介绍如何基于spring security实现前后端的同步权限控制. ...

  8. 看源码,重新审视Spring Security中的角色(roles)是怎么回事

    在网上看见不少的博客.技术文章,发现大家对于Spring Security中的角色(roles)存在较大的误解,最大的误解就是没有搞清楚其中角色和权限的差别(好多人在学习Spring Security ...

  9. springBoot整合spring security+JWT实现单点登录与权限管理--筑基中期

    写在前面 在前一篇文章当中,我们介绍了springBoot整合spring security单体应用版,在这篇文章当中,我将介绍springBoot整合spring secury+JWT实现单点登录与 ...

随机推荐

  1. error: object file .git/objects/...

    cd .git find . -type f -empty -delete -print tail -n 2 .git/logs/refs/heads/master git show xxxx(版本号 ...

  2. ubuntu14.04 安装MySQL 5.7

    ubuntu14.04 默认在线安装MySQL 5.5 1) wget http://dev.mysql.com/get/mysql-apt-config_0.7.3-1_all.deb 2) dpk ...

  3. jq 追加元素的几种方法

    jQuery添加插入元素技巧: jquery添加分为在指定元素的里面添加和外面添加两种: 里面添加使用(append 和prepend) 里面添加又分为在里面的前面添加和后面添加 里面的前面添加使用 ...

  4. 文件包含上传漏洞&目录遍历命令执行漏洞

    文件上传漏洞: 一句话木马 一句话木马主要由两部分组成:执行函数与 接收被执行代码的变量 执行函数: eval() assert() create_function() array_map() arr ...

  5. 支持Cron表达式、间隔时间的工具(TaskScheduler)

    后台任务如何支持间隔时间.Cron表达式两种方式? 分享一个项目TaskScheduler,这是我从Furion项目中拷出来的 源码:https://gitee.com/dot-net-core/ta ...

  6. Spring Boot 2.x 之 Spring Data JPA, Hibernate 5

    1. Spring Boot常用配置项 基于Spring Boot 2.0.6.RELEASE 1.1 配置属性类 spring.jpa前缀的相关配置项定义在JpaProperties类中, 1.2 ...

  7. SpringBoot系列——附件管理:整合业务表单实现上传、回显、下载

    前言 日常开发中,大多数项目都会涉及到附件上传.回显.下载等功能,本文记录封装通用附件管理模块,并与业务模块进行整合实现上传.回显.下载 我们之前已经对文件上传下载有过记录,传送门:基于"f ...

  8. 【简单数据结构】二叉树的建立和递归遍历--洛谷 P1305

    题目描述 输入一串二叉树,用遍历前序打出. 输入格式 第一行为二叉树的节点数n.(n \leq 26n≤26) 后面n行,每一个字母为节点,后两个字母分别为其左右儿子. 空节点用*表示 输出格式 前序 ...

  9. 38KHz,NEC红外模拟发送和接收程序

    /*************************************************************************************************/ ...

  10. PHP中的强制类型转换

    学过静态语言开发的朋友对类型转换不会陌生,比如Java.C#.C++等.静态语言的好处就是变量强制必须指定类型,这也是编译的要求,所以大部分编译型的语言都会有强制变量类型的要求.而PHP据说也会在PH ...