Spring OAuth2中clientDetails.getAuthorities()的作用、区别及应用场景
问题背景
我正在查阅Spring OAuth2的ClientDetails接口,对其中的getAuthorities()方法在授权流程中的作用与工作机制存在疑问。我知道它和UserDetails接口的getAuthorities()不同:
ClientDetails.getAuthorities() API描述
Collection<org.springframework.security.core.GrantedAuthority> getAuthorities() Returns the authorities that are granted to the OAuth client. Cannot return null. Note that these are NOT the authorities that are granted to the user with an authorized access token. Instead, these authorities are inherent to the client itself. Returns: the authorities (never null)
UserDetails.getAuthorities() API描述
java.util.Collection<? extends GrantedAuthority> getAuthorities() Returns the authorities granted to the user. Cannot return null. Returns: the authorities, sorted by natural key (never null)
我明白前者是为OAuth2客户端授予权限,后者是为用户主体授予权限,但不清楚二者的具体区别,以及何时使用clientDetails.getAuthorities()。
我熟悉的流程是:授权服务器签发的JWT令牌中包含用户权限,资源服务器通过这些权限校验用户是否能访问资源,比如:
{ "app-userId": "c54a-4140-9fa0-0f39", "user_name": "abc@xyz.com", "scope": [ "all" ], "exp": 1656929583, "authorities": [ "app1_viewer", "app1_modifier", "app2_viewer", "app2_blog_creator"], "client_id": "client_A" }
上述流程均使用userDetails.getAuthorities(),因此想了解clientDetails.getAuthorities()的具体作用、适用场景及示例。
核心区别
- UserDetails.getAuthorities():属于具体用户主体的权限,是用户被授予的访问资源的权限,会被包含在用户的访问令牌中,用于资源服务器校验用户是否能访问特定接口/资源。
- ClientDetails.getAuthorities():属于OAuth2客户端应用本身的权限,是客户端作为独立实体拥有的权限,与使用该客户端的具体用户无关。
作用与适用场景
1. 客户端凭证模式(Client Credentials Grant)
当客户端不需要用户参与,直接以自身身份向授权服务器请求令牌时,授权服务器会将clientDetails.getAuthorities()返回的权限注入到令牌中。这种场景下,客户端代表自己访问资源,而非代表某个用户。
2. 授权服务器内部的客户端权限校验
授权服务器可以基于客户端的权限,限制客户端的操作范围:
- 限制客户端能使用的OAuth2授权模式(比如只允许特定客户端使用授权码模式);
- 限制客户端能调用的授权服务器接口(比如仅允许指定客户端调用令牌校验接口)。
3. 资源服务器对客户端的权限校验
某些敏感资源不仅要求用户具备权限,还要求调用该资源的客户端本身具备对应权限。比如某个数据导出API只允许官方客户端调用,不管使用该客户端的用户权限如何,都需要客户端拥有DATA_EXPORT权限。
具体示例
示例1:客户端凭证模式下的权限使用
假设存在一个后台管理客户端(client_id: admin-client),需要直接访问客户端管理API,我们给该客户端配置CLIENT_MANAGER权限:
public class CustomClientDetails implements ClientDetails { @Override public Collection<GrantedAuthority> getAuthorities() { return Collections.singletonList(new SimpleGrantedAuthority("CLIENT_MANAGER")); } // 实现其他ClientDetails方法... }
当该客户端用客户端凭证模式请求令牌时,签发的JWT载荷如下:
{ "client_id": "admin-client", "scope": ["client-management"], "exp": 1656929583, "authorities": ["CLIENT_MANAGER"], ... }
资源服务器校验令牌时,会检查客户端是否具备CLIENT_MANAGER权限,允许则返回数据,否则返回403。
示例2:限制客户端调用授权服务器接口
在授权服务器配置中,仅允许具备TOKEN_CHECKER权限的客户端调用/oauth/check_token接口:
@Override public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { // 只有拥有TOKEN_CHECKER权限的客户端才能访问令牌校验接口 security.checkTokenAccess("hasAuthority('TOKEN_CHECKER')"); } @Service public class CustomClientDetailsService implements ClientDetailsService { @Override public ClientDetails loadClientByClientId(String clientId) throws ClientRegistrationException { if ("trusted-client".equals(clientId)) { CustomClientDetails client = new CustomClientDetails(); client.setAuthorities(Collections.singletonList(new SimpleGrantedAuthority("TOKEN_CHECKER"))); // 配置客户端其他信息... return client; } // 其他客户端处理逻辑... throw new NoSuchClientException("Client not found"); } }
内容的提问来源于stack exchange,提问作者samshers

