8

我正在尝试使用authorization_code授权流程设置我的身份验证。我以前使用过它grant_type=password,所以我有点知道这些东西应该如何工作。但是在使用时grant_type=authorization_code,我不能让它返回任何东西invalid_grant

这是我的设置:

app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions
{
    AllowInsecureHttp = true,
    TokenEndpointPath = new PathString("/auth/token"),
    AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(5),
    Provider = new SampleAuthProvider()
});

app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions
{
    AuthenticationMode = Microsoft.Owin.Security.AuthenticationMode.Active,
    AuthenticationType = "Bearer"
});

SampleAuthProvider 是以下类:https ://gist.github.com/anonymous/8a0079b705423b406c00

基本上,它只是记录每一步并验证它。我尝试了请求:

POST http://localhost:12345/auth/token
grant_type=authorization_code&code=xxxxxx&client_id=xxxxx&redirect_uri=https://xxxx.com/
Content-Type: application/x-www-form-urlencoded

它正在经历:

  • OnMatchEndpoint
  • OnValidateClientAuthentication

就这样。我预计它会调用OnValidateTokenRequestOnGrantAuthorizationCode下一个,但它没有。我不知道为什么。

请求中的xxxx' 不是占位符,我这样尝试过。也许中间件会自行进行一些检查并因此拒绝请求?redirect_uri我尝试了with的变体http,没有任何协议,没有斜杠......

它也适用于自定义grant_type. 所以如果我太绝望了,我想我可以用它来模拟authorization_code,但我宁愿不必那样做。

TL;博士

我使用后的OAuthAuthorizationServerProvider回报。{"error":"invalid_grant"}OnValidateClientAuthenticationgrant_type=authorization_code

  • 为什么停在那里?
  • 我怎样才能使整个该死的事情发挥作用?

谢谢你的帮助!


编辑

正如 RajeshKannan 所指出的,我在配置中犯了一个错误。我没有提供AuthorizationCodeProvider实例。但是,这并没有完全解决问题,因为在我的情况下,代码不是由 发布的AuthorizationCodeProvider,我不能只是反序列化它。我对我开始工作的解决方法感到满意。

4

6 回答 6

13

这是我的工作。我对这个解决方案并不完全满意,但它确实有效,应该可以帮助其他人解决他们的问题。


所以,问题是我没有设置AuthorizationCodeProvider属性。当grant_type=authorization_code收到请求时,代码必须由该代码提供者验证。该框架假定代码是由该代码提供者发布的,但这不是我的情况。我从另一台服务器获取它,并且必须将代码发送回它以进行验证。

在标准情况下,您也是发布代码的人,RajeshKannan 提供的链接描述了您必须做的所有事情。

这里是你必须设置属性的地方:

app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions
{
    TokenEndpointPath = new PathString(Paths.TokenPath),
    Provider = new SampleAuthProvider(),
    AuthorizationCodeProvider = new MyAuthorizationCodeProvider ()
}

以及类的声明MyAuthorizationCodeProvider

internal class MyAuthorizationCodeProvider : AuthenticationTokenProvider
{
    public override async Task ReceiveAsync(
        AuthenticationTokenReceiveContext context)
    {
        object form;
        // Definitely doesn't feel right
        context.OwinContext.Environment.TryGetValue(
                "Microsoft.Owin.Form#collection", out form); 
        var redirectUris = (form as FormCollection).GetValues("redirect_uri");
        var clientIds = (form as FormCollection).GetValues("client_id");
        if (redirectUris != null && clientIds != null)
        {
            // Queries the external server to validate the token
            string username = await MySsoService.GetUserName(context.Token,
                                                             redirectUris[0]);
            if (!string.IsNullOrEmpty(username))
            {
                var identity = new ClaimsIdentity(new List<Claim>()
                {
                    // I need the username in  GrantAuthorizationCode
                    new Claim(ClaimTypes.NameIdentifier, username) 
                }, DefaultAuthenticationTypes.ExternalBearer);

                var authProps = new AuthenticationProperties();

                // Required. The request is rejected if it's not provided
                authProps.Dictionary.Add("client_id", clientIds[0]); 

                // Required, must be in the future
                authProps.ExpiresUtc = DateTimeOffset.Now.AddMinutes(1); 

                var ticket = new AuthenticationTicket(identity, authProps);
                context.SetTicket(ticket);
            }
        }
    }
}
于 2014-07-11T13:07:32.610 回答
5

