AuthorizationCodeProvider:从不调用Create,如何生成授权码? [英] AuthorizationCodeProvider: Create is never called, how do I generate the authorization code?

查看:89
本文介绍了AuthorizationCodeProvider:从不调用Create,如何生成授权码?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在设置自己的OAuth2服务器.到目前为止,我已经在OAuthAuthorizationServerProvider的实现中成功实现了GrantResourceOwnerCredentials.现在,因为我正在为我们的业务开发应用程序,所以我想实现OAuth2授权代码授予.

I'm setting up my own OAuth2 server. So far, I have succesfully implemented GrantResourceOwnerCredentials in my implementation of OAuthAuthorizationServerProvider. Now, because I am developing an app for our business, I want to implement the OAuth2 Authorization Code grant.

我尝试按照此处的说明进行操作

I have tried to follow directions here https://docs.microsoft.com/en-us/aspnet/aspnet/overview/owin-and-katana/owin-oauth-20-authorization-server but in my implementation, I have not found how to reach the Create call of the AuthorizationCodeProvider (which I set in OAuthAuthorizationServerOptions).

我已经简短地检查了使用(错误的)代码参数访问TokenEndpointPath是否可行,并且在调试器中看到我的AuthorizationCodeProviderReceive调用被命中了.当然没有成功,因为我发送的代码是"sometestcode"而不是真实的代码,但是代码被命中,这意味着我处在正确的道路上.

I have briefly checked whether accessing the TokenEndpointPath with a (wrong) code parameter works, and in the debugger I see that my AuthorizationCodeProvider's Receive call is hit. Of course there is no success because the code I send is 'sometestcode' instead of a real one, but the code is hit so that means I'm on the right path.

这是我到目前为止所拥有的:

Here's what I have so far:

    public override Task ValidateClientRedirectUri(OAuthValidateClientRedirectUriContext context)
    {
        if (OAuthRepository.GetClient(context.ClientId) != null)
        {
            var expectedRootUri = new Uri(context.Request.Uri, "/");

            if (context.RedirectUri.StartsWith(expectedRootUri.AbsoluteUri))
            {
                context.Validated();
                return Task.FromResult<object>(null);
            }
        }

        context.Rejected();
        return Task.FromResult<object>(null);
    }

    public override Task AuthorizeEndpoint(OAuthAuthorizeEndpointContext context)
    {
        // I know this is wrong but it's just a start and not the focus of this SO question.
        context.Response.Redirect(context.AuthorizeRequest.RedirectUri);
        context.RequestCompleted();
        return Task.FromResult<object>(null);
    }

    public override Task GrantAuthorizationCode(OAuthGrantAuthorizationCodeContext context)
    {
        // Needs additional checks, not the focus of my question either 
        var newTicket = new AuthenticationTicket(context.Ticket.Identity, context.Ticket.Properties);
        context.Validated(newTicket);
        return Task.FromResult<object>(null);
    }

现在,当我用redirect_uri调用我的AuthorizeEndpointPath时,我会立即被发送到 that Uri.我知道这是错误的:应该将我发送到单独的登录页面.稍后我将修复我的Web API,以重定向到正确的Uri.

Now, when I call my AuthorizeEndpointPath with a redirect_uri, I am sent to that Uri immediately. I know this is wrong: I should be sent to a separate login page. I'll fix my Web API later to redirect to the correct Uri.

我的问题的重点是:我现在正在实现登录页面,但是在用户登录后,我不知道如何从WebAPI获取授权代码.(我跳过了暂时同意),并假设如果用户登录后可以接受,我将在稍后添加给予同意.)

