我正在使用Spring Security为我的webapp提供身份验证和授权。
我使用标准方法UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
登录DaoAuthenticationProvider
。
成功登录后,我可以通过两种不同的方式访问用户权限:
1#SecurityContextHolder.getContext().getAuthentication().getAuthorities()
2#((UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getAuthorities()
它们应该是相同的,因为Authentication实例权限列表是从UserDetails的user.getAuthorities()构造的,但它们实际上是2个不同的Collection实例。主体的一个是UnmodifiableSet,Authentication实例中的一个是UnmodifiableRandomAccessList。 2个不同的Collection实例,包含相同的权限列表。
当试图找到动态添加权限给当前经过身份验证的Principal的解决方案时,这让我很震惊。这不是一件好事,安全层不应该允许我这样做,但仍然是我需要的。
我认为可接受的解决方案是以编程方式登录当前经过身份验证的用户
new UsernamePasswordAuthenticationToken(authentication.getPrincipal(), authentication.getCredentials(), dbAuthsSet);
authentication
是当前的身份验证实例,dbAuthSet
是当前的权限列表+我需要添加的权限。
这很好用。现在唯一奇怪的是
1#SecurityContextHolder.getContext().getAuthentication().getAuthorities()
2#((UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getAuthorities()
不再返回相同的权限列表。
如果我根据我的应用程序中的身份验证列表检查权限,我很好,这是完全合理的事情。但如果我查看校长的名单,我就会遇到不一致的情况。
你怎么看?这是一个应该在Spring的Security 3.2中解决的问题吗?您是否觉得以编程方式使用new UsernamePasswordAuthenticationToken()
登录以实现我的目标是为会话授予当前经过身份验证的用户的额外权限是否合理?
使用Spring的Run-As Authentication Replacement功能会是一个好例子吗? 任何人都可以分享这方面的经验吗?