C# User.Identity.Name在我的ASP.NET核心Web API中为空

C# User.Identity.Name在我的ASP.NET核心Web API中为空,c#,authentication,authorization,asp.net-identity,identityserver4,C#,Authentication,Authorization,Asp.net Identity,Identityserver4,我在一个项目和一个数据库中添加了ASP.NET Core identity和identity Server4,我想在所有其他项目中使用我的identity Server IdentityServer4启动类 public class Startup { public IConfigurationRoot Config { get; set; } public Startup(IConfiguration configuration) { Config =

我在一个项目和一个数据库中添加了ASP.NET Core identity和identity Server4,我想在所有其他项目中使用我的identity Server

IdentityServer4启动类

public class Startup
{
    public IConfigurationRoot Config { get; set; }

    public Startup(IConfiguration configuration)
    {
        Config = new ConfigurationBuilder()
                     .SetBasePath(Directory.GetCurrentDirectory())
                     .AddJsonFile("appsettings.json", false)
                     .Build();

        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        IdentityModelEventSource.ShowPII = true;

        //=== Identity Config ===
        string ConnectionString = Config.GetSection("AppSettings:DefaultConnection").Value;
        var migrationAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;

        //-----------------------------------------------------------------
        services.AddDbContext<MyIdentityDbContext>(options =>
             options.UseSqlServer(ConnectionString, sql => sql.MigrationsAssembly(migrationAssembly)));

        //-----------------------------------------------------------------
        services.AddIdentity<MyIdentityUser, IdentityRole>(op =>
        {
            op.Password.RequireDigit = false;
            op.Password.RequiredLength = 6;
            op.Password.RequireUppercase = false;
            op.Password.RequireLowercase = false;
            op.Password.RequireNonAlphanumeric = false;
        })
        .AddEntityFrameworkStores<MyIdentityDbContext>()
        .AddDefaultTokenProviders();

        //=== IdentityServer4 config ===
        services.AddIdentityServer(options =>
        {
            options.Events.RaiseErrorEvents = true;
            options.Events.RaiseInformationEvents = true;
            options.Events.RaiseFailureEvents = true;
            options.Events.RaiseSuccessEvents = true;
        })
            .AddDeveloperSigningCredential()
            .AddConfigurationStore(options =>
            {
                options.ConfigureDbContext = b => b.UseSqlServer(ConnectionString, sql => sql.MigrationsAssembly(migrationAssembly));
            })
            .AddOperationalStore(options =>
            {
                options.ConfigureDbContext = b => b.UseSqlServer(ConnectionString, sql => sql.MigrationsAssembly(migrationAssembly));
            })
            .AddAspNetIdentity<MyIdentityUser>();

        services.AddMvc(options => options.EnableEndpointRouting = false);
        services.AddAuthorization();
        services.AddControllers();
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        app.UseAuthentication();
        app.UseRouting();

        app.UseAuthorization();
        app.UseIdentityServer();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    }
}
MyApi启动类

 public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = "oidc";
            })

        .AddIdentityServerAuthentication(options =>
        {
            options.Authority = "https://identity.mywebsite.ir";
                options.RequireHttpsMetadata = false;
            options.ApiName = "MyAPI";
            });

            services.AddOptions();
            string cs = Configuration["AppSettings:DefaultConnection"];
            services.AddDbContext<MyCommonDbContext>(options =>
            {
                options.UseSqlServer(cs,
                    sqlServerOptions =>
                    {
                        sqlServerOptions.MigrationsAssembly("MyAppProjectName");
                    });
            });
            services.AddDbContext<MyAppContext>(options =>
            {
                options.UseSqlServer(cs,
                    sqlServerOptions =>
                    {
                        sqlServerOptions.MigrationsAssembly("MyAppProjectName");
                    });
            });

            services.AddControllers();

            services.AddCors(options =>
            {
                options.AddPolicy("default", policy =>
                {
                    policy.WithOrigins("http://*.mywebsite.ir")
                        .AllowAnyHeader()
                        .AllowAnyMethod();
                });
            });
        }
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            app.UseRouting();
            app.UseCors("default");
            app.UseAuthentication();
            app.UseAuthorization();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
