Spring Security OAuth 2.0 - 授权代码授予始终需要客户端密钥

时间:2016-03-04 00:11:32

标签: spring security oauth-2.0 spring-security-oauth2

根据规范,只要client_id包含在请求 client_id中,就不需要对使用授权代码授权的令牌进行身份验证}与用于生成代码的那个相同。但是,使用Spring Security OAuth 2.0实现,即使客户端从未被分配秘密,似乎始终需要/oauth/token端点上的基本身份验证。

由于isSecretRequired()接口中的ClientDetails方法,似乎支持允许没有机密的客户端。我需要做些什么才能在没有秘密的情况下通过/oauth/token URL验证客户端?

  

4.1.3。访问令牌请求

     

客户端通过发送
向令牌端点发出请求   以下参数使用" application / x-www-form-urlencoded"
  格式为附录B,HTTP中的字符编码为UTF-8   请求entity-body:

     

grant_type            需要。值必须设置为" authorization_code"。

     

代码            需要。从中收到的授权码            授权服务器。

     

REDIRECT_URI            需要,如果" redirect_uri"参数包含在            第4.1.1节中描述的授权请求及其            值必须相同。

     

CLIENT_ID            如果客户端未通过身份验证,则需要            授权服务器,如第3.2.1节中所述。

     

如果客户端类型是机密或客户端是客户端   凭证(或指定的其他认证要求),
  客户端必须按授权服务器进行身份验证,如上所述   在第3.2.1节中。

6 个答案:

答案 0 :(得分:6)

使用allowFormAuthenticationForClients()方法启用使用表单参数而不是基本身份验证来验证客户端,如下面的代码示例所示。

class AuthorizationServerConfigurer extends AuthorizationServerConfigurerAdapter {

    @Override
    void configure(AuthorizationServerSecurityConfigurer security) {
        security
                .tokenKeyAccess("permitAll()")
                .checkTokenAccess("isAuthenticated()")
                .allowFormAuthenticationForClients()
    }
}

allowFormAuthenticationForClients()方法触发添加ClientCredentialsTokenEndpointFilter,允许通过表单参数进行身份验证。

答案 1 :(得分:4)

Spring允许您使用空密钥定义OAuth2客户端。 这些可以被视为" public"客户或无法保密的客户。想想Javascript应用程序,移动应用程序,.....你通常不希望存储客户机密。

正如您所指出的,根据OAuth2规范,令牌端点可以选择不要求这些公共客户端的秘密。

所以在Spring中,只需定义一个空密钥的OAuth2客户端,并为一组有限的授权类型(authorization_code和refresh_token)配置它

Spring Security实现令牌url将接受令牌交换而没有该特定OAuth2客户端的客户端密钥。

答案 2 :(得分:0)

最初,我对接受的答案进行了类似的设置,这绝对是完成此工作的前提。但是缺少的是您不能简单地将密码设置为null。您必须将其设置为空密码,例如:

String secret = PasswordEncoderFactories.createDelegatingPasswordEncoder().encode("");
clientDetails.setClientSecret(secret);

如果您不这样做,您仍然会得到401!

答案 3 :(得分:0)

要解决此问题,请参见类loadUserByUsername的方法org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService

if (clientSecret == null || clientSecret.trim().length() == 0) {
   clientSecret = this.emptyPassword;
}

在您的情况下,emptyPassword可能尚未由密码编码器使用空的编码密码初始化。 在AuthorizationServerConfigurerAdapter中设置缺少的密码编码器:

@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) {
    oauthServer.passwordEncoder(passwordEncoder);
}

答案 4 :(得分:0)

这对我有用

    @Override
    public void configure(AuthorizationServerSecurityConfigurer cfg) throws Exception {
        cfg
            .tokenKeyAccess("permitAll()")
            .checkTokenAccess("isAuthenticated()")
            .allowFormAuthenticationForClients()
            .passwordEncoder(clientPasswordEncoder());
    }


    @Bean("clientPasswordEncoder")
    PasswordEncoder clientPasswordEncoder() {
        return new BCryptPasswordEncoder(4);
    }

测试1: enter image description here enter image description here

测试2: enter image description here

答案 5 :(得分:-1)

像这样:

@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
    clients.inMemory()
            .withClient("client").secret(PasswordEncoderFactories.createDelegatingPasswordEncoder().encode("")) //empty
            .authorizedGrantTypes("authorization_code", "refresh_token")
            .redirectUris("http://www.dev.com")
            .scopes("all")
            .autoApprove(true);
} @Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer)
        throws Exception {
    oauthServer.tokenKeyAccess("permitAll()")
            .checkTokenAccess("isAuthenticated()")
            .allowFormAuthenticationForClients();
}

没关系。