首页 > 解决方案 > 如何获取 OpenIdConnectOptions StateDataFormat

问题描述

我有一个使用IdentityServer4的自定义 Open Id Connect 服务器。此 SSO 服务器具有用于非标准 Open Id Connect 操作的自定义端点。

为了使用此操作,我需要在客户端应用程序的请求中创建一个状态参数。客户端应用程序是带有 blazor 服务器端的 dotnet core 3.0 预览应用程序。

我正在使用以下内容注册 SSO 提供程序:

       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;
       });

基本的登录/注销流程按预期工作,没有任何问题。

我为使用自定义 SSO 功能而生成的自定义链接如下所示(剃刀):

            <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

当我单击标签并触发自定义流程时,一切都在 SSO 端按预期工作,但是当消息返回时,我收到以下错误:

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.

这是从 OpenIdHandler抛出的,它调用Unprotect我认为与StateDataFormat之前注入的保护器相同的保护器:

Options.StateDataFormat.Unprotect(message.State);

从详细日志记录中,我在调用时看到以下内容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').

但是当请求回来时,我得到了 unprotect 日志:

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')。根据文档,这意味着它们的加密和解密方式不同

我希望数据保护器是相同的,因为它们都引用了相同OpenIdConnectOptions的配置。

为什么两者DataProtector提供不同的目的?它们是不同的对象吗?我的配置中是否缺少某些内容?如何从内部框架和我注入的内容中获得相同的提供者?

标签: c#asp.net-coreopenid

解决方案


我有同样的问题并找到了答案,我们需要通过方案名称来获取正确的实例:

return _openIdOptions.Get("oidc").CurrentValue.StateDataFormat.Protect(authProperties);
            

推荐阅读