如何获取OpenIdConnectOptions StateDataFormat [英] How to get OpenIdConnectOptions StateDataFormat
问题描述
我有一个使用 IdentityServer4 的自定义Open Id Connect服务器.该SSO服务器具有用于非标准Open Id Connect操作的自定义终结点.
I have a custom Open Id Connect server using IdentityServer4. This SSO server has a custom endpoint for a non-standard Open Id Connect operation.
为了使用此操作,我需要在客户端应用程序的请求中创建一个状态参数.客户端应用程序是带有blazor服务器端的dotnet core 3.0预览应用程序.
In order to use this operation I need to create a state parameter in the client application's request. The client application is a dotnet core 3.0 preview application with blazor server side.
我正在通过以下方式注册SSO提供者:
I am registering the SSO provider with the following:
services.AddAuthentication(options => {
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = "oidc";
})
.AddCookie()
.AddOpenIdConnect("oidc", options => {
options.ClientId = oidcClientId;
options.ClientSecret = "secret";
options.Authority = "https://test.org";
options.ResponseType = "code id_token";
options.Scope.Clear();
options.Scope.Add("openid");
options.Scope.Add("extra");
options.GetClaimsFromUserInfoEndpoint = true;
options.SaveTokens = true;
options.RequireHttpsMetadata = false;
});
基本的登录/注销流程可以按预期工作,并且没有任何问题.
The basic login/logout flow works as expected and does not have any issues.
我为使用自定义SSO功能而生成的自定义链接如下所示(剃刀):
The custom link I generate to use the custom SSO function looks like the following (razor):
<a href=@($"https://test.org/custom/change-organization/{organization.OrganizationCode}?client_id=local-data-manager&redirect_uri=http://localhost:5000/signin-oidc&response_type=code id_token&scope=openid custom profile&nonce={GenerateNonce()}&state={GenerateState()}")>@organization.Name</a>
使用已定义的方法:
private string GenerateNonce()
{
string nonce = Convert.ToBase64String(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString() + Guid.NewGuid().ToString()));
return DateTime.UtcNow.Ticks.ToString(CultureInfo.InvariantCulture) + "." + nonce;
}
private string GenerateState()
{
var state = GenerateNonce();
AuthenticationProperties authProperties = new AuthenticationProperties
(
new Dictionary<string, string>
{
{ OpenIdConnectDefaults.UserstatePropertiesKey, state },
}
);
authProperties.RedirectUri = "http://localhost:5000";
//This StateDataFormat does not use the correct DataProtectionProvider
return openIdOptions.CurrentValue.StateDataFormat.Protect(authProperties);
}
其中 openIdOptions
是依赖项注入的地方.作为 @inject IOptionsMonitor< OpenIdConnectOptions>openIdOptions
Where openIdOptions
is dependency injected. As @inject IOptionsMonitor<OpenIdConnectOptions> openIdOptions
当我单击标记并触发自定义流程时,一切都会在SSO端按预期工作,但是当消息返回时,出现以下错误:
When I click the tag and trigger the custom flow everything works as expected on the SSO side, but when the message comes back I get the following error:
An unhandled exception has occurred while executing the request.
System.Exception: An error was encountered while handling the remote login.
System.Exception: Unable to unprotect the message.State.
这被抛出的noreferrer>会调用 Unprotect
,它与我之前注入的 StateDataFormat
保护器相同:
This is thrown from the OpenIdHandler which calls Unprotect
on what I would assume to be the same StateDataFormat
protector as was injected earlier:
Options.StateDataFormat.Unprotect(message.State);
从详细的日志记录中,我在调用 GenerateState()
时看到以下内容:
From verbose logging I see the following when calling GenerateState()
:
trce: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector[31]
Performing protect operation to key {cdf7e79b-8d1a-4e7e-a093-fea402dbba8c} with purposes ('/app/DataManager', 'Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler', '', 'v1').
但是当请求返回时,我会得到取消保护的日志:
But when the request comes back I get the unprotect log:
trce: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector[5]
Performing unprotect operation to key {cdf7e79b-8d1a-4e7e-a093-fea402dbba8c} with purposes ('/app/DataManager', 'Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler', 'oidc', 'v1').
主要区别在于DataProtector的用途"不同(一个具有",一个具有"oidc").根据文档,这意味着它们被不同地加密和解密.
The key difference is that the DataProtector "purposes" are different ( one having '' and one having 'oidc'). Which according to the documentation means they are being encrypted and decrypted differently.
我希望数据保护器是相同的,因为它们都引用已配置的相同 OpenIdConnectOptions
.
I would expect the data protectors to be the same as they both refer to the same OpenIdConnectOptions
that are configured.
为什么两个 DataProtector
提供不同的目的?它们是不同的对象吗?我的配置中缺少什么吗?如何从内部框架中获得相同的提供程序以及注入的内容?
Why is that the two DataProtector
's are providing different purposes? Are they different objects? Am I missing something in my configuration? How do I get the same provider from the internal framework and what I inject?
推荐答案
我发现,除了生成状态字符串外,我还必须添加一个Correlation Cookie.请参阅 RemoteAuthenticationHandel.cs
上的 GenerateCorrelationId
方法,此处
I found that in addition to Generating the state string, I also had to add a Correlation Cookie. See the GenerateCorrelationId
method on the RemoteAuthenticationHandel.cs
here https://github.com/dotnet/aspnetcore/blob/c925f99cddac0df90ed0bc4a07ecda6b054a0b02/src/Security/Authentication/Core/src/RemoteAuthenticationHandler.cs#L220
我还发现我必须在 AuthenticationProperties
对象(.xsrf,.redirect等)上添加正确的键/值对
I also found I had to add the correct key/value pairs on the AuthenticationProperties
object (.xsrf, .redirect, etc)
我的代码看起来像这样方法
My code looks something like this Methods
private string GenerateState(OpenIdConnectOptions openIdOptions, string nonce)
{
AuthenticationProperties authProperties = new AuthenticationProperties();
authProperties.Items.Add(".xsrf", nonce);
authProperties.Items.Add(".redirect", "/");
authProperties.Items.Add("OpenIdConnect.Code.RedirectUri", $"https://{this.Request.Host}/signin-auth0";
//This StateDataFormat does not use the correct DataProtectionProvider
return openIdOptions.StateDataFormat.Protect(authProperties);
}
private string GenerateNonce()
{
string nonce = Convert.ToBase64String(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString() + Guid.NewGuid().ToString()));
return DateTime.UtcNow.Ticks.ToString(CultureInfo.InvariantCulture) + "." + nonce;
}
主控制器动作
OpenIdConnectOptions opts = _openIdOptions.Get("Auth0");
string correlationId = GenerateNonce();
string state = GenerateState(opts, correlationId);
string cookieName = opts.CorrelationCookie.Name + correlationId;
CookieOptions cookieOptions = opts.CorrelationCookie.Build(this.HttpContext, DateTime.UtcNow);
Response.Cookies.Append(cookieName, "N", cookieOptions);
ViewBag.State = state;
return View();
将状态变量传递给外部提供程序将返回到OpenIdConnector中间件,并且应该正确验证.
Passing the state variable to the external provider will be returned to the OpenIdConnector middleware and should validate correctly.
这篇关于如何获取OpenIdConnectOptions StateDataFormat的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!