【问题标题】:Migration from Core 1.1 to 2.0 - Authentication从 Core 1.1 迁移到 2.0 - 身份验证
【发布时间】:2018-02-15 13:49:14
【问题描述】:

在我的 .net core 1.1 代码中,我按如下方式进行身份验证(将不记名令牌发送到外部 URL 并在返回令牌中查找声明)。此代码在Configure 方法中

app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationScheme = "Cookies"
        });

        app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions
        {
            AuthenticationScheme = "oidc",
            SignInScheme = "Cookies",

            Authority = signinAuthority,
            RequireHttpsMetadata = signinHTTPS,

            ClientId = "skybus",
            ClientSecret = "secret",

            ResponseType = "code id_token",
            Scope = { "api1", "offline_access" },

            GetClaimsFromUserInfoEndpoint = true,
            SaveTokens = true
        });

现在我将代码升级到 .net Core 2.0,UseCookieAuthenticationUseOpenIdConnectAuthentication 都已更改。我发现在这种情况下很难找到需要做的事情

我在ConfigureServices方法中改成如下

services.AddAuthentication(options => {
            options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
        })
            .AddCookie()
            .AddOpenIdConnect(o =>
            {
                o.Authority = signinAuthority;
                o.SignInScheme = "Cookies";
                o.RequireHttpsMetadata = signinHTTPS;
                o.ClientId = "skybus";
                o.ClientSecret = "secret";
                o.ResponseType = "code id_token";
                o.GetClaimsFromUserInfoEndpoint = true;
                o.SaveTokens = true;
                o.Scope.Add("api1");
                o.Scope.Add("offline_access");
            });

在浏览器中,我在上述更改后看到了这个 URL。如果用户未登录,它应该向我显示外部登录页面或返回我网站的主页

http://localhost:5000/Account/Login?ReturnUrl=%2F

【问题讨论】:

    标签: c# .net authentication asp.net-core-1.1 .net-core-2.0


    【解决方案1】:

    我关注this link from microsoft 开始我的迁移。此链接涵盖了大部分迁移,但我遇到了我的大部分声明都丢失的问题。

    使用 ASP.NET Core 1.x,客户端会收到以下声明:nbf、exp、iss、aud、nonce、iat、c_hash、sid、sub、auth_time、idp、amr。

    在 Core 2.0 中,我们只得到 sid、sub 和 idp。发生了什么?

    Microsoft 在其 OpenID Connect 处理程序中添加了一个名为 ClaimActions 的新概念。声明操作允许修改来自外部提供者的声明如何映射(或不映射)到您的 ClaimsPrincipal 中的声明。查看 OpenIdConnectOptions 的 ctor,您可以看到处理程序现在将默认跳过以下声明:

    ClaimActions.DeleteClaim("nonce");
    ClaimActions.DeleteClaim("aud");
    ClaimActions.DeleteClaim("azp");
    ClaimActions.DeleteClaim("acr");
    ClaimActions.DeleteClaim("amr");
    ClaimActions.DeleteClaim("iss");
    ClaimActions.DeleteClaim("iat");
    ClaimActions.DeleteClaim("nbf");
    ClaimActions.DeleteClaim("exp");
    ClaimActions.DeleteClaim("at_hash");
    ClaimActions.DeleteClaim("c_hash");
    ClaimActions.DeleteClaim("auth_time");
    ClaimActions.DeleteClaim("ipaddr");
    ClaimActions.DeleteClaim("platf");
    ClaimActions.DeleteClaim("ver");
    

    如果您想“取消跳过”索赔,则需要在设置处理程序时删除特定的索赔操作。以下是获取 amr 声明的非常直观的语法:

    options.ClaimActions.Remove("amr");
    

    向 OIDC 提供商请求更多声明

    当您请求更多范围时,例如导致更多声明的配置文件或自定义范围,还有另一个令人困惑的细节需要注意。

    根据 OIDC 协议中的 response_type,一些声明通过 id_token 传输,一些通过 userinfo 端点传输。

    所以首先,您需要在处理程序中启用对 userinfo 端点的支持:

    options.GetClaimsFromUserInfoEndpoint = true;
    

    最后你需要添加以下类来导入所有其他自定义声明

    public class MapAllClaimsAction : ClaimAction
        {
            public MapAllClaimsAction() : base(string.Empty, string.Empty)
            {
            }
    
            public override void Run(JObject userData, ClaimsIdentity identity, string issuer)
            {
                foreach (var claim in identity.Claims)
                {
                    // If this claimType is mapped by the JwtSeurityTokenHandler, then this property will be set
                    var shortClaimTypeName = claim.Properties.ContainsKey(JwtSecurityTokenHandler.ShortClaimTypeProperty) ?
                        claim.Properties[JwtSecurityTokenHandler.ShortClaimTypeProperty] : string.Empty;
    
                    // checking if claim in the identity (generated from id_token) has the same type as a claim retrieved from userinfo endpoint
                    JToken value;
                    var isClaimIncluded = userData.TryGetValue(claim.Type, out value) || userData.TryGetValue(shortClaimTypeName, out value);
    
                    // if a same claim exists (matching both type and value) both in id_token identity and userinfo response, remove the json entry from the userinfo response
                    if (isClaimIncluded && claim.Value.Equals(value.ToString(), StringComparison.Ordinal))
                    {
                        if (!userData.Remove(claim.Type))
                        {
                            userData.Remove(shortClaimTypeName);
                        }
                    }
                }
    
                // adding remaining unique claims from userinfo endpoint to the identity
                foreach (var pair in userData)
                {
                    JToken value;
                    var claimValue = userData.TryGetValue(pair.Key, out value) ? value.ToString() : null;
                    identity.AddClaim(new Claim(pair.Key, claimValue, ClaimValueTypes.String, issuer));
                }
            }
        }
    

    然后使用上面的类代码添加到ClaimActions

    options.ClaimActions.Add(new MapAllClaimsAction());
    

    【讨论】:

      【解决方案2】:

      您是否使用了身份验证中间件?

      public void Configure(IApplicationBuilder app, IHostingEnvironment env)
      {
          app.UseAuthentication();
      ...
      

      【讨论】:

        【解决方案3】:

        我不知道你是否在使用 IdentityServer4,但他们在 github 上为 ASP.NET Core 2.0 提供了一些示例。

        希望对你有所帮助。

        Sample Project

        【讨论】:

          猜你喜欢
          • 2018-04-05
          • 2018-01-28
          • 2018-06-12
          • 2018-01-27
          • 1970-01-01
          • 1970-01-01
          • 2021-08-26
          • 2020-01-24
          • 1970-01-01
          相关资源
          最近更新 更多