问题描述
我已经正确设置了 OpenIddict,并且运行良好。
现在,我需要与之交互的应用程序之一只能使用 Authorization 标头执行 POST someurl。我无法控制此应用。
我尝试向我的服务器添加另一条路由:
[EnableCors]
[HttpPost("TokensDev"),Produces("application/json")]
public async Task<IActionResult> ExchangeDev()
{
if (! this.Request.Headers.TryGetValue("Authorization",out var authHeader_))
return Unauthorized();
var authHeader = AuthenticationHeaderValue.Parse(authHeader_);
var credentialBytes = Convert.FromBase64String(authHeader.Parameter);
var credentials = Encoding.UTF8.GetString(credentialBytes).Split(new[] { ':' },2);
var user = await _userManager.FindByNameAsync(credentials[0]);
if (user == null)
return Unauthorized();
var result = await _signInManager.CheckPasswordSignInAsync(user,credentials[1],lockoutOnFailure: true);
if (!result.Succeeded)
return Unauthorized();
var principal = await _signInManager.createuserPrincipalAsync(user);
var ticket = new AuthenticationTicket(principal,new AuthenticationProperties(),OpenIddictServerDefaults.AuthenticationScheme);
foreach (var claim in ticket.Principal.Claims)
{
claim.SetDestinations(GetDestinations(claim,ticket));
}
return SignIn(ticket.Principal,ticket.Properties,ticket.AuthenticationScheme);
}
但是,问题是 OpenIddict 阻止了:
fail: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
An unhandled exception has occurred while executing the request.
system.invalidOperationException: An authorization or token response cannot be returned from this endpoint.
at AspNet.Security.OpenIdConnect.Server.OpenIdConnectServerHandler.SignInAsync(AuthenticationTicket ticket)
at Microsoft.AspNetCore.Authentication.AuthenticationService.SignInAsync(HttpContext context,String scheme,ClaimsPrincipal principal,AuthenticationProperties properties)
at Microsoft.AspNetCore.Mvc.SignInResult.ExecuteResultAsync(ActionContext context)
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeResultAsync(IActionResult result)
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResultFilterasync[TFilter,TFilterasync]()
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResultExecutedContext context)
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.ResultNext[TFilter,TFilterasync](State& next,Scope& scope,Object& state,Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeResultFilters()
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter()
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(State& next,Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync()
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync()
at Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
有没有办法配置 OpenIddict 以允许这样做?
注意:我尝试直接对 OpenId 和 Basic Authorization 使用相同的方法,但是在这种情况下 OpenIddict 拒绝 CORS 协商...
解决方法
在深入研究 OpenIddict 代码数小时后,我找到了一种方法来做我需要的事情。
我不认为它很漂亮,但它有效:
[EnableCors]
[HttpPost("TokensDev"),Produces("application/json")]
public async Task<IActionResult> ExchangeDev()
{
if (! this.Request.Headers.TryGetValue("Authorization",out var authHeader_))
return Unauthorized();
var authHeader = AuthenticationHeaderValue.Parse(authHeader_);
var credentialBytes = Convert.FromBase64String(authHeader.Parameter);
var credentials = Encoding.UTF8.GetString(credentialBytes).Split(new[] { ':' },2);
var request = new OpenIdConnectRequest
{
GrantType = "password",Username = credentials[0],Password = credentials[1],Scope = "openid",};
request.SetProperty(OpenIdConnectConstants.Properties.MessageType,OpenIdConnectConstants.MessageTypes.TokenRequest);
HttpContext.SetOpenIdConnectRequest(request);
return await Exchange(); //this is the "normal" openid entry point
}
请注意,这仅是因为第 3 方应用程序正在使用 JSON 结果的 access_token 属性...