代码之家  ›  专栏  ›  技术社区  ›  mohsen

User.Identity.Name在我的asp.net核心webapi中为空

  •  0
  • mohsen  · 技术社区  · 6 年前

    我在一个项目和一个数据库中添加了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();
            });
        }
    }
    

    我的配置类,我用它为我的标识数据库种子:

    public class Config
    {
        public static IEnumerable<IdentityResource> GetIdentityResources()
        {
            return new List<IdentityResource>
            {
                new IdentityResources.OpenId(),
                new IdentityResources.Email(),
                new IdentityResources.Profile(),
            };
        }
    
        public static IEnumerable<ApiResource> GetApis()
        {
            return new List<ApiResource>
            {
                new ApiResource("MyAPI", "My asp.net core web api"),
            };
        }
    
        public static IEnumerable<Client> GetClients()
        {
            return new List<Client>
            {
                new Client()
                {
                     ClientId = "MyAndroidApp",
                     ClientName = "My Application for Android",
                     AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
                     ClientSecrets =
                     {
                        new Secret("secret".Sha256())
                     },
                     AllowedScopes=
                     {
                         IdentityServerConstants.StandardScopes.OpenId,
                         IdentityServerConstants.StandardScopes.Profile,
                         IdentityServerConstants.StandardScopes.Email,
                         IdentityServerConstants.StandardScopes.Address,
                         "MyAPI"
                     },
                },
            };
        }
    }
    

    我已在我的IdentityServer4&中的用户控制器中使用以下操作方法向角色管理员注册了一个用户;标识项目

    [HttpPost]
    public async Task<IActionResult> Post([FromBody]SignUpModel model)
    {                               
        MydentityUser NewUser = new MydentityUser ()
                {
                    UserName = model.UserName,
                };
        IdentityResult result = await UserManager.CreateAsync(NewUser, model.Password);
    
        if (result.Succeeded)
        {
            if (!RoleManager.RoleExistsAsync("Admin").Result)
            {
                IdentityResult r = RoleManager.CreateAsync(new IdentityRole("Admin")).Result;
                r = RoleManager.CreateAsync(new IdentityRole("Member")).Result;
                r = RoleManager.CreateAsync(new IdentityRole("Guest")).Result;
            }
    
            result = await UserManager.AddToRoleAsync(NewUser, "Admin");
    
            if (result.Succeeded)
            {
                List<Claim> UserClaims = new List<Claim>() {
                        new Claim("userName", NewUser.UserName),
                        new Claim(JwtClaimTypes.Role, "Admin"),
                    };
    
                result = await UserManager.AddClaimsAsync(NewUser, UserClaims.ToArray());
                return Ok("Registered");
            }
        }            
    }
    

    现在我有另一个ASP.NETWebAPI项目,我想在我的android应用程序中使用这个API。

    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)
                .AddJwtBearer(options =>
                {
                    options.Authority = "https://identity.mywebsite.ir";
                    options.RequireHttpsMetadata = false;
                    options.Audience = "MyAPI";                    
                });
             //I used below but not work too
            //.AddIdentityServerAuthentication(options =>
            //{
            //    options.Authority = "https://identity.mywebsite.ir";
            //    options.RequireHttpsMetadata = false;
            //    options.ApiName = "MyAPI";
            //    options.NameClaimType = ClaimTypes.Name;
            //    options.RoleClaimType = ClaimTypes.Role;                    
            //});
    
            services.AddOptions();
            string cs = Configuration["AppSettings:DefaultConnection"];
            services.AddDbContext<MyApiContext>(options =>
            {
                options.UseSqlServer(cs,
                    sqlServerOptions =>
                    {
                        sqlServerOptions.MigrationsAssembly("MyApi.Database");
                    });
            });
    
            services.AddControllers();
    
            services.AddCors(options =>
            {
                options.AddPolicy("default", policy =>
                {
                    policy.WithOrigins("*")
                        .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();
            });
        }
    }
    

    我的问题是,当我在另一个项目中使用ASP.NET核心身份的用户身份验证时,如何在我的Webapi中找到用户ID,

    public class TestController : ControllerBase
    {
        public async Task<IActionResult> Index()
        {            
            string message = "";
    
            if (User.Identity.IsAuthenticated)
            {
                message += "You are Registered ";
            }
            else
            {
                message += "You are not Registered ";
            }
    
            if (string.IsNullOrWhiteSpace(User.Identity.Name))
            {
                message += "UserId is null";
            }
            else
            {
                message += "UserId is not null";
            }
    
            return Ok(message);
        }
    }
    

    我得到这个信息:

    您未注册用户ID为空

    如何在WebAPI中访问我的用户ID?为什么User.Identity.Name为空?为什么 User.Identity.Claims.Count

    编辑

    我已经在jwt.io网站中输入了访问令牌,这是输出

    {
      "nbf": 1587133648,
      "exp": 1587137248,
      "iss": "https://identity.mywebsite.ir",
      "aud": "MyAPI",
      "client_id": "MyAndroidApp",
      "sub": "7e904278-78cc-46a8-9943-51dfeb360d8e",// I want this in my api but i get null
      "auth_time": 1587133648,
      "idp": "local",
      "scope": [
        "openid",
        "MyAPI"
      ],
      "amr": [
        "pwd"
      ]
    }
    

    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();
                });
            }
        }
    
    0 回复  |  直到 6 年前
        1
  •  6
  •   mohsen    6 年前

    在我的例子中,问题在于我没有将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,
                        }
                    },
                };
            }
    

    现在我将使用下面的代码获取UserId和UserName

    
        public static class ClaimsPrincipalExtensions
        {
            public static string GetSub(this ClaimsPrincipal principal)
            {
                return principal?.FindFirst(x => x.Type.Equals("sub"))?.Value;
            }
            public static string GetEmail(this ClaimsPrincipal principal)
            {
                return principal?.FindFirst(x => x.Type.Equals("email"))?.Value;
            }
        }
    

    string UserId=User.GetSub();
    
        2
  •  5
  •   Feras Taleb    6 年前

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

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

    http://schemas.microsoft.com/ws/2008/06/identity/claims/name

    http://schemas.microsoft.com/ws/2008/06/identity/claims/role . (角色)

    http://schemas.microsoft.com/ws/2008/06/identity/claims/nameidentifier

    因此,您需要清除此映射,因为在您的令牌中,声明类型是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,我认为只清除默认的入站类型就足够了。


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

    options.DefaultAuthenticateScheme=IdentityServerAuthenticationDefaults.AuthenticationScheme;

    3-在IdentityServer 4中启动