spring security 动态 修改当前登录用户的 权限
1.前言
spring security 可以获取当前登录的用户信息,同时提供了接口 来修改权限列表信息 ,
使用这个方法 ,可以动态的修改当前登录用户权限。
那么问题来了。。。
如果我是管理员 ,如何动态地修改用户的权限?比如vip权限?
按照以前的权限使用方法 ,修改数据库的权限信息后,当前用户需要重新登录,才能从数据库获取新的权限信息后再更新当前用户的权限列表,一般是管理员修改权限后,强制用户重新登录,
这样对用户很不友好 ,使用spring security 可以直接更新当前用户的权限 ,其实就是重新注册权限列表信息。
可是问题又来了。。。
spring security 不是只能修改当前登录用户的信息么?那么怎么修改别人的?
有两个解决方案:
(1)方案一:管理员在数据库修改用户权限数据后,检查该用户是否已经登录,未登录则操作结束,
如果已经登录,则使用websocket通知用户前端向后端Ajax发送一个修改当前权限的请求。
(2)方案二:管理员在数据库修改用户权限数据,检查该用户是否已经登录,未登录则操作结束,
如果已经登录,获取当前用户存在内存的session,根据session获取该用户的认证信息 ,取出权限列表后对其修改,然后重新注册权限列表。
2.操作
准备一个配置好的spring boot+ spring security的工程 ,详细操作这里不演示 ,在我的其他随笔有详细记录
(1)目录结构

(2)添加方法

