Как добавить роли к заявкам в IdentityServer4? - PullRequest
3 голосов
/ 30 мая 2019

Я новичок в IdentityServer и весь день боролся с этой проблемой.Настолько, что я почти сдаюсь.Я знаю, что этот вопрос задавался снова и снова, и я пробовал много разных решений, но ни одно из них не работает.Надеюсь, вы поможете мне в этом.1006 * После этого я создал новую базу данных IdentityServer и запустил миграцию.К тому времени у меня была структура базы данных Identity по умолчанию.

В Config.cs я изменил MVC client на следующее:

new Client
{
    ClientId = "mvc",
    ClientName = "MVC Client",

    AllowedGrantTypes = GrantTypes.Implicit,
    ClientSecrets = { new Secret("47C2A9E1-6A76-3A19-F3C0-S37763QB36D9".Sha256()) },

    RedirectUris = { "https://localhost:44307/signin-oidc" },
    FrontChannelLogoutUri = "https://localhost:44307/signout-oidc",
    PostLogoutRedirectUris = { "https://localhost:44307/signout-callback-oidc" },

    AllowOfflineAccess = true,
    AllowedScopes = { "openid", "profile", "api1", JwtClaimTypes.Role }                
},

И изменил метод GetApis на этот:

public static IEnumerable<ApiResource> GetApis()
{
    return new ApiResource[]
    {
        new ApiResource("api1", "My API #1", new List<string>() { "role" })
    };
}

Там, где, конечно, еще нет пользователей в базе данных, поэтому я добавил регистрационную форму и зарегистрировал двух фиктивных пользователей, одного с именем пользователя admin@example.com и одного с именем пользователя subscriber@example.com.

Чтобы назначить роли этим пользователям, я создал следующий метод в Startup.cs.

private async Task CreateUserRoles(IServiceProvider serviceProvider) {
    var RoleManager = serviceProvider.GetRequiredService<RoleManager<IdentityRole>>();
    var UserManager = serviceProvider.GetRequiredService<UserManager<ApplicationUser>>();

    IdentityResult adminRoleResult;
    IdentityResult subscriberRoleResult;

    bool adminRoleExists = await RoleManager.RoleExistsAsync("Admin");
    bool subscriberRoleExists = await RoleManager.RoleExistsAsync("Subscriber");

    if (!adminRoleExists) {
        adminRoleResult = await RoleManager.CreateAsync(new IdentityRole("Admin"));
    }

    if(!subscriberRoleExists) {
        subscriberRoleResult = await RoleManager.CreateAsync(new IdentityRole("Subscriber"));
    }

    ApplicationUser userToMakeAdmin = await UserManager.FindByNameAsync("admin@example.com");
    await UserManager.AddToRoleAsync(userToMakeAdmin, "Admin");

    ApplicationUser userToMakeSubscriber = await UserManager.FindByNameAsync("subscriber@example.com");
    await UserManager.AddToRoleAsync(userToMakeSubscriber, "Subscriber");
}

В методе Configure того же класса я добавил параметр IServiceProvider services и вызвалВышеуказанный метод примерно так: CreateUserRoles(services).Wait();.К этому времени моя база данных имела две роли:

Затем я создал новое решение (в том же проекте) и в файле Startup.cs этого решения добавил следующее в методе ConfigureServices.

    JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

    services.AddAuthentication(options =>
    {
        options.DefaultScheme = "Cookies";
        options.DefaultChallengeScheme = "oidc";
    })
        .AddCookie("Cookies")
        .AddOpenIdConnect("oidc", options => {
            options.SaveTokens = true;
            options.ClientId = "mvc";
            options.ClientSecret = "32D7A7W0-0ALN-2Q44-A1H4-A37990NN83BP";
            options.RequireHttpsMetadata = false;
            options.Authority = "http://localhost:5000/";
            options.ClaimActions.MapJsonKey("role", "role");
        });

После этого я добавил app.UseAuthentication(); в метод Configure того же класса.

Затем я создал новую страницу со следующими операторами if.

if(User.Identity.IsAuthenticated) {
 <div>Yes, user is authenticated</div>
} 

if(User.IsInRole("ADMIN")) {
 <div>Yes, user is admin</div>
}

Я вошел в систему с admin@example.com, но второй оператор if возвращает False.Я проверил все заявки, выполнив их циклическую обработку следующим образом.

@foreach (var claim in User.Claims) {
    <dt>@claim.Type</dt>
    <dd>@claim.Value</dd>
}

