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

需求:张三 登录了系统拥有 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. HTML+CSS+JS设计注册页面

    HTML实战--设计一个个人信息填写界面 应用的技术:HTML+CSS+JS CSS和JS是套用的模板,主要练习了表单的验证和正则表达式的使用 效果图: 代码: <!DOCTYPE html&g ...

  2. 深入剖析RocketMQ源码-NameServer

    一.RocketMQ架构简介 1.1 逻辑部署图 (图片来自网络) 1.2 核心组件说明 通过上图可以看到,RocketMQ的核心组件主要包括4个,分别是NameServer.Broker.Produ ...

  3. Shell系列(4)- 历史命令

    格式:history [选项] [历史命令保存文件] 选项: -c:清空历史命令 -w:把缓存中的历史命令写入到历史命令保存文件~ /.bash_history;用户的家目录下 例子: [root@l ...

  4. Python return self

    在Python中,return self的作用为: Returning self from a method simply means that your method returns a refer ...

  5. pyqt5读取文本框内容,输出到日志框(QTextBrowser)

    import sys from PyQt5.QtWidgets import QApplication, QMainWindow, QAction,QLabel,QLineEdit,QPushButt ...

  6. nginx 配置文件(支持thnkphp3.2~5)

    server { listen 8080 ; server_name localhost; set $root /var/www/myweb; #listen 443 ssl; #ssl_certif ...

  7. 解决Windows 游戏 错误代码 1170000

    安装"Xbox标识提供程序" 下载地址:https://www.microsoft.com/store/apps/9wzdncrd1hkw

  8. cas的基础配置

    去除HTTPS的j基础认证方式 cas的:deployerConfigContext.xml <!-- Required for proxy ticket mechanism. -->&l ...

  9. 解除你学习Python自动化测试框架的所有疑惑,开启学习直通车

    学习框架第一步 前言 很多同学学完Python基础后出现迷茫......有同感的小伙伴,点赞关注........ 学习完Python还要学习什么? 什么是自动化测试框架? 如何搭建自动化测试框架? 甚 ...

  10. Ubuntu开发相关环境搭建

    一.Ubuntu系统语言环境切换修改 安装时,选择的中文版,但实际使用起来,很不爽,果断切换为英文 1.1 打开终端: vim /etc/default/locale 1.2 修改配置 LANG=&q ...