The focus of my question is this: I am now in the process of implementing the login page, but I do not know how to get the authorization code from my WebAPI after the user has logged in. (I'm skipping the consent part for now and assume that if the user is logged in they're okay with it, I'll add giving consent later.)

我的流程基于此处共享的图 https://docs.apigee.com/api-platform/security/oauth/oauth-v2-policy-authorization-code-grant-type

I am basing my flow on the diagram shared here https://docs.apigee.com/api-platform/security/oauth/oauth-v2-policy-authorization-code-grant-type

我正在使用Thinktecture IdentityModel在MVC控制器中创建登录页面.现在,我需要从MVC控制器中的Web API检索授权代码.之后,我可以将用户重定向回请求授权码流的原始客户端(应用).

I am using Thinktecture IdentityModel to create the login page in an MVC Controller. Now I need to retrieve the authorization code from the Web API in my MVC Controller. And after that I can then redirect the user back to the original client (app) that requested the Authorization Code flow.

要从Web API获取授权代码,我在Thinktecture的OAuth2Client中看到了三种方法:

To obtain the authorization code from my Web API, I see three methods in Thinktecture's OAuth2Client:

  • CreateAuthorizeUrl
  • CreateCodeFlowUrl
  • RequestAuthorizationCodeAsync

似乎都没有做我想要的.如何进行操作,以便调用我的WebAPI生成代码?

Neither seem to do what I want. How do I proceed so that my WebAPI is called to generate the code?

    [HttpGet]
    [ImportModelStateFromTempData]
    public ActionResult Authorize(string clientId, string returnUrl, string responseType)
    {
        AuthorizeViewModel viewModel = new AuthorizeViewModel();
        ...
        ... 
        ...
        return View(viewModel);
    }

    [HttpPost]
    [ExportModelStateToTempData]
    public async Task<ActionResult> Authorize(AuthorizeViewModel viewModel)
    {
        // NOTE: This is in MVC and is postback from *.cshtml View.
        OAuth2Client.?????? // <=== How to obtain authorization code from WebAPI?

        ...
        return Redirect(returnUrl);
    }

我认为我已经在Web API端正确设置了它.我只是不知道该怎么打流程的Create部分.我希望有人能帮助我理解我所没有看到的.我认为某个地方有一个盲点...

I think I have it correctly setup on the Web API side. I just don't know how to hit the Create part of the flow. I hope someone can help me understand what I am not seeing. I have a blind spot somewhere I think...

我如何让OAuth2Client从我的WebAPI获得授权代码?

How do I have OAuth2Client get me the authorization code from my WebAPI?

也在使用Postman测试我的Web API.如果有人可以帮助我获取返回授权码的Web API 2.0中的URL,我也将其作为答案.然后我可以自己用MVC编写代码.

I am also using Postman to test my Web API. If anyone can help me get the URL in Web API 2.0 that returns an authorization code, I would also accept that as an answer. Then I can write the code in MVC myself.

好的,所以我认为我找到了盲点的一部分.首先,我将"AuthorizeEndpoint"标记为不是这个SO问题的重点",但这是一个很大的错误.

Okay, so I think I found a part of my blind spot. Firstly, I marked `AuthorizeEndpoint' as "not the focus of this SO question", but that was a big mistake.

当我像这样修改AuthorizeEndpoint时:

When I adapt the AuthorizeEndpoint like so:

    public override Task AuthorizeEndpoint(OAuthAuthorizeEndpointContext context)
    {
        System.Security.Claims.ClaimsIdentity ci = new System.Security.Claims.ClaimsIdentity("Bearer");
        context.OwinContext.Authentication.SignIn(ci);
        context.RequestCompleted();
        return Task.FromResult<object>(null);
    }

如果我像这样修改AuthorizationCodeProvider.Create的实现,则:

And if I adapt my implementation of AuthorizationCodeProvider.Create like so:

    public void Create(AuthenticationTokenCreateContext context)
    {
        context.Ticket.Properties.IssuedUtc = DateTime.UtcNow;
        context.Ticket.Properties.ExpiresUtc = DateTime.UtcNow.AddSeconds(60);

        // Some random Guid
        context.SetToken(Guid.NewGuid().ToString("n"));
    }

使用查询参数code=<THE_RANDOM_GUID> 将对/authorize的任何调用都重定向到redirect_uri ! :D

Any call to /authorize is redirected to redirect_uri with a query parameter code=<THE_RANDOM_GUID>! :D

很明显,此实现不在应有的位置,因此我的问题尚未解决.剩余的问题:

Obviously, this implementation is not where it should be, so my question is not yet resolved. Remaining issues:

  • 现在,任何人都可以请求授权码,client_id被忽略. ValidateClientAuthentication显然没有作为AuthorizeEndpoint的一部分被命中.如何在AuthorizeEndpoint中获取ClientId?
  • 授权代码未耦合到客户端.任何拦截代码的人都可以使用它.如何在AuthorizationCodeProvider.Create中获取ClientId,以便可以将其与代码一起存储?
  • 授权代码根本没有耦合到用户,它是一个空的ClaimsIdentity.如何在两者之间放置一个用户登录页面,并在AuthorizeEndpoint中获取已登录用户的ClaimsIdentity?
  • Right now, anybody can request an authorization code, the client_id is ignored. ValidateClientAuthentication is apparently not hit as part of AuthorizeEndpoint. How do I obtain ClientId in AuthorizeEndpoint?
  • The authorization code is not coupled to a client. Anyone who intercepts the code could use it. How do I obtain the ClientId in AuthorizationCodeProvider.Create so that I can store it with the code?
  • The authorization code is not coupled to a user at all, it's an empty ClaimsIdentity. How do I put a user-login page in between and in AuthorizeEndpoint obtain the ClaimsIdentity for the logged-in user?

推荐答案

因此,在网上进行了大量搜索之后,我通过搜索github获得了一些成功.显然,OAuthAuthorizationServerProvider提供了AuthorizeEndpoint,并且该方法应同时用于嘿,您没有权限,请登录!"以及啊,好极了,这是授权码".我曾期望OAuthAuthorizationServerProvider为此可以有两种单独的方法,但事实并非如此.这就解释了为什么在github上,我找到一些以特殊方式实现AuthorizeEndpoint的项目.我已经采纳了.这是一个示例:

So, after quite some searching online, I got some success by searching github. Apparently, OAuthAuthorizationServerProvider offers AuthorizeEndpoint and that method should be used for both "Hey, you're not authorized, go log in you!" as well as for "Ahh, okay you're cool, here's an authorization code.". I had expected that OAuthAuthorizationServerProvider would have two separate methods for that, but it doesn't. That explains why on github, I find some projects that implement AuthorizeEndpoint in a rather peculiar way. I've adopted this. Here's an example:

public override async Task AuthorizeEndpoint(OAuthAuthorizeEndpointContext context)
{
    if (context.Request.User != null && context.Request.User.Identity.IsAuthenticated)
    {
        var redirectUri = context.Request.Query["redirect_uri"];
        var clientId = context.Request.Query["client_id"];

        var authorizeCodeContext = new AuthenticationTokenCreateContext(
            context.OwinContext, 
            context.Options.AuthorizationCodeFormat,
            new AuthenticationTicket(
                (ClaimsIdentity)context.Request.User.Identity,
                new AuthenticationProperties(new Dictionary<string, string>
                {
                    {"client_id", clientId},
                    {"redirect_uri", redirectUri}
                })
            {
                IssuedUtc = DateTimeOffset.UtcNow,
                ExpiresUtc = DateTimeOffset.UtcNow.Add(context.Options.AuthorizationCodeExpireTimeSpan)
            }));

        await context.Options.AuthorizationCodeProvider.CreateAsync(authorizeCodeContext);

        context.Response.Redirect(redirectUri + "?code=" + Uri.EscapeDataString(authorizeCodeContext.Token));
    }
    else
    {
        context.Response.Redirect("/account/login?returnUrl=" + Uri.EscapeDataString(context.Request.Uri.ToString()));
    }
    context.RequestCompleted();
}

来源: https://github.com/wj60387/WebApiOAUthBase/blob/master/OwinWebApiBase/WebApiOwinBase/Providers/OAuthServerProvider.cs

关于我剩下的三个问题:

As for my remaining three questions:

  1. 现在,任何人都可以请求授权码,client_id被忽略. ValidateClientAuthentication显然未作为AuthorizeEndpoint的一部分命中.如何在AuthorizeEndpoint中获取ClientId?

答案:您必须实现"ValidateClientAuthentication".

Answer: You have to implement `ValidateClientAuthentication'.

  1. 授权代码未耦合到客户端.任何拦截代码的人都可以使用它.如何在AuthorizationCodeProvider.Create中获取ClientId,以便可以将其与代码一起存储?

答案:OAuthAuthorizationServerProvider会处理此问题.只要您在票证中设置"client_id",它就会检查请求访问令牌以获取授权码的客户端是否相同.

Answer: OAuthAuthorizationServerProvider takes care of this. As long as you set "client_id" in the ticket, it will check that the client that requests an access token for the authorization code is the same.

  1. 授权代码根本没有耦合到用户,它是一个空的ClaimsIdentity.如何在两者之间放置一个用户登录页面,并在AuthorizeEndpoint中获取登录用户的ClaimsIdentity?

回答:您将创建一个单独的登录页面.这样做是使用户登录.如果您的WebAPI使用基于cookie的身份验证,则可以再次将用户重定向到AuthorizeEndpoint.如果您使用访问令牌,则您的登录页面必须使用访问令牌向"AuthorizeEndpoint"发出请求,以获取授权码. (不要将访问令牌提供给第三方.您的登录页面会请求授权代码并将其发送回去.)换句话说,如果您使用访问令牌,则此流程中涉及两个客户端.

Answer: You create a separate login page. What this does is sign the user in. If your WebAPI uses cookie-based authentication, you can just redirect the user to the AuthorizeEndpoint again. If you use access tokens, your login page has to make a request to `AuthorizeEndpoint' with the access token to obtain an authorization code. (Don't give the access token to the third party. Your login page requests the authorization code and sends that back.) In other words, if you use access tokens then there are two clients involved in this flow.

这篇关于AuthorizationCodeProvider:从不调用Create,如何生成授权码?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