spring security中动态更新用户的权限

业务背景: 管理员更改其他用户权限,正好用户在登陆状态下,无法刷新管理员刚赋值的权限,只能退出登录,重新登录才能拥有新权限.
业务需求:管理员更改权限,其他用户不退出登录,可以拥有新权限,动态刷新session
感谢这位博客提供的线索
前提条件需要拥有

@Autowired
    SessionRegistry sessionRegistry;

如果找不到SessionRegistrybean 需要自行注册

/**
     * 注册bean sessionRegistry
     */
    @Bean
    public SessionRegistry sessionRegistry() {
        return new SessionRegistryImpl();
    }

配置security http

http
		... 省略代码
				.and()
                .sessionManagement()
                // 无效session跳转
                .invalidSessionUrl(login)
                .maximumSessions(1)
                // session过期跳转
                .expiredUrl(login)
                .sessionRegistry(sessionRegistry())
       ... 省略代码         

定义一个 UserSessionManage

package com.gszcn.hisweb.config.session;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpSession;
import java.util.*;

/**
 * 用户存储session
 * 一个用户储存多个session 出现一个用户多个地方登录
 */
@Component
@Data
@Slf4j
@CacheConfig(cacheNames = "UserSessionManage")
public class UserSessionManage {
    /**
     * 用户存储session对象
     */
    private Map<String,List<HttpSession>> userHttpSession=new HashMap <>();

    /**
     * 获取当前在线的session
     * @param id
     * @return
     */
    @Cacheable(key = "#id")
    public List<HttpSession> getUserSession(String id) {
        List <HttpSession> httpSessions = userHttpSession.get(id);
        if(httpSessions==null){
            httpSessions=new ArrayList <>();
        }
        return httpSessions;
    }

    /**
     * 修改缓存
     * @param id
     * @param userSession
     */
    @CachePut(key = "#id")
    public List<HttpSession> putUserSession(String id, List<HttpSession> userSession) {
        userHttpSession.put(id,userSession);
        return userSession;
    }
}

然后在定义一个SessionManage

package com.gszcn.hisweb.config.session;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpSession;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * session管理容器
 */
@Data
@Slf4j
@Component
@CacheConfig(cacheNames = "SessionManage")
public class SessionManage {
    @Autowired
    UserSessionManage userSessionManage;
    /**
     * 创建map容器
     */
    private Map<String,HttpSession> httpSessionMap=new HashMap <>();

    /**
     * 创建session
     * @param id
     * @param session
     */
    @Cacheable(key = "#id")
    public HttpSession createdSession(String id, HttpSession session) {
        httpSessionMap.put(id,session);
        return session;
    }

    /**
     * 销毁session
     * @param id
     */
    @CacheEvict(key = "#id")
    public void destroyedSession(String id) {
        httpSessionMap.remove(id);
    }

    /**
     * 改变session
     * @param oldSessionId
     * @param newSessionId
     * @return
     */
    public void changeSession(String oldSessionId, String newSessionId) {
        //查询旧的session

    }
    /**
     * 根据sessionid查询session
     */
    @Cacheable(key = "#id")
    public HttpSession getSessionID(String id){
        return httpSessionMap.get(id);
    }

    /**
     * 当前用户保存session
     * @param id 用户id
     * @param httpSessions
     */
    @Cacheable(key = "'user'+#id",unless = "!#result.contains(#httpSessions)")
    public List <HttpSession> putUserSession(String id, HttpSession httpSessions) {
        List <HttpSession> userSession = userSessionManage.getUserSession(id);
        if(!userSession.contains(httpSessions)){
            userSession.add(httpSessions);
        }
        userSessionManage.putUserSession(id,userSession);
        return userSession;
    }
}

监听每次的请求防止多账号不同步权限

 /**
     * 监听Servlet 请求
     */
    @Component
    class ServletRequestHandledEventListener implements ApplicationListener <ServletRequestHandledEvent> {

        @Override
        public void onApplicationEvent(ServletRequestHandledEvent event) {
            log.info("ServletRequestHandledEventListener:{}",event);
            String sessionId = event.getSessionId();
            SessionInformation sessionInformation = sessionRegistry.getSessionInformation(sessionId);
            if(sessionInformation==null){return;}
            Object principal = sessionInformation.getPrincipal();


            try {
                if(principal instanceof SysUser){
                    SysUser user = (SysUser) principal;
                    sessionManage.putUserSession(user.getId(),SecurityUtil.getHttpSession());
                }

            } catch (Exception e) {
                log.warn("当前无法监听到用户信息");
            }

        }
    }

sessionManage 中取出当前在线用户的所有session

/**
     * 刷新session
     * 刷新在线用户角色
     * @param save
     */
    private void refreshSession(SysUser save) {
        UserSessionManage userSessionManage = sessionManage.getUserSessionManage();
        List<HttpSession> userSession = userSessionManage.getUserSession(save.getId());
        userSession.forEach(session -> {
            this.reloadUserAuthority(session);
        });
    }

当修改角色调用刷新session中的在线用户权限

/**
     * 重新加载用户的权限
     *
     * @param session
     */
    public void reloadUserAuthority(HttpSession session) {
        try {
            SecurityContext securityContext = (SecurityContext) session.getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY);
            Authentication authentication = securityContext.getAuthentication();
            Object principal1 = authentication.getPrincipal();
            if (principal1 instanceof SysUser) {
                UserDetails principal = (SysUser) principal1;
                /**
                 * 重载用户对象
                 */
                principal = this.loadUserByUsername(principal.getUsername());

                // 重新new一个token,因为Authentication中的权限是不可变的.
                UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(
                        principal, authentication.getCredentials(),
                        principal.getAuthorities());
                result.setDetails(authentication.getDetails());
                securityContext.setAuthentication(result);
            }
        } catch (Exception e) {
            log.error("当前用户session有可能不存在");
        }

    }

本页面的代码本人测试无误,请放心参考,当然源码不提供公司的代码,如果又不懂的地方请留言或者联系QQ:1810258114及时帮你解答

  • 7
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Spring Security可以通过刷新用户的Session来更新用户权限。在代码,可以调用`reloadUserAuthority(HttpSession session)`方法来重新加载用户权限。这个方法首先获取当前用户的安全上下文,并从获取认证信息。然后,通过调用`loadUserByUsername(String username)`方法重新加载用户对象,得到新的用户对象。接下来,创建一个新的`UsernamePasswordAuthenticationToken`对象,其包含新的用户对象、认证凭证和权限列表。最后,将新的认证信息设置回安全上下文,以更新用户权限。 为了实现动态刷新Session,需要满足以下前提条件: 1. 需要使用`@Autowired`注入`SessionRegistry`对象。 2. 在业务需求,管理员更改了用户权限后,可以调用`sessionRegistry`对象的相应方法来使其他用户的Session得到刷新,从而拥有新的权限。 综上所述,通过调用`reloadUserAuthority`方法并满足前提条件,可以实现Spring Security动态更新用户权限的功能。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [spring security动态更新用户权限](https://blog.csdn.net/qq_40127376/article/details/102765576)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [SpringSecurity动态加载用户角色权限实现登录及鉴权](https://blog.csdn.net/hanxiaotongtong/article/details/103268544)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值