Spring OAuth2 client_credentials授权模式未校验用户凭证问题求助
问题根本原因
client_credentials(客户端模式)是OAuth2标准定义的授权类型,设计初衷就是仅对客户端本身进行授权,不需要用户参与授权流程,所以该模式默认不会处理、校验请求携带的username和password参数,仅校验client_id和client_secret,你当前遇到的是该授权模式的标准正常行为,不是配置错误。
根据你的实际业务需求,可以选择以下两种解决方案:
方案1:更换为需要用户校验的授权模式(推荐)
如果你的业务场景需要校验终端用户的账号密码,说明你应该使用password(密码模式)而非客户端模式,修改成本极低:
- 在
OAuthConfiguration类的客户端配置中,将授权类型替换为password:
@Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() .withClient("test-client-id") .secret(passwordEncoder.encode("test-client-secret")) .accessTokenValiditySeconds(accessTokenValiditySeconds) .refreshTokenValiditySeconds(refreshTokenValiditySeconds) // 替换授权类型 .authorizedGrantTypes("password") .scopes("read", "write") .resourceIds("api"); }
修改后请求/oauth/token接口时传入grant_type=password,同时携带client_id、client_secret、username、password四个参数,系统就会自动调用你配置的UserDetailsService对用户账号密码进行校验。
方案2:自定义扩展客户端模式的校验逻辑
如果你的业务场景特殊,确实需要在客户端模式下额外校验用户账号密码,可以自定义TokenGranter扩展原有逻辑:
- 自定义客户端模式的令牌颁发器,增加用户名密码校验逻辑
public class CustomClientCredentialsTokenGranter extends ClientCredentialsTokenGranter { private final AuthenticationManager authenticationManager; public CustomClientCredentialsTokenGranter(AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory, AuthenticationManager authenticationManager) { super(tokenServices, clientDetailsService, requestFactory); this.authenticationManager = authenticationManager; } @Override public OAuth2Authentication grant(String grantType, TokenRequest tokenRequest) { // 提取请求参数中的用户名密码 String username = tokenRequest.getRequestParameters().get("username"); String password = tokenRequest.getRequestParameters().get("password"); if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) { throw new InvalidGrantException("用户名和密码不能为空"); } // 校验用户账号密码 try { Authentication auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password)); SecurityContextHolder.getContext().setAuthentication(auth); } catch (AuthenticationException e) { throw new InvalidGrantException("用户名或密码错误"); } return super.grant(grantType, tokenRequest); } }
- 在授权服务配置中替换默认的令牌颁发器
@Override public void configure(final AuthorizationServerEndpointsConfigurer endpoints) { // 注册自定义的令牌颁发器 List<TokenGranter> granters = new ArrayList<>(); granters.add(new CustomClientCredentialsTokenGranter(endpoints.getTokenServices(), endpoints.getClientDetailsService(), endpoints.getOAuth2RequestFactory(), authenticationManager)); endpoints.tokenGranter(new CompositeTokenGranter(granters)) .accessTokenConverter(accessTokenConverter()) .userDetailsService(userService) .authenticationManager(authenticationManager); }
内容的提问来源于stack exchange,提问作者breakline
相关产品推荐
相关产品推荐

