【问题标题】:Update authorities through Spring SecurityContextHolder通过 Spring SecurityContextHolder 更新权限
【发布时间】:2015-02-04 01:25:28
【问题描述】:

我正在使用 Spring Security 来验证用户。

问题是动态更新权限的最佳方式是什么? 我想根据请求更新它,现在我只在用户登录系统后执行一次。

我有基于管理器的应用程序,因此管理员可以随时决定用户可以做什么,并删除/添加角色。这种方法的问题是,用户只有在注销并重新登录后才能获得新的权限集。

我知道我可以使用

Authentication auth = SecurityContextHolder.getContext().getAuthentication();
List<GrantedAuthority> authorities = Lists.newArrayList();

userDao.getAuthorities(authorities, user);

Authentication newAuth = new UsernamePasswordAuthenticationToken(auth.getPrincipal(), auth.getCredentials(), authorities);
 SecurityContextHolder.getContext().setAuthentication(newAuth);

主要问题是什么时候做这件事最合适?框架命中控制器或拦截器之前的一些过滤器链?它有多安全?线程安全吗?

假设我把它放在拦截器中,当我在一个请求中更新 SecurityContextHolder 时,另一个请求读取它 - 会发生什么?

快速草稿

public class VerifyAccessInterceptor extends HandlerInterceptorAdapter {
    public boolean preHandle(
            HttpServletRequest request,
            HttpServletResponse response,
            Object handler) throws Exception {

          Authentication auth =  SecurityContextHolder.getContext().getAuthentication();
           List<GrantedAuthority> authorities = Lists.newArrayList();

           userDao.getAuthorities(authorities, user);

           Authentication newAuth = new  UsernamePasswordAuthenticationToken(auth.getPrincipal(), auth.getCredentials(),             authorities);
               SecurityContextHolder.getContext().setAuthentication(newAuth);

    }
}

【问题讨论】:

    标签: java spring spring-mvc spring-security


    【解决方案1】:

    如果我错了,请纠正我。

    从您的问题来看,很明显您希望基于请求的 Authority 更改。理想情况下,管理员将有一个不同的 UI,他可以在其中删除/添加权限。这些更改必须近乎实时地反映在任何登录的用户会话中。

    目前您提供的代码 sn-p 是您可以做到的唯一方法。

    回答您的疑虑。

    The main question is what would be the right moment to do it?

    如果您希望仅将其应用于登录用户,那么您必须将其放在拦截器中,因为它只会在 Spring 安全过滤器链之后应用。

    Some filter chain before framework hit controller or interceptor?
    

    是的,在您的请求到达控制器或拦截器之前,将首先调用 DelegatingFilterProxy 和 FilterChainProxy。

    And how safe it is? Thread safe?
    

    是的,如果您在默认设置下使用SecurityContextHolder,它将使用线程安全的ThreadLocalSecurityContextHolderStrategy

    由于所有请求都必须通过拦截器,因此性能会受到影响。而且由于只有在重新设置Authentication之前,您才需要更改权限,以便更好地检查您的拦截器中的权限。

    public class VerifyAccessInterceptor extends HandlerInterceptorAdapter {
        public boolean preHandle(
                HttpServletRequest request,
                HttpServletResponse response,
                Object handler) throws Exception {
    
              Authentication auth =  SecurityContextHolder.getContext().getAuthentication();
               List<GrantedAuthority> authorities = Lists.newArrayList();
    
               userDao.getAuthorities(authorities, user);
    
               // If contents of auth.getAuthorities() equals authorities then no need to re-set.
               Authentication newAuth = new  UsernamePasswordAuthenticationToken(auth.getPrincipal(), auth.getCredentials(),             authorities);
                   SecurityContextHolder.getContext().setAuthentication(newAuth);
    
        }
    }
    

    【讨论】:

    • 不用纠正,你的理解正是我需要的。但是仍然有一些事情阻止我在拦截器中执行此操作,过程中是否还有其他步骤。找到这个网址 - stackoverflow.com/questions/892733/…。在您的 AbstractSecurityInterceptor 中谈论 alwaysReauthenticate,但不确定如何将它与我的代码 Shippet 一起使用。
    • alwaysReauthenticate 标志用于每次重新登录用户,理想情况下只需再次调用 AuthenticationProvider 并在 SecurityContextHolder.getContext() 中设置身份验证。因此,在您的情况下,这不是必需的,因为您只需要重新加载权限即可。
    • shazin,同意你的观点,但是拥有拦截器有多安全?阻止我这样做的东西,是否可以使 SecurityContextHolder 请求范围而不是 Session 范围并使用 request 创建它?所以我知道另一个浏览器选项卡不会修改?
    猜你喜欢
    • 2019-09-08
    • 2015-02-08
    • 2019-04-24
    • 2021-04-05
    • 1970-01-01
    • 1970-01-01
    • 2012-11-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多