web-dev-qa-db-fra.com

Comment ajouter des rôles aux revendications dans IdentityServer4?

Je suis nouveau sur IdentityServer et j'ai eu du mal avec ce problème toute la journée. À tel point que je suis sur le point d'abandonner. Je sais que cette question a été posée à maintes reprises et j'ai essayé de nombreuses solutions différentes, mais aucune ne semble fonctionner. J'espère que vous pourrez m'aider Poussez-moi dans la bonne direction avec ça.

J'ai d'abord installé les modèles IdentityServer4 en exécutant dotnet new -i identityserver4.templates Et créé un nouveau projet avec le modèle is4aspid en exécutant dotnet new is4aspid -o IdentityServer.

Après cela, j'ai créé une nouvelle base de données IdentityServer et exécuté les migrations. À ce moment-là, j'avais une structure de base de données d'identité par défaut.

Dans Config.cs, j'ai changé MVC client Comme suit:

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 }                
},

Et changé la méthode GetApis en ceci:

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

Là, bien sûr, il n'y avait pas encore d'utilisateurs dans la base de données, j'ai donc ajouté un formulaire d'inscription et enregistré deux utilisateurs fictifs, l'un avec le nom d'utilisateur [email protected] Et l'autre avec le nom d'utilisateur [email protected].

Pour attribuer les rôles à ces utilisateurs, j'ai créé la méthode suivante dans 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("[email protected]");
    await UserManager.AddToRoleAsync(userToMakeAdmin, "Admin");

    ApplicationUser userToMakeSubscriber = await UserManager.FindByNameAsync("[email protected]");
    await UserManager.AddToRoleAsync(userToMakeSubscriber, "Subscriber");
}

Dans la méthode Configure de la même classe, j'ajoute le paramètre IServiceProvider services Et j'ai appelé la méthode ci-dessus comme ceci: CreateUserRoles(services).Wait();. À ce moment-là, ma base de données avait deux rôles.

Ensuite, j'ai créé une nouvelle solution (dans le même projet) et dans le fichier Startup.cs de cette solution, j'ai ajouté ce qui suit dans la méthode 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");
        });

Après cela, j'ai ajouté app.UseAuthentication(); dans la méthode Configure de la même classe.

J'ai ensuite créé une nouvelle page avec les instructions if suivantes.

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

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

Je me suis connecté avec [email protected] Mais la deuxième instruction if renvoie False. J'ai inspecté toutes les revendications en les bouclant comme ça.

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

Mais il n'y avait aucune revendication de rôle à trouver, seulement sid, sub, idp, Preferred_username et name.

J'ai essayé d'obtenir le rôle là-bas pour que la deuxième instruction if renvoie True, mais après avoir essayé et essayé, je n'ai pas encore pu le faire fonctionner. Quelqu'un peut-il voir ce que je dois faire pour que cela fonctionne? Je suis un débutant absolu dans IdentityServer4 et je fais de mon mieux pour le comprendre. Toute aide serait appréciée. Merci d'avance!

EDIT 1:

Grâce à cette question et cette question j'ai eu le sentiment d'être sur la bonne voie. J'ai apporté quelques modifications mais je n'arrive toujours pas à le faire fonctionner. J'ai juste essayé ce qui suit.

  1. J'ai créé une nouvelle classe ProfileService dans mon projet IdentityServer avec le contenu suivant.
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;
 }
}

Ensuite, j'ai enregistré cette classe dans la méthode ConfigureServices en ajoutant la ligne services.AddTransient<IProfileService, MyProfileService>();. Après cela, j'ai ajouté une nouvelle ligne à la méthode GetIdentityResources, qui ressemble à ceci maintenant.

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

J'ai également ajouté les rôles à mon client Mvc comme ceci: AllowedScopes = { "openid", "profile", "api1", "roles" }.

Ensuite, je suis passé à l'autre projet et j'ai ajouté les lignes suivantes dans l'oidc .AddOpenIdConnect.

options.ClaimActions.MapJsonKey("role", "role", "role");
options.TokenValidationParameters.RoleClaimType = "role";

Mais encore, je ne peux pas le faire fonctionner comme je le veux. Quelqu'un sait ce qui me manque?

7
Mitch

Deux choses que vous devez faire pour vous assurer que vous obtiendrez des rôles d'utilisateurs dans les revendications:

1- Dans le projet IdentityServer4: vous devez avoir une implémentation pour IProfileService http://docs.identityserver.io/en/latest/reference/profileservice.html

n'oubliez pas d'ajouter la classe dans le fichier startup.cs comme ceci

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

2- Dans le fichier startup.cs du projet Web Client: lors de la configuration de l'openId, vous devez le mentionner:

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"
            };**
        });
1
Feras Taleb