https://leastprivilege.com/2017/11/15/missing-claims-in-the-asp-net-core-2-openid-connect-handler/

ользуюСервер аутентификации OpenId ConnectконкретноIdentity Server 4 (версия 1.5.2) в .NET Core 1.1. У меня это работает с веб-приложениями ASP.NET Framework MVC 5 и ASP.NET Core 1.1 MVC. Следующая конфигурация из веб-приложения .NET Core 1.1:

public void Configure(
    IApplicationBuilder app,
    IHostingEnvironment env,
    ILoggerFactory loggerFactory)
{
    app.UseDeveloperExceptionPage();
    app.UseStatusCodePages();
    app.UseRewriter(new RewriteOptions().AddRedirectToHttps());
    app.UseStaticFiles();

    #region Configure Authentication
    JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

    app.UseCookieAuthentication(
        new CookieAuthenticationOptions
        {
            AuthenticationScheme = "Cookies",
            AutomaticAuthenticate = true,
            AccessDeniedPath = "/AccessDenied"
        });
    app.UseOpenIdConnectAuthentication(
        new OpenIdConnectOptions
        {
            AuthenticationScheme = "oidc",
            SignInScheme = "Cookies",

            Authority = "https://localhost:44316",
            ClientId = "test-mule",
            ClientSecret = "secret",
            ResponseType = "code id_token",

            SaveTokens = true,
            GetClaimsFromUserInfoEndpoint = true,

            PostLogoutRedirectUri = "https://localhost:44324",
            RequireHttpsMetadata = true,

            Scope = { "openid", "profile", "name", "email", "org", "role" },

            TokenValidationParameters = new TokenValidationParameters
            {
                NameClaimType = "name",
                RoleClaimType = "role"
            }
        });
    #endregion Configure Authentication

    app.UseMvc();
}

После входа в систему я могу перечислить претензии, связанные с аутентифицированным пользователем:

var claims = User.Claims.OrderBy(c => c.Type).ToList();

В приложении ASP.NET 1.1 это обеспечивает следующий список требований:

amr         pwd
aud         test-mule
auth_time   1504529067
c_hash      nouhsuXtd5iKT7B33zxkxg
email       [email protected]
exp         1504532668
family_name Cobley
given_name  Tom
iat         1504529068
idp         local
iss         https://localhost:44316
name        tom
nbf         1504529068
nonce       6364012...
org         IBX
role        SysAdmin
role        TeleMarketing
role        AccountManager
role        DataManager
role        Member
sid         2091...
sub         1b19...440fa

Что, это то, что я хочу / ожидаю.

Я сейчас пытаюсь повторить это поведение в моем первомASP.NET Core 2.0 приложение со следующимStartup конфигурация:

public Startup()
{
    JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
}

public void ConfigureServices(IServiceCollection services)
{
    services.AddAuthentication("Cookies")
        .AddCookie("Cookies", options =>
            {
                options.LoginPath = "/SignIn";
                options.AccessDeniedPath = "/AccessDenied";
            })
        .AddOpenIdConnect("oidc", options =>
            {
                options.SignInScheme = "Cookies";
                options.Authority = "https://localhost:44316";
                options.ClientId = "test-mule";
                options.ClientSecret = "secret";
                options.ResponseType = "code id_token";

                options.SaveTokens = true;
                options.GetClaimsFromUserInfoEndpoint = true;

                options.SignedOutRedirectUri = "https://localhost:44367";
                options.RequireHttpsMetadata = true;

                options.Scope.Clear();
                options.Scope.Add("openid");
                options.Scope.Add("profile");
                options.Scope.Add("name");
                options.Scope.Add("email");
                options.Scope.Add("org");
                options.Scope.Add("role");

                options.TokenValidationParameters = new TokenValidationParameters
                {
                    NameClaimType = "name",
                    RoleClaimType = "role"
                };
            });

    // Add framework services.
    services.AddMvc();
}

Для справки/Signin Действие контроллера выглядит так:

[Route("/SignIn")]
public IActionResult SignIn(string returnUrl = null)
{
    if (!Url.IsLocalUrl(returnUrl)) returnUrl = "/";

    var props = new AuthenticationProperties
    {
        RedirectUri = returnUrl
    };

    return Challenge(props, "oidc");
}

В этой среде после успешного входа в систему, если я перечисляю претензии пользователя, я вижу только подмножество того, что доступно в Core 1.1:

email       [email protected]
family_name Cobley
given_name  Tom
idp         local
name        tom.cobley
sid         2091...
sub         1b19...440fa

Я запустил журналы трассировки как на клиенте, так и на сервере, но ничего не вижу / не распознаю. Я также предполагаю, что это не проблема Identity Server, как это'только что' сервис Open Id Connect, который должен быть совместим с любым клиентом?

Кто-нибудь может указать мне правильное направление относительно того, где я иду не так?

