【问题标题】:Transforming Open Id Connect claims in ASP.Net Core在 ASP.Net Core 中转换 Open Id Connect 声明
【发布时间】:2016-12-26 11:39:13
【问题描述】:

我正在编写一个 ASP.Net Core Web 应用程序并使用UseOpenIdConnectAuthentication 将其连接到 IdentityServer3。模拟他们的 ASP.Net MVC 5 示例我正在尝试转换从 Identity Server 收到的声明以删除“low level protocol claims that are certainly not needed”。在 MVC 5 中,他们为 SecurityTokenValidated Notification 添加了一个处理程序,该处理程序将 AuthenticationTicket 替换为仅具有所需声明的通知。

在 ASP.Net Core 中,要进行等效操作,我认为我需要处理 OpenIdConnectEvents 中的 OnTokenValidated。但是,在那个阶段似乎没有检索到附加范围信息。如果我处理OnUserInformationReceived,则存在额外信息,但存储在用户而不是主体上。

在身份验证完成后,似乎没有任何其他事件可以永久删除我不想保留的声明。任何建议都非常感谢!

【问题讨论】:

    标签: c# asp.net-core claims-based-identity identityserver3


    【解决方案1】:

    我喜欢 LeastPrivilege 的建议,即在此过程的早期进行转换。提供的代码不太好用。这个版本可以:

    var oidcOptions = new OpenIdConnectOptions
    {
       ...
    
       Events = new OpenIdConnectEvents
       {
           OnTicketReceived = e =>
           {
              e.Principal = TransformClaims(e.Ticket.Principal);
              return Task.CompletedTask;
           }
       }
    };
    

    这将替换 Principal 而不是 Ticket。您可以使用我其他答案中的代码来创建新的Principal。你也可以同时替换Ticket,但我不确定是否有必要。

    非常感谢 LeastPrivilege 和 Adem 提出的几乎可以回答我的问题的方法……只是代码需要稍作调整。总的来说,我更喜欢 LeastPrivilege 提早转换声明的建议。

    【讨论】:

      【解决方案2】:

      您可以实现SignInSchemeOnSigningIn 事件。这是一个例子:

              app.UseCookieAuthentication(new CookieAuthenticationOptions()
              {
                  AuthenticationScheme = "OpenIdCookies",
                  AutomaticAuthenticate = true,
                  Events = new CookieAuthenticationEvents()
                  {
                      OnSigningIn = async (context) =>
                      {
                          ClaimsIdentity identity = (ClaimsIdentity)context.Principal.Identity;
                          identity.Claims = identity.Claims.Where(...);
                      }
                  }
              });
      
              var oidcOptions = new OpenIdConnectOptions
              {
                  AuthenticationScheme = "oidc",
                  SignInScheme = "OpenIdCookies"
              };
      
              //.. set other options
      
              app.UseOpenIdConnectAuthentication(oidcOptions); 
      

      【讨论】:

      • 感谢您让我走上正轨。唯一的问题是 identity.Claim 是只读属性。我添加了一个有效的答案,我只是不确定它是否是“正确”的方法。
      【解决方案3】:

      感谢 Adem 的回复...它解决了绝大多数问题...唯一的问题是身份。声明是只读属性。我发现创建一个新的校长确实有效:

      Events = new CookieAuthenticationEvents()
      {
          OnSigningIn = (context) =>
          {
              ClaimsIdentity identity = (ClaimsIdentity)context.Principal.Identity;
      
              var givenName = identity.FindFirst(Constants.ClaimTypes.GivenName);
              var familyName = identity.FindFirst(Constants.ClaimTypes.FamilyName);
              var sub = identity.FindFirst(Constants.ClaimTypes.Subject);
      
              var claimsToKeep = new List<Claim> {givenName, familyName, sub};
      
              var newIdentity = new ClaimsIdentity(claimsToKeep, identity.AuthenticationType);
      
              context.Principal = new ClaimsPrincipal(newIdentity);
      
              return Task.FromResult(0);
          }
      }
      

      我不确定这是否是正确的方法,但它似乎有效。

      【讨论】:

      • 你有没有得出任何结论,如果替换 Principal 而不是 Ticket 可以这样做?
      【解决方案4】:

      我个人更喜欢在发生实际身份验证的中间件中进行声明转换。

      您可以为此使用 OIDC 中间件上的 OnTicketReceived 事件。

      var oidcOptions = new OpenIdConnectOptions
      {
         AuthenticationScheme = "oidc",
         SignInScheme = "cookies",
      
         Authority = Clients.Constants.BaseAddress,
      
         ClientId = "mvc.hybrid",
         ClientSecret = "secret",
         ResponseType = "code id_token",
         SaveTokens = true,
      
         TokenValidationParameters = new TokenValidationParameters
         {
            NameClaimType = JwtClaimTypes.Name,
            RoleClaimType = JwtClaimTypes.Role,
         },
      
         Events = new OpenIdConnectEvents
         {
             OnTicketReceived = e =>
             {
                 ClaimsPrincipal p = TransformClaims(e.Ticket.Principal);
                 e.Ticket = new AuthenticationTicket(
                  p,
                  e.Ticket.Properties,
                  e.Ticket.AuthenticationScheme);
      
              return Task.CompletedTask;
          }
        }
      };
      

      【讨论】:

      • 这看起来应该可以,但是当我尝试它时,原始声明仍然存在。如果不是用新的 AuthenticationTicket 替换 e.Ticket,而是用新的 Principal 替换 e.Principal,它确实有效。
      • @PiersLawson 如果替换 e.Principal 而不是 e.Ticket 是否可以,您是否得出任何结论?
      • 这个答案对我使用 AspNetCore 1.1.2 对 Identity Server 3 进行身份验证很有效。
      【解决方案5】:

      感谢这个帖子中的答案,我也能够为自己工作。 没有在这里解决的是,如果需要修改需要服务的声明。就我而言,我需要构建服务提供者以获得正确的依赖关系,从而转换声明。 (我也能够在不进行转换的情况下删除声明 - 在这里也显示该代码)。

      public void ConfigureServices(IServiceCollection services)
      {
          services
              .AddAuthentication(options =>
              {
                  // set options
              })
              .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
              {
                  // set options
              })
              .AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
              {
                  // options such as Authority, ClientId, etc set here
                  options.Authority = "your-value";
                  options.ClientId = "your-value";
                  // ...
      
                  // remove automatically mapped claims we do not need, keeps the authentication cookie smaller
                  options.ClaimActions.DeleteClaim("sid");
                  options.ClaimActions.DeleteClaim("idp");
                  options.ClaimActions.DeleteClaim("s_hash");
                  options.ClaimActions.DeleteClaim("auth_time");
      
                  options.Events.OnTicketReceived = async context =>
                  {
                      // Build the service provider and necessary dependencies
                      // in order to enhance our claims once we receive it initially
                      ServiceProvider serviceProvider = services.BuildServiceProvider();
                      ICustomProvider customProvider = serviceProvider.GetService<ICustomProvider>();
                      EnhanceClaimsTransformation claimsTransformation = new EnhanceClaimsTransformation(customProvider);
      
                      context.Principal = await claimsTransformation.TransformAsync(context.Principal);
                      await Task.CompletedTask;
                  };
              });
      }
      

      增强声明转换 (ICustomProvider在ConfigureServices的依赖注入中注册)

      请注意,在此代码中,我们需要对主体进行克隆以实际向其添加声明。

      public class EnhanceClaimsTransformation : IClaimsTransformation
      {
          private readonly ICustomProvider _customProvider;
      
          public EnhanceClaimsTransformation(ICustomProvider customProvider)
          {
              _customProvider = customProvider;
          }
      
          /// <summary>
          /// Upon authentication, we transform the claims in order to enhance
          /// the claims with user-enhanced values.
          /// </summary>
          /// <param name="principal"></param>
          /// <returns></returns>
          public async Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
          {
              // https://gunnarpeipman.com/aspnet-core-adding-claims-to-existing-identity/
              ClaimsPrincipal clone = principal.Clone();
              ClaimsIdentity claimsIdentity = (ClaimsIdentity)clone.Identity;
      
              Response response = await _customProvider.Find(principal.Identity.Name, CancellationToken.None);
      
              // Setting claims values
              claimsIdentity.AddClaims(new List<Claim>
              {
                  new Claim("Datapoint1", response.Datapoint1),
                  new Claim("Datapoint2", response.Datapoint2),
                  // ...
              });        
      
              return clone;
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2016-09-11
        • 2018-01-24
        • 2020-02-17
        • 2018-06-14
        • 1970-01-01
        • 2018-05-08
        • 2020-05-28
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多