源码
package com.example.security5500.controller; import org.apache.commons.lang3.StringUtils;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController; import java.security.Principal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map; /**
* 作为授权类 ,用来动态更新权限
*/
@RestController
public class AuthorityController { //添加权限 ,参数是需要新增的权限名
@RequestMapping("/addAuth")
public Map<String,Object> addAuth(String authName){
Map<String,Object> map = new HashMap<>();
if (StringUtils.isBlank(authName)){
map.put("data","权限名称不可空,参数名authName");
return map;
} try {
//========================================================
//这一段仅仅是更新当前登录用户的权限列表 ,登出后将释放 ,当再次从数据库获取权限数据时将还原 ,因此如果需要持久性的更改权限,
// 还需要修改数据库信息 ,懒得写 ,这里就不做修改数据库演示了
//
// 得到当前的认证信息
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
// 生成当前的所有授权
List<GrantedAuthority> updatedAuthorities = new ArrayList<>(auth.getAuthorities());
// 添加 ROLE_VIP 授权
updatedAuthorities.add(new SimpleGrantedAuthority("ROLE_" + authName));
// 生成新的认证信息
Authentication newAuth = new UsernamePasswordAuthenticationToken(auth.getPrincipal(), auth.getCredentials(), updatedAuthorities);
// 重置认证信息
SecurityContextHolder.getContext().setAuthentication(newAuth);
//========================================================
map.put("data","权限 "+authName+" 添加成功");
}catch (Exception e){
e.printStackTrace();
map.put("data","权限添加失败");
}
return map;
} //获取用户权限信息
@RequestMapping({"/info"})
@ResponseBody
public Object info(@AuthenticationPrincipal Principal principal) {
return principal;
}
/*
{"authorities":[{"authority":"admin"},{"authority":"user"}],
"details":{"remoteAddress":"0:0:0:0:0:0:0:1","sessionId":"1F57B8E39C5D1DB1F875D57D533DB982"},
"authenticated":true,"principal":{"password":null,"username":"xi","authorities":[{"authority":"admin"},
{"authority":"user"}],"accountNonExpired":true,"accountNonLocked":true,
"credentialsNonExpired":true,"enabled":true},"credentials":null,"name":"xi"} */ //http://localhost:5500/addAuth?authName=love1
//http://localhost:5500/info }
(3)拦截位置 ,需要权限 ROLE_love1 才可以访问

3.测试

启动工程
(1)访使用一个 有 权限 ROLE_love1 的账户
username = cen
password = 11
访问网址 http://localhost:5500/home

点击登录

显然可以正常运行
访问网址 http://localhost:5500/info 查看当前登录用户的认证信息 ,是有 ROLE_love1 权限的

(2)访使用一个 没有 权限 ROLE_love1 的账户
username = yue
password = 11
访问网址 http://localhost:5500/home
选择 “记住我” ,可以自动登录

提示 403 ,

访问网址 http://localhost:5500/info 查看当前登录用户的认证信息 ,是 没有 ROLE_love1 权限的

现在添加权限
访问网址 http://localhost:5500/addAuth?authName=love1

再次 访问网址 http://localhost:5500/info 查看当前登录用户的认证信息 ,发现 有 ROLE_love1 权限了

再次 访问网址 http://localhost:5500/home ,发现访问成功啦

(2)那么现在问题来了,现在是开启了自动登录模式 ,那么关闭浏览器后 cookie是否会删除? 如果不删除 ,新加的权限是否会删除?
继续上面yue的登录页面 直接关闭浏览器,再访问 http://localhost:5500/home
发现被拦截进入 登录页面了

难道被强制登出了?
不 ,查看cookie ,并没有被删除

继续 访问 http://localhost:5500/hai ,发现是已经自动登录了

于是查看 认证信息 ,访问网址 http://localhost:5500/info

发现 ROLE_love1 权限被清除了
(3)为什么会这样?
有两个猜测 :
猜测一:在第一次登录时 ,没有权限的 认证信息已经存在cookie ,不再修改,自动登录不再从数据库获取权限信息。
猜测二 : 即便是自动登录 ,每次登录的都会从数据库获取用户信息并更新 ,以前登录时存在内存的信息会在浏览器销毁后释放。
证明:
我在注册权限的地方加了指令将添加到注册列表的权限名打印

源码
package com.example.security5500.securityConfig; import com.example.security5500.entitis.tables.TUser;
import com.example.security5500.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service; import java.util.ArrayList;
import java.util.List; @Service
public class DbUserDetailsService implements UserDetailsService { @Autowired
private UserService userService; @Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//根据用户名查询用户信息
TUser tUser = userService.getByUsername(username);
if (tUser == null){
throw new UsernameNotFoundException("用户不存在!");
}
//权限设置
// List<GrantedAuthority> simpleGrantedAuthorities = new ArrayList<>();
List<SimpleGrantedAuthority> simpleGrantedAuthorities = new ArrayList<>();
String role = tUser.getRole();
//分割权限名称,如 user,admin
String[] roles = role.split(",");
System.out.println("注册该账户权限");
for (String r :roles){
System.out.println(r);
//添加权限
simpleGrantedAuthorities.add(new SimpleGrantedAuthority(r));
} // simpleGrantedAuthorities.add(new SimpleGrantedAuthority("USER"));
/**
* 创建一个用于认证的用户对象并返回,包括:用户名,密码,角色
*/
//输入参数
return new org.springframework.security.core.userdetails.User(tUser.getUsername(), tUser.getPsw(), simpleGrantedAuthorities);
} }
自动登录后
控制台打印的结果:

