【问题标题】:How can i get value or check the role from Identity Server 4 to my MVC client?如何从 Identity Server 4 到我的 MVC 客户端获取价值或检查角色?
【发布时间】:2022-02-14 18:23:38
【问题描述】:

我有一个 MVC 客户端(ASP.NET 核心),它与 Identity Server 4(“安装”了 Identity ASP.NET)交互,用于登录、注册等的所有功能......,无需 API。

在客户端中,我需要检查登录用户的角色,但我不知道该怎么做。 我尝试了解决方案User.IsInRole("Administrator"),但它并没有读懂我的角色,以及[Authorize(Role="Administrator")]。 当我使用具有角色的用户登录时,这实际上显示在诊断页面的声明之间(在图像中)。

但奇怪的是,当我去分析时,在调试阶段,User.Claims Claims 的数组,“角色”不存在,或者我找不到它(作为 Identity 和 Identity 的初学者服务器)。

那么我该如何从 MVC 客户端获取角色呢? 我正在考虑使用该“角色”的值创建 Policy,如果无法使用 User.IsInRole("Administrator")[Authorize (Role = "Administrator")],但问题始终是我无法获得角色。

我将客户端和身份服务器的启动文件以及后者的 Config.cs 留给您,以便您更好地分析它们。可能有一些不必要的代码行,但一切都在开发中,请见谅。

Startup.cs 的客户端

public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            var builder = new ConfigurationBuilder().AddJsonFile("appsettings.json", true, true);
            Configuration = builder.Build();
            
        }

        public IConfiguration Configuration { get; }

        
        public void ConfigureServices(IServiceCollection services)
        {
            
            JwtSecurityTokenHandler.DefaultMapInboundClaims = false;

            services.AddAuthentication(options =>
            {
                options.DefaultScheme = "Cookies";
                options.DefaultChallengeScheme = "oidc";
            })
                .AddCookie("Cookies")
                .AddOpenIdConnect("oidc", options =>
                {
                    options.Authority = "https://localhost:5001";

                    
                    options.SignInScheme = "Cookies";
                    options.RequireHttpsMetadata = false;

                    options.ClientId = "mvc";
                    options.ClientSecret = "secret";
                    options.ResponseType = "code";

                    options.SaveTokens = true;
                   
                });

            services.AddAuthorization(options => {

                options.AddPolicy("Admin", policy => policy.RequireRole("Administrator"));

            });

            services.AddSession(options =>
            {
                options.IdleTimeout = TimeSpan.FromMinutes(55);
                
            });
            
            string connString = Configuration.GetConnectionString("DefaultConnection");

            services.AddDbContext<SushiWebDbContext>(options => options.UseSqlServer(connString));
            services.AddMvc();
            services.AddRazorPages();
            services.AddControllersWithViews();
            services.AddDistributedMemoryCache();
        }

        
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
                
                app.UseHsts();
            }
           
            
            app.UseSession();

            app.UseHttpsRedirection();
            app.UseStaticFiles();

            app.UseRouting();

            app.UseAuthentication();
            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                
                endpoints.MapDefaultControllerRoute();                    

            });

        }
    }

Startup.cs 的 Identity Server

public IWebHostEnvironment Environment { get; }
        public IConfiguration Configuration { get; }

        public Startup(IWebHostEnvironment environment, IConfiguration configuration)
        {
            Environment = environment;
            Configuration = configuration;
        }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllersWithViews();
            services.AddRazorPages();            

            services.AddDbContext<ApplicationDbContext>(options =>
                options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

            services.AddIdentity<ApplicationUser, IdentityRole>()                
                .AddRoles<IdentityRole>()
                .AddRoleManager<RoleManager<IdentityRole>>()
                .AddEntityFrameworkStores<ApplicationDbContext>()                
                .AddDefaultUI()
                .AddDefaultTokenProviders();

            var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;

            services.AddTransient<IProfileService, UserProfile>();

            var builder = services.AddIdentityServer()
                .AddAspNetIdentity<ApplicationUser>()
                .AddConfigurationStore(options =>
                    {
                        options.ConfigureDbContext = b => b.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"),
                            sql => sql.MigrationsAssembly(migrationsAssembly));
                    })
                    .AddOperationalStore(options =>
                    {
                        options.ConfigureDbContext = b => b.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"),
                            sql => sql.MigrationsAssembly(migrationsAssembly));
                    })
                    .AddProfileService<UserProfile>();


            
            builder.AddDeveloperSigningCredential();

            services.AddAuthentication()
                .AddGoogle(options =>
                {
                    options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;

                    
                    options.ClientId = "copy client ID from Google here";
                    options.ClientSecret = "copy client secret from Google here";
                });
        }

        public void Configure(IApplicationBuilder app, IServiceProvider serviceProvider)
        {


            if (Environment.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();

            }

            app.UseStaticFiles();

            app.UseRouting();
            app.UseIdentityServer();
            app.UseAuthorization();
            
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapDefaultControllerRoute();
                endpoints.MapRazorPages();
            });
            
        } 
}
身份服务器的