公共类启动
{
public void配置服务(IServiceCollection服务)
{
services.AddAuthentication(选项=>
{
options.DefaultAuthenticateScheme=IdentityServerAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme=“oidc”;
})
.AddIdentityServerAuthentication(选项=>
{
选项。权限=”https://identity.mywebsite.ir";
options.RequireHttpsMetadata=false;
options.ApiName=“MyAPI”;
});
services.AddOptions();
字符串cs=Configuration[“AppSettings:DefaultConnection”];
services.AddDbContext(选项=>
{
选项。使用SQLServer(cs,
sqlServerOptions=>
{
sqlServerOptions.MigrationsAssembly(“MyAppProjectName”);
});
});
services.AddDbContext(选项=>
{
选项。使用SQLServer(cs,
sqlServerOptions=>
{
sqlServerOptions.MigrationsAssembly(“MyAppProjectName”);
});
});
services.AddControllers();
services.AddCors(选项=>
{
options.AddPolicy(“默认”,策略=>
{
policy.WithOrigins(“http://*.mywebsite.ir”)
.AllowAnyHeader()
.AllowAnyMethod();
});
});
}
public void配置(IApplicationBuilder应用程序、IWebHostEnvironment环境)
{
if(env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
应用程序UseCors(“默认”);
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(端点=>
{
endpoints.MapControllers();
});
}
}

在我的案例中,问题在于我没有将UserClaims添加到ApiResources中,因此我更改了种子ApiResource方法,如下所示,并添加了声明

public static IEnumerable<ApiResource> GetApis()
        {

            return new List<ApiResource>
            {
                new ApiResource("MyAPI", "My Asp.net core WebApi,the best Webapi!"){
                    UserClaims =
                    {
                        JwtClaimTypes.Name,
                        JwtClaimTypes.Subject,
                        JwtClaimTypes.Role,
                    }
                },
            };
        }
获取用户ID

string UserId=User.GetSub();

在我的例子中,问题在于我没有将UserClaims添加到ApiResources中,所以我更改了种子ApiResource方法,如下所示,并添加了声明

public static IEnumerable<ApiResource> GetApis()
        {

            return new List<ApiResource>
            {
                new ApiResource("MyAPI", "My Asp.net core WebApi,the best Webapi!"){
                    UserClaims =
                    {
                        JwtClaimTypes.Name,
                        JwtClaimTypes.Subject,
                        JwtClaimTypes.Role,
                    }
                },
            };
        }
获取用户ID

string UserId=User.GetSub();
在ConfigureServices中的“MyApi”startup.cs文件中:

1-确保在添加身份验证之前执行这行代码: JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear()

因为(感谢!!!对于microsoft--),默认情况下,名称的声明类型映射为:

(名字或类似的东西)

。(角色)

(身份证)

因此,您需要清除此映射,因为在您的令牌中,声明类型是jwt标准,sub==userid,并且您暂时不在您共享的令牌中嵌入名称或角色

顺便说一下,我通常使用这部分代码:

services.AddAuthentication("Bearer")
                .AddJwtBearer("Bearer", options =>
                {
                    options.Authority = "";
                    options.RequireHttpsMetadata = true;
                    options.Audience = "myapi";
                    options.TokenValidationParameters = new TokenValidationParameters
                    {
                        NameClaimType = "name",
                        RoleClaimType = "role",
                    };
                });
您只需要以下部件:

                        options.TokenValidationParameters = new TokenValidationParameters
                    {
                        NameClaimType = "name",
                        RoleClaimType = "role",
                    };
顺便说一下,keep require https设置为true而不是false

对于UserId,我认为只清除默认的入站类型就足够了


我不确定您是否真的需要第二步,但请仔细检查:

2-确保AuthenticationScheme值为“载体”: options.DefaultAuthenticateScheme=IdentityServerAuthenticationDefaults.AuthenticationScheme

3-在IdentityServer 4中启动

请在UseRouting之后而不是之前保留UseAuthentication(这与您的问题无关,但我刚刚注意到)

在ConfigureServices中的“MyApi”startup.cs文件中:

1-确保在添加身份验证之前执行这行代码: JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear()

因为(感谢!!!对于microsoft--),默认情况下,名称的声明类型映射为:

(名字或类似的东西)

。(角色)

(身份证)

因此,您需要清除此映射,因为在您的令牌中,声明类型是jwt标准,sub==userid,并且您暂时不在您共享的令牌中嵌入名称或角色

顺便说一下,我通常使用这部分代码:

services.AddAuthentication("Bearer")
                .AddJwtBearer("Bearer", options =>
                {
                    options.Authority = "";
                    options.RequireHttpsMetadata = true;
                    options.Audience = "myapi";
                    options.TokenValidationParameters = new TokenValidationParameters
                    {
                        NameClaimType = "name",
                        RoleClaimType = "role",
                    };
                });
您只需要以下部件:

                        options.TokenValidationParameters = new TokenValidationParameters
                    {
                        NameClaimType = "name",
                        RoleClaimType = "role",
                    };
顺便说一下,keep require https设置为true而不是false

对于UserId,我认为只清除默认的入站类型就足够了


我不确定您是否真的需要第二步,但请仔细检查:

2-确保AuthenticationScheme值为“载体”: options.DefaultAuthenticateScheme=IdentityServerAuthenticationDefaults.AuthenticationScheme

3-在IdentityServer 4中启动


请在UseRouting之后而不是之前保留UseAuthentication(这与您的问题无关,但我刚刚注意到)

在创建令牌时,您需要在声明中存储userId。然后使用“User.Claims.FirstOrDefault(x=>x.type==“userId”);“您可以在token.com中看到
userId
,但是当我想用
User.Identity.Name
获得它时,它是空的。事实上User.Claims.Count是0您是否忘了将
服务.AddAuthorization
添加到API的ConfigureServices方法中?还是您在示例中遗漏了它?@Dennis1679不,我在api中有这个问题,我将编辑问题以添加api启动类,我已经解决了我的问题,我将很快回答我的问题,谢谢您在创建令牌时需要在声明中存储用户ID。然后使用类似“User.Claims.FirstOrDefault(x=>x.type==“userId”);”的claimprincil,您可以
services.AddAuthentication("Bearer")
                .AddJwtBearer("Bearer", options =>
                {
                    options.Authority = "";
                    options.RequireHttpsMetadata = true;
                    options.Audience = "myapi";
                    options.TokenValidationParameters = new TokenValidationParameters
                    {
                        NameClaimType = "name",
                        RoleClaimType = "role",
                    };
                });
                        options.TokenValidationParameters = new TokenValidationParameters
                    {
                        NameClaimType = "name",
                        RoleClaimType = "role",
                    };