我正在尝试使用 DotNetOpenAuth 实现OAuth2授权服务器 . 客户端是基于JavaScript的,因此无法保守任何秘密 . 这与this question完全相同,但与另一个框架相同 .

客户端(使用令牌 endpoints ) access_tokenrefresh_token 请求以下参数:

  • grant_type :密码

  • username :foo

  • password :吧

这确实有效 . 现在我想使用 refresh_token 并使用以下参数对令牌 endpoints 发出请求:

  • grant_type :refresh_token

  • refresh_token :ABCDEF

这给了我以下回应:

{"error":"invalid_client","error_description":"The client secret was incorrect."}

哪个(至少有些)有意义,因为RFC6749表明:

由于刷新令牌通常是用于请求其他访问令牌的持久凭证,因此刷新令牌将绑定到发布它的客户端 . 如果客户端类型是机密的或客户端已获得客户端凭证(或分配了其他身份验证要求),则客户端必须使用授权服务器进行身份验证,如第3.2.1节中所述 .

如果我改变我的请求:

  • grant_type :refresh_token

  • refresh_token :ABCDEF

  • client_id :MYCLIENT

  • client_secret :CLIENT_SECRET

问题是我的客户端不应该保密(因为它毕竟是客户端JavaScript) .

这是客户端的定义方式:

New ClientDescription(ApiKey, New Uri(allowedCallback), ClientType.Public)

我搜索了DotNetOpenAuth源代码,发现没有使用 ClientType . 对我而言,它看起来根本就没用过 .

设置一个空的客户端密钥也是不可能的,因为DotNetOpenAuth源代码会主动检查这个( ClientAuthenticationModules.cs ):

if (!string.IsNullOrEmpty(clientSecret)) {
                    if (client.IsValidClientSecret(clientSecret)) {
                        return ClientAuthenticationResult.ClientAuthenticated;
                    } else { // invalid client secret
                        return ClientAuthenticationResult.ClientAuthenticationRejected;
                    }
                } else { // no client secret provided
                    return ClientAuthenticationResult.ClientIdNotAuthenticated;
                }

如果我看一下 MessageValidationBindingElement.cs

if (authenticatedClientRequest != null) {
            string clientIdentifier;
            var result = this.clientAuthenticationModule.TryAuthenticateClient(this.AuthServerChannel.AuthorizationServer, authenticatedClientRequest, out clientIdentifier);
            switch (result) {
                case ClientAuthenticationResult.ClientAuthenticated:
                    break;
                case ClientAuthenticationResult.NoAuthenticationRecognized:
                case ClientAuthenticationResult.ClientIdNotAuthenticated:
                    // The only grant type that allows no client credentials is the resource owner credentials grant.
                    AuthServerUtilities.TokenEndpointVerify(resourceOwnerPasswordCarrier != null, accessTokenRequest, Protocol.AccessTokenRequestErrorCodes.InvalidClient, this.clientAuthenticationModule, AuthServerStrings.ClientSecretMismatch);
                    break;
                default:
                    AuthServerUtilities.TokenEndpointVerify(false, accessTokenRequest, Protocol.AccessTokenRequestErrorCodes.InvalidClient, this.clientAuthenticationModule, AuthServerStrings.ClientSecretMismatch);
                    break;
            }

特别是注释唯一不允许客户端凭据的授权类型是资源所有者凭据授权 . 我好疑惑 . 这是否意味着在我的场景中JS客户端应该发送用户名/密码?不会这会引发以下异常:

AccessTokenResourceOwnerPasswordCredentialsRequest parameter 'grant_type' to have value 'password' but had 'refresh_token' instead.

哪个对我好,因为我不希望客户端保留密码 .

所以我的问题在这里:

  • 我是否对密码授予,refresh_token方案存在根本错误?

  • 正如我在JS客户端中看到的那样, client_id 是公共知识,所以它不用于任何安全目的 . 我对么?

  • 更改DotNetOpenAuth以使用 ClientType.Public 是否有意义?

  • 如果我只使用 client_idclient_secret 作为 not secret 会有什么不同吗?例如 . 只提供虚拟值?有什么安全隐患?