我有同样的错误。我缺少的东西:

  • OAuthAuthorizationServerOptions.AuthorizationCodeProvider根据文档指定。
  • client_id向令牌端点发出请求时指定与 GET 参数相同的参数,就像收到authorization_code.
  • 覆盖OAuthAuthorizationServerProvider.ValidateClientAuthentication并在此方法中调用context.TryGetFormCredentials。这会将属性设置为GET 参数context.ClientId中的值。必须设置client_id此属性,否则您将收到错误消息。另外,调用.invalid_grantcontext.Validated()

完成上述所有操作后,我终于可以在令牌端点处将换成authorization_codean了。access_token

于 2017-12-06T11:17:33.660 回答
2

谢谢方案,我的代码缺少以下两个必需值。在这里发布以防其他人发现它有用:

            // Required. The request is rejected if it's not provided
            authProps.Dictionary.Add("client_id", clientIds[0]); 

            // Required, must be in the future
            authProps.ExpiresUtc = DateTimeOffset.Now.AddMinutes(1); 
于 2015-08-02T20:24:51.573 回答
1

确保您已配置授权服务器选项。我认为您应该提供您的授权端点详细信息:

 AuthorizeEndpointPath = new PathString(Paths.AuthorizePath)

在下面的链接中,将详细解释授权码授予,并列出了授权码授予生命周期中涉及的方法。

Owin Oauth 授权服务器

于 2014-07-04T20:36:40.980 回答
1

@dgn 的答案或多或少对我有用。这只是对此的扩展。事实证明,您可以向ClaimsIdentity构造函数提供您想要的任何字符串。以下内容同样有效,并兼作详细的代码注释:

var identity = new ClaimsIdentity(
    @"Katana - What a shitty framework/implementation.
    Unintuitive models and pipeline, pretty much have to do everything, and the docs explain nothing. 
    Like what can go in here? WTF knows but turns out as long as _something_ is in here, 
    there is a client_id key in your AuthenticationProperties with the same value as 
    what's set inside your implementation for OAuthAuthorizationServerProvider.ValidateClientAuthentication, and
    your AuthenticationProperties.ExpiresUtc is set to some time in the future, it works.
    Oh and you don't actually need to supply an implementation for OAuthAuthorizationServerProvider.GrantAuthorizationCode...
    but if you are using the resource owner grant type, you _do_ need to supply an implementation of 
    OAuthAuthorizationServerProvider.GrantResourceOwnerCredentials. Hmm. Whatever.
    Katana and IdenetityServer - two frameworks that are absolute garbage. In the amount of time it took me to
    figure out all the observations in this paragraph, I could've written my own /token endpoint."
);
于 2021-09-09T10:00:45.870 回答
0

我用下面最简单的例子解决了这个问题,并想分享它。希望有人觉得它有帮助。

--

似乎中间件将检查密钥是否redirect_uri存在于 的字典中AuthenticationProperties,将其删除并且一切正常(使用经过验证的上下文)。

一个简化的例子AuthorizationCodeProvider如下:

public class AuthorizationCodeProvider:AuthenticationTokenProvider {
    public override void Create(AuthenticationTokenCreateContext context) {
        context.SetToken(context.SerializeTicket());
    }

    public override void Receive(AuthenticationTokenReceiveContext context) {
        context.DeserializeTicket(context.Token);

        context.Ticket.Properties.Dictionary.Remove("redirect_uri"); // <-
    }
}

并且不要忘记在覆盖的方法中验证上下文OAuthAuthorizationServerProvider.ValidateClientAuthenticationApplicationOAuthProvider同样,这是一个从模板项目类继承的简化示例:

public partial class DefaultOAuthProvider:ApplicationOAuthProvider {
    public override Task ValidateClientRedirectUri(OAuthValidateClientRedirectUriContext context) {
        if(null!=context.RedirectUri) {
            context.Validated(context.RedirectUri);
            return Task.CompletedTask;
        }

        return base.ValidateClientRedirectUri(context);
    }

    public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context) {
        if(context.TryGetFormCredentials(out String clientId, out String clientSecret)) {
            // Specify the actual expected client id and secret in your case
            if(("expected-clientId"==clientId)&&("expected-clientSecret"==clientSecret)) {

                context.Validated(); // <-

                return Task.CompletedTask;
            }
        }

        return base.ValidateClientAuthentication(context);
    }

    public DefaultOAuthProvider(String publicClientId) : base(publicClientId) {
    }
}

请注意,如果您context.Validated使用特定的客户端 ID 调用,则必须将相同的 client_id 放入票证的属性中,您可以使用该方法执行此操作AuthenticationTokenProvider.Receive

于 2021-06-12T08:44:44.647 回答