因此 ,猜测二是正确的 。
4.总结:
更新当前登录用户的权限列表 ,登出后将释放 ,当再次从数据库获取权限数据时将还原【包括自动登录】 ,因此如果需要持久性的更改权限,
还需要修改数据库信息
spring security 动态 修改当前登录用户的 权限的更多相关文章
- spring security中当已登录用户再次访问登录界面时,应跳转到home
@RequestMapping("/login") public String login(){ Authentication auth = SecurityContextHold ...
- Spring Security 动态url权限控制(三)
一.前言 本篇文章将讲述Spring Security 动态分配url权限,未登录权限控制,登录过后根据登录用户角色授予访问url权限 基本环境 spring-boot 2.1.8 mybatis-p ...
- Spring Security之多次登录失败后账户锁定功能的实现
在上一次写的文章中,为大家说到了如何动态的从数据库加载用户.角色.权限信息,从而实现登录验证及授权.在实际的开发过程中,我们通常会有这样的一个需求:当用户多次登录失败的时候,我们应该将账户锁定,等待一 ...
- Spring Security 入门(1-3-1)Spring Security - http元素 - 默认登录和登录定制
登录表单配置 - http 元素下的 form-login 元素是用来定义表单登录信息的.当我们什么属性都不指定的时候 Spring Security 会为我们生成一个默认的登录页面. 如果不想使用默 ...
- Spring Security OAuth2 SSO 单点登录
基于 Spring Security OAuth2 SSO 单点登录系统 SSO简介 单点登录(英语:Single sign-on,缩写为 SSO),又译为单一签入,一种对于许多相互关连,但是又是各自 ...
- 七:Spring Security 前后端分离登录,非法请求直接返回 JSON
Spring Security 前后端分离登录,非法请求直接返回 JSON 解决方案 在 Spring Security 中未获认证的请求默认会重定向到登录页,但是在前后端分离的登录中,这个默认行为则 ...
- Spring Security(17)——基于方法的权限控制
目录 1.1 intercept-methods定义方法权限控制 1.2 使用pointcut定义方法权限控制 1.3 使用注解定义方法权限控制 1.3.1 JSR-25 ...
- Spring Security 实战干货:图解用户是如何登录的
1. 前言 欢迎阅读Spring Security 实战干货系列文章,在集成Spring Security安全框架的时候我们最先处理的可能就是根据我们项目的实际需要来定制注册登录了,尤其是Http登录 ...
- spring security 管理会话 多个用户不可以使用同一个账号登录系统
多个用户不能使用同一个账号同时登陆系统. 1. 添加监听器 在web.xml中添加一个监听器,这个监听器会在session创建和销毁的时候通知Spring Security. <listener ...
随机推荐
- Nginx模块之Nginx-echo
目录 一.简介 二.使用 一.简介 官网 Nginx-echo可以在Nginx中用来输出一些信息,是在测试排错过程中一个比较好的工具.它也可以做到把来自不同链接地址的信息进行一个汇总输出.总之能用起来 ...
- 一种基于Java Swing/HTML/MySQL的汽车租赁系统
该项目是一个Java的课程作业(大二),主要运用Java.Swing.HTML.MySQL,实现基本的租车逻辑.界面可视化.信息导出.数据存储等功能.实现管理员.用户两种角色登录,并结合Java开发中 ...
- Svelte入门——Web Components实现跨框架组件复用(二)
在上节中,我们一起了解了如何使用Svelte封装Web Component,从而实现在不同页面间使用电子表格组件. Svelte封装组件跨框架复用,带来的好处也十分明显: 1.使用框架开发,更容易维护 ...
- 如何基于 Docker 快速搭建 Springboot + Mysql + Redis 项目
目录 前言 项目目录 搭建项目 1. docker安装启动mysql以及redis 1.1 安装mysql 1.2 安装redis 2. 初始化数据库 3.创建项目 4.初始化代码 4.1 全局配置文 ...
- how2heap学习(二)
拖了好久,但是在期间做了几道pwn题目,发现堆原来也没有想象中的难. fastbin_dup_into_stack 这个说白了,就是利用double free可以进行任意地址的写,说是任意地址不准确, ...
- UVA10079 Pizza Cutting 题解
Content 求用 \(n\) 条直线最多能将平面分成多少块区域. 多组输入,以一个负数结束. 数据范围:\(0\leqslant n\leqslant 2.1\times 10^8\). Solu ...
- LuoguP7008 [CERC2013]What does the fox say? 题解
Content 森林里面有很多声响,你想知道有哪些声响是由狐狸发出来的. 已知你搜集到了 \(n\) 个声响,并且还知道某些其他动物能够发出的声响,已知如果没有哪一个声响是由其他任何一种动物发出来的话 ...
- 小白误入(<<<绝没有针对>>>)企业级架构介绍与IP tables防火墙介绍
内容详细 架构图 架构图详解 架构: 把一个整体(完成人类生存的所有工作)切分成不同的部分(分工),由不同角色来完成这些分工,并通过建立不同部分相互沟通的机制,使得这些部分能够有机的结合为一个整体,并 ...
- 【LeetCode】5686. 移动所有球到每个盒子所需的最小操作数 Minimum Number of Operations to Move All Balls to Each Box
作者: 负雪明烛 id: fuxuemingzhu 公众号:负雪明烛 本文关键词:LeetCode,力扣,算法,算法题,交替合并字符串,Merge Strings Alternately,刷题群 目录 ...
- 【LeetCode】1408. 数组中的字符串匹配 String Matching in an Array
作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 暴力遍历 日期 题目地址:https://leetco ...