Благодарю.

Обновить

Следуя предложению MVCutter, я добавил обработчик события OnUserInformationReceived, так как заметил, что не все мои пользовательские утверждения правильно сопоставляются с идентификационной информацией пользователя. Я не уверен, почему это необходимо или есть лучшее место, чтобы сделать это, но это, кажется, дает мне то, что я хочу сейчас.

private Task OnUserInformationReceivedHandler(
    UserInformationReceivedContext context)
{
    if (!(context.Principal.Identity is ClaimsIdentity claimsId))
    {
        throw new Exception();
    }

    // Get a list of all claims attached to the UserInformationRecieved context
    var ctxClaims = context.User.Children().ToList();

    foreach (var ctxClaim in ctxClaims)
    {
        var claimType = ctxClaim.Path;
        var token = ctxClaim.FirstOrDefault();
        if (token == null)
        {
            continue;
        }

        var claims = new List<Claim>();
        if (token.Children().Any())
        {
            claims.AddRange(
                token.Children()
                    .Select(c => new Claim(claimType, c.Value<string>())));
        }
        else
        {
            claims.Add(new Claim(claimType, token.Value<string>()));
        }

        foreach (var claim in claims)
        {
            if (!claimsId.Claims.Any(
                c => c.Type == claim.Type &&
                     c.Value == claim.Value))
            {
                claimsId.AddClaim(claim);
            }
        }
    }

    return Task.CompletedTask;
}

Ответы на вопрос(2)

tions. Набор ClaimActions по умолчанию удалит иск, который вы ищете. Вы можете получить претензии обратно, очистив ClaimActions для вашего объекта параметров:

options.ClaimActions.Clear();

Смотрите также:https://leastprivilege.com/2017/11/15/missing-claims-in-the-asp-net-core-2-openid-connect-handler/

Решение Вопроса

смотрите ниже, я столкнулся с той же проблемой, что и вы. Я уверен, что есть проблема конфигурации, которую мы пропускаем, но на данный момент я проанализировал значения, возвращаемые из UserInfoEndpoint в обработчике события OnUserInformationReceived.

    public override void ConfigureServices(IServiceCollection services)
    {
        services.AddAuthentication(sharedOptions =>
        {
            sharedOptions.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            sharedOptions.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
        })
            .AddCookie()
            .AddOpenIdConnect(o =>
            {
                o.ClientId = "sss";
                o.ClientSecret = "sss";
                o.RequireHttpsMetadata = false;
                o.Authority = "http://localhost:60000/";
                o.MetadataAddress = "http://localhost:60000/IdSrv/.well-known/openid-configuration";
                o.ResponseType = OpenIdConnectResponseType.IdTokenToken;
                o.CallbackPath = new PathString("/CGI/Home/Index");
                o.SignedOutCallbackPath = new PathString("/CGI/Account/LoggedOut");
                o.Scope.Add("openid");
                o.Scope.Add("roles");
                o.SaveTokens = true;
                o.GetClaimsFromUserInfoEndpoint = true;
                o.Events = new OpenIdConnectEvents()
                {
                    OnUserInformationReceived = (context) =>
                    {
                        ClaimsIdentity claimsId = context.Principal.Identity as ClaimsIdentity;

                        var roles = context.User.Children().FirstOrDefault(j => j.Path == JwtClaimTypes.Role).Values().ToList();
                        claimsId.AddClaims(roles.Select(r => new Claim(JwtClaimTypes.Role, r.Value<String>())));

                        return Task.FromResult(0);
                    }
                };
                o.TokenValidationParameters = new TokenValidationParameters
                {
                    NameClaimType = JwtClaimTypes.Name,
                    RoleClaimType = JwtClaimTypes.Role,
                };
            });
    }

Редактировать:

Я обнаружил, что есть метод расширения для свойства ClaimsAction под названием MapUniqueJsonKey, который, кажется, работает для пользовательских однозначных ключей, но бомб на типах массива, таких как роли ... становится ближе

o.ClaimActions.MapUniqueJsonKey("UserType", "UserType");
 user194956120 окт. 2017 г., 22:36
Добавьте еще один в список людей, имеющих точно такую ​​же проблему, но чувствует, что так не должно быть. Сейчас я собираюсь следовать вышеприведенному набору, однако, должна быть настройка или что-то, чего нам не хватает
 Neilski06 сент. 2017 г., 12:30
Спасибо MVCutter, это работает и для меня. В моем случае, однако, я все еще заметил, что некоторые из утверждений не были назначены для ClaimsIdentity, поэтому я расширил вашу идею, чтобы рассмотреть все токены, назначенные пользователю - я уверен, что это можно сделать более аккуратно, но это работает в процессе на данный момент (Re: Хромой извините!). В очередной раз благодарим за помощь.

Ваш ответ на вопрос