我正在设置自己的OAuth2服务器。到目前为止,我已经在GrantResourceOwnerCredentials
的实现中成功实现了OAuthAuthorizationServerProvider
。现在,因为我正在为我们的业务开发应用程序,所以我想实现OAuth2授权代码授予。
我尝试遵循此处的说明https://docs.microsoft.com/en-us/aspnet/aspnet/overview/owin-and-katana/owin-oauth-20-authorization-server,但是在实现中,我没有找到如何到达Create
的{{1}}调用(我在{{1}中进行了设置) }。
我已经简短地检查了使用(错误的)代码参数访问AuthorizationCodeProvider
是否可行,并且在调试器中,我看到了OAuthAuthorizationServerOptions
的{{1}}调用被击中。当然不会成功,因为我发送的代码是“ sometestcode”而不是真实的代码,但是代码被命中,这意味着我处在正确的道路上。
这是我到目前为止所拥有的:
TokenEndpointPath
现在,当我用AuthorizationCodeProvider
呼叫我的Receive
时,我会立即被发送到那个 Uri。我知道这是错误的:应该将我发送到单独的登录页面。稍后我将修复Web API,以重定向到正确的Uri。
我的问题的重点是:我现在正在实现登录页面,但是在用户登录后,我不知道如何从WebAPI获取授权代码。(我跳过了暂时同意),并假设如果用户登录后可以接受,我将在以后添加给予同意。)
我的流程基于此处https://docs.apigee.com/api-platform/security/oauth/oauth-v2-policy-authorization-code-grant-type共享的图
我正在使用Thinktecture IdentityModel在MVC控制器中创建登录页面。现在,我需要从MVC控制器中的Web API检索授权代码。之后,我可以将用户重定向回请求授权码流的原始客户端(应用)。
要从我的Web API获取授权代码,我在Thinktecture的OAuth2Client中看到了三种方法:
似乎都没有做我想要的。如何进行操作,以便调用我的WebAPI生成代码?
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);
}
我认为我已经在Web API端正确设置了它。我只是不知道如何实现流程的AuthorizeEndpointPath
部分。我希望有人能帮助我理解我所没有看到的。我认为某个地方有一个盲点...
我如何让OAuth2Client从我的WebAPI获得授权代码?
我也使用Postman测试我的Web API。如果有人可以帮助我获得返回授权码的Web API 2.0中的URL,我也将其作为答案。然后我可以自己用MVC编写代码。
好的,所以我认为我发现了盲点的一部分。首先,我将“ AuthorizeEndpoint”标记为“不是这个SO问题的重点”,但这是一个很大的错误。
当我像这样修改AuthorizeEndpoint时:
redirect_uri
如果我像这样修改 [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);
}
的实现,则:
Create
使用查询参数 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
的任何调用都重定向到 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"));
}
! :D
很显然,此实现不在应有的位置,因此我的问题尚未解决。剩余的问题:
/authorize
显然没有被打为redirect_uri
的一部分。如何在AuthorizeEndpoint中获取ClientId?code=<THE_RANDOM_GUID>
中的ClientId,以便将其与代码一起存储? ValidateClientAuthentication
? 答案 0 :(得分:0)
因此,在网上进行了大量搜索之后,我通过搜索github获得了一些成功。显然,OAuthAuthorizationServerProvider
提供了AuthorizeEndpoint
,并且该方法应同时用于“嘿,您未被授权,请登录!”以及“啊,好极了,这是授权码”。我曾预期OAuthAuthorizationServerProvider
可以有两种单独的方法,但事实并非如此。这就解释了为什么在github上,我找到一些以特殊方式实现AuthorizeEndpoint
的项目。我已经采纳了。这是一个示例:
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();
}
关于我剩下的三个问题:
答案:您必须实现“ ValidateClientAuthentication”。
答案:OAuthAuthorizationServerProvider
会处理这个问题。只要您在票证中设置“ client_id”,它就会检查请求授权码访问令牌的客户端是否相同。
回答:您将创建一个单独的登录页面。这样做是使用户登录。如果您的WebAPI使用基于cookie的身份验证,则可以再次将用户重定向到AuthorizeEndpoint
。如果您使用访问令牌,则您的登录页面必须使用访问令牌向“ AuthorizeEndpoint”发出请求,以获取授权码。 (不要将访问令牌提供给第三方。您的登录页面会请求授权码并将其发送回去。)换句话说,如果您使用访问令牌,那么此流程中将涉及两个客户端。