Config.cs

 public static class Config
    {
        public static IEnumerable<IdentityResource> IdentityResources =>
            new List<IdentityResource>
            {
                new IdentityResources.OpenId(),
                new IdentityResources.Profile()
                
            };


        public static IEnumerable<ApiScope> ApiScopes =>
            new List<ApiScope>
            {
               
            };

        public static IEnumerable<Client> Clients =>
            new List<Client>
            {
                
                new Client
                {
                    ClientId = "mvc",
                    ClientSecrets = { new Secret("secret".Sha256()) },

                    AllowedGrantTypes = GrantTypes.Code,
                    
                    // where to redirect to after login
                    RedirectUris = { "https://localhost:5002/signin-oidc" },

                    // where to redirect to after logout
                    PostLogoutRedirectUris = { "https://localhost:5002/signout-callback-oidc" },

                    AllowedScopes = new List<string>
                    {
                        IdentityServerConstants.StandardScopes.OpenId,
                        IdentityServerConstants.StandardScopes.Profile
                    }
                }
            };
    }

也许解决方案比预期的要容易,请原谅我。非常感谢!

【问题讨论】:

标签: c# asp.net asp.net-mvc asp.net-identity identityserver4


【解决方案1】:

要从 MVC 中的 IdentityServer 获取角色,您需要在 IdentityServer 项目中更改 Config.cs 并在 MVC 项目中更改 Startup.cs,如下所示:

在MVC Client的Startup.cs中添加

.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
{
    ...

    options.Scope.Add("roles");
    options.ClaimActions.MapJsonKey("role", "role");
    options.GetClaimsFromUserInfoEndpoint = true;
    options.TokenValidationParameters = new TokenValidationParameters
    {
        NameClaimType = "name",
        RoleClaimType = "role"
    };
}

如果我们使用MapUniqueJsonKey,那么所有角色都会像这样存储:

...
[8] [Claim]:{role: ["Admin","User"]}
...

在这种情况下,User.IsInRole("Admin"); 总是返回 false,所以我更喜欢获取所有角色,例如:

...
[8] [Claim]:{role: "Admin"}
[9] [Claim]:{role: "User"}
...

在IdentityServer中添加Config.cs

public static class Config
{
    public static IEnumerable<IdentityResource> IdentityResources =>
        new List<IdentityResource>
        {
            new IdentityResources.OpenId(),
            new IdentityResources.Profile(),
            new IdentityResource("roles", "Your role(s)", new List<string>() { "role" })
        };
    public static IEnumerable<Client> Clients =>
        new List<Client>
        {
            new Client
            {
                ...

                AllowedScopes = new List<string>
                {
                    IdentityServerConstants.StandardScopes.OpenId,
                    IdentityServerConstants.StandardScopes.Profile,
                    "roles"
                }
            }
        };

ConfigurationStore 从 SQL 更改为 Config.cs: 在 IdentityServer Startup.cs 中

var builder = services.AddIdentityServer(options =>
{
    options.Events.RaiseErrorEvents = true;
    options.Events.RaiseInformationEvents = true;
    options.Events.RaiseFailureEvents = true;
    options.Events.RaiseSuccessEvents = true;
    options.EmitStaticAudienceClaim = true;
    options.UserInteraction.LoginUrl = "/Account/Login";
    options.UserInteraction.LogoutUrl = "/Account/Logout";
    options.Authentication = new AuthenticationOptions()
    {
        CookieLifetime = TimeSpan.FromHours(10),
        CookieSlidingExpiration = true
    };
})
    .AddInMemoryIdentityResources(Config.IdentityResources)
    .AddInMemoryApiScopes(Config.ApiScopes)
    .AddInMemoryClients(Config.Clients)
    .AddAspNetIdentity<ApplicationUser>();

你可以使用数据库代替Config.cs,但我不喜欢它,因为它会在数据库中添加很多表,我更喜欢使用配置文件进行少量设置。

【讨论】:

  • 此解决方案适用于身份服务器,但不适用于身份。我正在为所有操作使用身份默认 UI,例如注册新用户等。我试图在您的解决方案中更改“/Identity/Account/Login”中的 LoginUrl,但我没有看到用户声明中的角色。
  • 在这个repository 中,您可以找到适用于 ASP.NET Core Identity 的完整解决方案。
  • 登录和注销我使用IdentityServer准备的AccountController.cs,其他功能使用ASP.NET Core Identity。
  • @Andrelan 我编辑了我的答案,也许它现在涵盖了你的问题。
猜你喜欢
  • 2021-03-18
  • 2019-07-25
  • 2019-02-15
  • 2019-04-22
  • 2023-01-03
  • 2020-12-07
  • 2020-09-19
  • 2020-03-22
  • 2020-01-11
相关资源
最近更新 更多