You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot OAuth请求/oauth/token返回401 Unauthorized问题排查

问题分析与解决方案

我帮你排查了下,调用/oauth/token返回401 Unauthorized的问题主要出在两个核心点上,下面是具体的修复步骤:

1. 未允许客户端通过表单提交凭证

你的curl请求是通过表单参数传递client_id和client_secret的,但AuthorizationServer的安全配置里没有开启允许这种认证方式的开关。默认情况下OAuth2要求客户端通过Basic Auth传递凭证,所以需要手动开启表单认证支持。

修改AuthorizationServerConfiguration中的configure(oauthServer)方法:

@Throws(Exception::class)
override fun configure(oauthServer: AuthorizationServerSecurityConfigurer?) {
    oauthServer!!.realm(REALM + "/client")
        .allowFormAuthenticationForClients() // 新增此行,允许表单提交客户端凭证
}

2. 缺失密码编码器(Spring Security 5强制要求)

Spring Security 5之后,所有密码(包括用户密码和客户端密钥)都必须经过密码编码器处理,不能直接使用明文。你的配置里不管是用户的登录密码还是客户端的secret都是明文,这会直接导致认证失败。

步骤1:添加密码编码器Bean

在OAuth2SecurityConfiguration中新增密码编码器的Bean(测试环境可以用NoOpPasswordEncoder,生产环境请务必替换为BCryptPasswordEncoder这类安全加密方式):

@Bean
fun passwordEncoder(): PasswordEncoder {
    // 测试用,生产环境推荐使用BCryptPasswordEncoder.getInstance()
    return NoOpPasswordEncoder.getInstance()
}

步骤2:给用户认证绑定密码编码器

修改globalUserDetails方法,指定密码编码器:

@Autowired
@Throws(Exception::class)
fun globalUserDetails(auth: AuthenticationManagerBuilder, passwordEncoder: PasswordEncoder) {
    auth.inMemoryAuthentication()
        .passwordEncoder(passwordEncoder) // 绑定密码编码器
        .withUser("bill").password("abc123").roles("ADMIN").and()
        .withUser("demo").password("1234").roles("USER")
}

步骤3:给客户端配置绑定密码编码器

在AuthorizationServerConfiguration中注入PasswordEncoder,然后修改客户端的secret配置:

@Autowired
private val passwordEncoder: PasswordEncoder? = null

@Throws(Exception::class)
override fun configure(clients: ClientDetailsServiceConfigurer?) {
    clients!!.inMemory()
        .withClient("client-id")
        .authorizedGrantTypes("password", "authorization_code", "refresh_token", "implicit")
        .authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT")
        .scopes("read", "write", "trust")
        .secret(passwordEncoder!!.encode("secret")) // 用编码器处理客户端密钥
        .accessTokenValiditySeconds(120)
        .refreshTokenValiditySeconds(600)
}

(如果用NoOpPasswordEncoder,encode方法会直接返回明文,也可以暂时保持.secret("secret"),但为了统一和扩展性,建议还是用编码器处理)

验证修改

完成以上修改后重启服务,再执行你的curl请求,应该就能成功获取access_token了。

另外提醒:生产环境绝对不能使用NoOpPasswordEncoder,一定要用BCryptPasswordEncoder这类安全加密方式,并且客户端密钥和用户密码都要提前加密好再配置。

内容的提问来源于stack exchange,提问作者user672009

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:11:47