Но не было найдено ни одной заявки на роль, только sid, sub, idp, предпочитаемое_имя_пользователя и имя.

Я пытался получить роль там, чтобы второе выражение if возвращало True, но после попытки и попытки я еще не смог заставить его работать.Может кто-нибудь увидеть, что я должен сделать, чтобы сделать эту работу?Я абсолютный новичок в IdentityServer4 и изо всех сил стараюсь понять это.Любая помощь будет оценена.Заранее спасибо!

РЕДАКТИРОВАТЬ 1:

Благодаря этот вопрос и этот вопрос У меня возникло ощущение, что яЯ на правильном пути.Я сделал некоторые изменения, но я до сих пор не могу заставить его работать.Я только что попробовал следующее.

  1. Создал новый класс ProfileService в моем проекте IdentityServer со следующим содержимым.
public class MyProfileService : IProfileService {
 public MyProfileService() { }
 public Task GetProfileDataAsync(ProfileDataRequestContext context) {
  var roleClaims = context.Subject.FindAll(JwtClaimTypes.Role);
  List<string> list = context.RequestedClaimTypes.ToList();
  context.IssuedClaims.AddRange(roleClaims);
  return Task.CompletedTask;
 }

 public Task IsActiveAsync(IsActiveContext context) {
  return Task.CompletedTask;
 }
}

Далее я зарегистрировал этот класс в методе ConfigureServicesдобавив строку services.AddTransient<IProfileService, MyProfileService>();.После этого я добавил новую новую строку в метод GetIdentityResources, который выглядит следующим образом.

public static IEnumerable<IdentityResource> GetIdentityResources()
{
    return new IdentityResource[]
    {
        new IdentityResources.OpenId(),
        new IdentityResources.Profile(),
        new IdentityResource("roles", new[] { "role" })
};
}

Я также добавил роли в свой клиент Mvc следующим образом: AllowedScopes = { "openid", "profile", "api1", "roles" }.

* 1070Затем я переключился на другой проект и добавил следующие строки в oidc .AddOpenIdConnect.
options.ClaimActions.MapJsonKey("role", "role", "role");
options.TokenValidationParameters.RoleClaimType = "role";

Но все же я не могу заставить его работать так, как я хочу.Кто-нибудь знает, что мне не хватает?

Ответы [ 2 ]

2 голосов
/ 31 мая 2019

Немного другой вопрос, абсолютно совпадающий ответ.

С Edit 1 , конфигурация IdP выглядит достаточно, чтобы предоставить как identity , так и доступ токенов с ролями по запросу .Осталось только настроить клиент на запрос маркера доступа (по умолчанию клиент .Net этого не делает) или просто запросить область действия roles в токене идентификации.

Чтобы получить ролипри id_token конфигурация на стороне клиента должна включать options.Scope.Add("roles");

Чтобы получить роли с токеном-носителем, этот токен необходимо запросить, указав options.ResponseType = "id_token token"; в конфигурации на стороне клиента.

1 голос
/ 01 июня 2019

Две вещи, которые необходимо сделать, чтобы убедиться, что вы получите роли пользователей в утверждениях:

1- В проекте IdentityServer4: вам нужно иметь реализацию для IProfileService http://docs.identityserver.io/en/latest/reference/profileservice.html

не забудьте добавить класс в файл startup.cs следующим образом

services.AddIdentityServer()
// I just removed some other configurations for clarity
                **.AddProfileService<IdentityProfileService>();**

2- В файле startup.cs проекта веб-клиента: при настройке openId вы должны указать следующее:

services.AddAuthentication(options =>
        {
            options.DefaultScheme = "Cookies";
            options.DefaultChallengeScheme = "oidc";
        })
        .AddCookie("Cookies")
        .AddOpenIdConnect("oidc", options =>
        {
            options.SignInScheme = "Cookies";
            options.Authority = "Identity URL ";
            options.RequireHttpsMetadata = true;

            options.ClientId = "saas_crm_webclient";
            options.ClientSecret = "49C1A7E1-0C79-4A89-A3D6-A37998FB86B0";
            options.ResponseType = "code id_token";
            options.SaveTokens = true;
            options.GetClaimsFromUserInfoEndpoint = false;

            options.Scope.Add("test.api");
            options.Scope.Add("identity.api");
            options.Scope.Add("offline_access");


            **options.ClaimActions.Add(new JsonKeyClaimAction("role", null, "role"));**

            **options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
            {
                NameClaimType = "name",
                RoleClaimType = "role"
            };**
        });
...