如何使用Spring Security正确获取与用户关联的GrantedAuthority列表?

3

我对Spring Security并不熟悉,我在尝试检索与特定用户相关的授权列表时遇到了以下问题。

我有这个方法可以检索连接用户(这个方法正常工作):

protected CustomUserDetail getUtenteConnesso() {
    return (CustomUserDetail) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
}

我想要做的是:

ArrayList<GrantedAuthority> autorizzazioni = (ArrayList<GrantedAuthority>) getUtenteConnesso().getAuthorities();

我想要检索与此用户相关联的授予权限列表,但是当我执行此方法时会抛出异常。

我认为问题在于getAuthorities()方法的签名定义在org.springframework.security.core.userdetails.User类中:

public Collection<GrantedAuthority> getAuthorities() {
    return authorities;
}

因此,该方法返回一个通用的Collection接口。

我试图将这个Collection强制转换为ArrayList,但似乎不起作用。

出了什么问题?我漏掉了什么?如何解决这个问题?


1
这不是一个列表,而是一个集合。如果你想要一个数组列表,创建一个新的,并将所有权限添加到其中。 - undefined
1个回答

8

接口返回一个集合,因此你不能使用ArrayList进行转换。你必须使用Collection:

Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
Collection<GrantedAuthority> authorities = authentication.getAuthorities();

如果您想要一个ArrayList,例如:

List<GrantedAuthority> listAuthorities = new ArrayList<GrantedAuthority>();
listAuthorities.addAll(authorities);

如果您对Spring的内部行为感兴趣,我在下面进行详细说明。 该接口指定了集合(请参见https://github.com/spring-projects/spring-security/blob/master/core/src/main/java/org/springframework/security/core/Authentication.java第68行):

Collection<? extends GrantedAuthority> getAuthorities();

默认的抽象实现内部使用ArrayList,但仍然返回Collection(参见 https://github.com/spring-projects/spring-security/blob/master/core/src/main/java/org/springframework/security/authentication/AbstractAuthenticationToken.java 67-70行):

    private final Collection<GrantedAuthority> authorities;
    ...
    ArrayList<GrantedAuthority> temp = new ArrayList<GrantedAuthority>(
            authorities.size());
    temp.addAll(authorities);
    this.authorities = Collections.unmodifiableList(temp);

在身份验证接口的Javadoc中详细解释了原因:“实现应确保对返回的集合数组的修改不会影响身份验证对象的状态,或使用一个不可修改的实例。”这就是为什么你不能进行类型转换。如果你真的需要一个列表,有人建议创建一个新的ArrayList并添加所有权限。

非常感谢,只有一个最后的疑问:为什么您首先创建了具有指定数量的权限的临时数组,然后将所有这些权限添加到该数组中?这是出于某种安全原因吗?为什么?如果我只是从权限集合中创建一个新数组会发生什么? - undefined
1
那不是我的代码,那是Spring Security的。我只是想展示它的工作方式,如果你对此感兴趣的话。我帖子的前两行:那就是你应该做的。你不需要一个临时的ArrayList。我不知道为什么你需要ArrayList,但是你可以简单地使用Authorities的集合来创建一个新的ArrayList,就像你提到的那样。 - undefined
1
在你的评论之后,我编辑了帖子。我想向你展示,即使你有一个集合,这个集合可能是有序的,因为Spring在内部管理ArrayList(至少默认情况下是这样)。无论如何,在我使用它时,它是有序的。希望现在更清楚了。 - undefined
1
@AndreaNobili 在构造函数中设置ArrayList的初始大小是一个很好的做法,特别是当您事先知道所需列表的大小时,因为这样可以避免扩展内部的ArrayList存储空间,而扩展操作并不是免费的,同时还能使用最优量的内存。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接