是否可以在没有客户端密码的情况下从 Spring OAuth2 服务器获取 access_token?
Posted
技术标签:
【中文标题】是否可以在没有客户端密码的情况下从 Spring OAuth2 服务器获取 access_token?【英文标题】:Is it possible to get an access_token from Spring OAuth2 server without client secret? 【发布时间】:2017-09-07 11:16:57 【问题描述】:我正在使用 Spring Security 的 OAuth2 服务器实现。我正在尝试使用 OAuth2“密码”授权类型从服务器的 /oauth/token
端点获取 access_token,方法是仅提供用户名和密码以及没有客户端密码的客户端 ID。
只要我在我的 HTTP 请求的 Authorization
标头中提供客户端 ID 和客户端密码,就可以正常工作,如下所示:
curl -u clientid:clientsecret http://myhost ... -d "grant_type=password&username=user&password=pw&client_id=OAUTH_CLIENT"
按照此处的建议:Spring OAuth2 disable HTTP Basic Auth for TokenEndpoint,我设法为/auth/token
端点禁用了 HTTP 基本身份验证。但是当我尝试像这样通过 cURL 获取 access_token 时:
curl http://myhost ... -d "grant_type=password&username=user&password=pw&client_id=OAUTH_CLIENT"
我收到了BadCredentialsException
并且可以看到消息:
身份验证失败:密码与存储的值不匹配
在我的服务器日志中。此时我有点恼火,因为据我了解,此消息仅在用户名和/或密码有问题时才会出现,而不是客户端 ID 和/或密码有问题。在 cURL 命令中额外提供客户端密码后,如下所示:
curl http://myhost ... -d "grant_type=password&username=user&password=pw&client_id=OAUTH_CLIENT&client_secret=SECRET"
一切又好了。
这是否意味着我必须以一种或另一种方式提供客户端密码才能访问/auth/token
端点?
PS:我知道关于安全性,通过 HTTP 基本身份验证保护此端点通常是一个好主意,但在某些用例中人们宁愿不这样做。
编辑:
我似乎找到了一种省略客户端密码的方法。这是我的 OAuth2 服务器配置(注意对 allowFormAuthenticationForClients()
和 autoApprove(true)
的调用):
@Configuration
@EnableAuthorizationServer
class OAuth2Config extends AuthorizationServerConfigurerAdapter
private final AuthenticationManager authenticationManager;
public OAuth2Config(AuthenticationManager authenticationManager)
this.authenticationManager = authenticationManager;
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception
endpoints.authenticationManager(this.authenticationManager);
@Override
public void configure(AuthorizationServerSecurityConfigurer oauth) throws Exception
// allows access of /auth/token endpoint without HTTP Basic authentication
oauth.allowFormAuthenticationForClients();
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception
clients
.inMemory()
.withClient("acme")
.autoApprove(true) // <- allows for client id only
.authorizedGrantTypes("authorization_code", "refresh_token", "password").scopes("openid");
编辑二:
这里的问题:Spring Security OAuth 2.0 - client secret always required for authorization code grant 与此问题密切相关,但处理的是 OAuth2 授权类型“授权代码”,这会导致与授权类型“密码”不同的工作流程。
【问题讨论】:
你能看到this question吗? 查看答案***.com/a/57081799/3090180 【参考方案1】:根据规范 (RFC 6749),如果您的应用程序的客户端类型是 public,则不需要客户端密码。相反,如果客户端类型是机密,则需要客户端机密。
如果 Spring 提供了设置客户端类型的 API,请尝试将客户端类型设置为 public。
【讨论】:
接受指向规范。似乎问题编辑中描述的解决方案根据需要将客户端类型设置为公共。【参考方案2】:Spring Boot 的实现需要传入一个 client-secret 来进行身份验证。但是,您可以通过创建 AuthorizationServerConfigurer
类型的 bean 并自己配置它来覆盖它。 This is the link to the documenation...
【讨论】:
【参考方案3】:使用基本身份验证,但密码为空。
【讨论】:
【参考方案4】:在AuthorizationServerConfigurerAdapter
的实现中覆盖configure
并将密码编码器设置为原始文本编码器(不要将其用作默认密码编码器!)。
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception
oauthServer.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()")
.passwordEncoder(plainTextPasswordEncoder())
.allowFormAuthenticationForClients();
private PasswordEncoder plainTextPasswordEncoder()
return new PasswordEncoder()
@Override
public boolean matches(CharSequence rawPassword, String encodedPassword)
return !StringUtils.hasText(encodedPassword) || passwordEncoder.matches(rawPassword, encodedPassword);
@Override
public String encode(CharSequence rawPassword)
return passwordEncoder.encode(rawPassword);
;
现在,对于 OAuth 客户端详细信息(在内存或数据库中),将客户端密码设置为 null
。在这种情况下,客户端将被视为公共的,不需要client_secret
参数。如果您为 OAuth 客户端详细信息(例如 BCrypt 哈希)设置客户端机密,则客户端将被视为机密。它将依赖默认密码编码器(例如 BCrypt)并需要发送client_secret
参数以获得访问令牌。
【讨论】:
以上是关于是否可以在没有客户端密码的情况下从 Spring OAuth2 服务器获取 access_token?的主要内容,如果未能解决你的问题,请参考以下文章
是否可以在没有警报视图的情况下从 iPhone 中删除照片?
是否可以在未安装 VS 的情况下从 MSBuild 命令行运行 FxCop 代码分析?
是否可以在没有画布的情况下从 ImageBitMap Web 对象中获取像素?
是否可以在没有原始 .fla 的情况下从 documentClass 文件 (.as) 生成 SWF?