Grails + spring-security-core:用户登录后如何分配角色?

Posted

技术标签:

【中文标题】Grails + spring-security-core:用户登录后如何分配角色?【英文标题】:Grails + spring-security-core: How to assign a role after user has logged in? 【发布时间】:2011-11-27 04:39:37 【问题描述】:

我有一个使用 spring-security-core 和 spring-security-ldap 的 grails 应用程序,并针对 Active Directory 进行身份验证。我有一个自定义的UserDetailsUserDetailsContextMapper

我有一个用例,用户可以临时承担单个会话的额外职责。我希望能够在用户他们已经登录之后(即会话中)为其分配一个角色,然后在会话到期时删除该角色。

我有一个user_role 数据库表,用于存储用户和角色之间的关系。在这种情况下,关系是添加到数据库然后在会话到期时删除,还是仅存在于内存中都没有关系。无论哪种方式,我都在寻找一种在用户登录后分配角色(并立即应用)的方法。这可能吗?

【问题讨论】:

【参考方案1】:

UserDetails.getAuthorities() 拥有当前登录用户的所有角色。由于您已经有一个自定义的UserDetails 您只需在会话中开始时将附加角色添加到getAuthorities() 返回的值中,然后在会话中结束时将其删除。 (见下文编辑

即:

public class MyUserDetails implements UserDetails 
    // holds the authorities granted to the user in DB
    private List<GrantedAuthority> authorities;
    // holds the temporarily added authorities for the mid-session
    private List<GrantedAuthority> extraAuthorities;

   public GrantedAuthority[] getAuthorities() 
       List<GrantedAuthority> auths = new ArrayList<GrantedAuthority>();
       auths.addAll(this.authorities);
       auths.addAll(this.extraAuthorities);
       return auths;
   

   public void addExtraAuthorities(GrantedAuthority...auths) 
       for (GrantedAuthority a : auths) 
           this.extraAuthorities.add(a);
       
   

   public void clearExtraAuthorities() 
       this.extraAuthorities.clear();
   

或者您可以围绕原始 UserDetails 创建一个包装器,该包装器将保存额外的权限并将其包装并在会话中期开始时设置为当前的身份验证对象,并在会话中期结束时展开。


编辑:

正如 Ben 在评论中指出的那样,UserDetails.getAuthorities() 确实只被调用一次,在登录时,当创建 Authentication 对象时 - 我忘记了这一点。但这给我们带来了正确的答案,这一次我确信它会起作用,因为我自己就是这样做的。 Authentication.getAuthorities() 是要注意的方法,而不是 UserDetails.getAuthorities()。我真的推荐一个包装器,而不是Authenticationinterace 的自定义实现,因为它会更灵活,并允许透明地支持不同的身份验证机制。

即:

public class MidSessionAuthenticationWrapper implements Authentication 

    private Authentication wrapped;
    private List<GrantedAuthority> authorities;

    public MidSessionAuthenticationWrapper(
            Authentication wrapped, Collection<GrantedAuthority> extraAuths) 
        this.wrapped = wrapped;
        this.authorities = new ArrayList<GrantedAuthority>(wrapped.getAuthorities());
        this.authorities.addAll(extraAuths);
    

    public Authentication getWrapped() 
        return this.wrapped;
    

    @Override
    public Collection<GrantedAuthority> getAuthorities() 
        return this.authorities;
    

    // delegate all the other methods of Authentication interace to this.wrapped

那么您需要做的就是在会话中期开始时:

Authentication authentication = 
    SecurityContextHolder.getContext().getAuthentication();
Collection<GrantedAuthority> extraAuths = 
    null; // calculate the extra authorities
MidSessionAuthenticationWrapper midSessionAuthentication =
    new MidSessionAuthenticationWrapper(authentication, extraAuths);
SecurityContextHolder.getContext().setAuthentication(midSessionAuthentication);

在会话中期结束时:

MidSessionAuthenticationWrapper midSessionAuthentication =
    (MidSessionAuthenticationWrapper) SecurityContextHolder.getContext().getAuthentication();
Authentication authentication = midSessionAuthentication.getWrapped();
SecurityContextHolder.getContext().setAuthentication(authentication);

【讨论】:

感谢 Roadrunner。我已经尝试过您的方法,但是似乎使用 或控制器注释进行安全检查时未调用 getAuthorities() 。据我所知,只有在用户首次登录时才会调用该方法。这与您的体验不同吗? @Ben 你是对的。我更正了我的答案以反映这一点。现在我记得为什么我上次自己更改了Authentication 而不是UserDetails :)。很抱歉一开始误导了你。 效果很好,谢谢! (对不起,延迟回复,我有一段时间偏离了方向)。【参考方案2】:

我刚刚遇到了同样的问题,并找到了一个更短的解决方案。我使用“之前”过滤器来检查 LDAP 用户是否有本地(db)用户,如有必要,查找或创建它,为用户添加角色,然后通过以下方式重新验证用户:

springSecurityService.reauthenticate(user.username)

然后,用户将拥有当前的权限列表。

【讨论】:

这对我很有用。为用户分配一个新角色,重新验证并完成! 您能否添加指向教程或文档的链接,具体如何执行此操作?例如。使用 Grails 3.x 拦截器。谢谢

以上是关于Grails + spring-security-core:用户登录后如何分配角色?的主要内容,如果未能解决你的问题,请参考以下文章

Spring-security/Grails 应用程序 - 未调用自定义 WebSecurity 配置

Grails Spring-Security - 如何比较密码-

休息资源的 Grails spring-security 静态规则似乎无法正常工作

grails spring-security 插件保护所有控制器,而不仅仅是带有@Secured注解的控制器

Spring-security 记住我的功能不起作用

如何使用spring-security通过用户名和密码登录?