如何在spring security中更新用户权限后立即启用权限?

我正在使用spring-security框架。当我更新权限时,它不会立即生效。我必须退出当前用户(意味着注销),然后重新访问(意味着登录)将更新用户的权限。

在spring security中更新用户权限后立即启用权限的方法是什么?

您可以像这样在AbstractSecurityInterceptor中设置alwaysReauthenticate

  ...  

当然你应该注意,因为99.9%你不需要重新认证。 由于身份validation可能使用数据库或其他内容,因此性能可能会降低。 但通常你有一个缓存,比如带有hibernate的二级缓存,所以每次加载用户详细信息应该是一个只有内存的操作,在所有情况下权限都没有改变。

甘道夫解决方案有效但不完整。 为了让spring权限被Spring安全性考虑(例如,允许访问以前不可用的页面),您需要创建一个包含新权限列表的新身份validation对象(例如,new UsernamePasswordAuthenticationToken)。

不足以重置Thread Local上下文,您还需要更新会话:

 UserContext userContext = (UserContext) context.getAuthentication().getPrincipal(); if (userContext != null && userContext.getUsername() != null) { //This is my function to refresh the user details UserDetailsBean userDetails = getUserDetailsBean(userContext.getUsername()); Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if (authentication instanceof UsernamePasswordAuthenticationToken) { UsernamePasswordAuthenticationToken auth = (UsernamePasswordAuthenticationToken) authentication; auth.setDetails(userDetails); } return userDetails; } else { throw new ServiceException("User not authenticated"); } request.getSession().setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, SecurityContextHolder.getContext()); 

至少在google appengine中,会话不是引用,通过修改本地线程不会自动更新,你必须手动session.set你的对象。

以下主题说明了如何在每个请求中重新加载用户/主体:

从Spring Database中的数据库每个请求重新加载UserDetails对象

完全披露我是上述链接中问题的问答的作者。

由于您没有在问题中提供确切的详细信息,我认为您的情况如下:

  1. 您正在提供UserDetailsS​​ervice以在用户尝试登录时加载UserDetails
  2. 作为该服务的一部分,您正在查询数据库/ DAO以加载有关用户权限的详细信息,并基于此设置授予的权限
  3. 当你说“当我更新权限”时,你指的是更新用户在数据库中的权限(或者你正在存储数据的任何内容)。

如果是这样,那么您所看到的是设计 – Spring Security仅在用户首次尝试登录时为用户加载UserDetails,然后将其存储在Session中。 通常这是有道理的,因为它避免了应用程序必须对每个请求的用户详细信息执行相同的查询。 此外,用户的权限通常不会在99.9%的访问中发生变化。

要更改此行为,您可能希望在某处添加“刷新”命令/页面,这将触发一些代码(您必须编写),这将重新查询UserDetailsS​​ervice并替换SecurityContext中的UserDetails。 我不相信有任何内置的方法来做到这一点。

您可以创建自己的身份validation机制返回的UserDetails接口实现,允许访问GrantedAuthorities []。 然后将新权限直接添加到该UserDetails对象。 如果用户可以同时打开多个会话(或者如果多个用户共享相同的通用登录名),则可能会遇到问题,新的权限只会在您更改的会话中看到。

你可以试试这个

 SecurityContextHolder.getContext().setAuthentication(SecurityContextHolder.getContext().getAuthentication());