【问题标题】:ClaimTypes.NameIdentifier always return nullClaimTypes.NameIdentifier 总是返回 null
【发布时间】:2020-12-23 20:20:42
【问题描述】:

实际上是 asp.net core 3.1 中的新手,我正在尝试创建用户登录并使用 cookie 注册 当我试图让ClaimTypes.NameIdentifier 总是返回 null 时,你能帮帮我吗? 控制器代码

public class AccountController : ControllerBase
    {
        private readonly ApiSiteDbContext _db;
        private readonly UserManager<AppUser> _userManager;
        private readonly SignInManager<AppUser> _signInManager;
        private readonly RoleManager<AppRole> _roleManager;

        public AccountController(ApiSiteDbContext db,
            UserManager<AppUser> userManager,
            SignInManager<AppUser> signInManager,
            RoleManager<AppRole> roleManager)
        {
            _db = db;
            _userManager = userManager;
            _signInManager = signInManager;
            _roleManager = roleManager;
        }

        [AllowAnonymous]
        [HttpPost("Login")]
        public async Task<IActionResult> Login(LoginModel loginModel)
        {                
            var user = await _userManager.FindByEmailAsync(loginModel.Email);
                          
           // **** this is always return null ***** 
            var id = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
            if (id != null)
            {
                return BadRequest("User already logged !!");
            }

            var result = await _signInManager.PasswordSignInAsync(user, loginModel.Password, loginModel.RememberMe, true);
            if (result.Succeeded)
            {
                if (await _roleManager.RoleExistsAsync("User"))
                {
                    if (!await _userManager.IsInRoleAsync(user, "User"))
                    {
                        await _userManager.AddToRoleAsync(user, "User");
                    }
                }

                var roleName = await GetRoleNameByUserId(user.Id);
                if (roleName != null)
                {
                    AddCookies(user.UserName, user.Id, roleName,  loginModel.RememberMe, user.Email);
                }
                return Ok();
            }
            else if (result.IsLockedOut)
            {
                return Unauthorized("Your account were locked");
            }
            return BadRequest("Wrong  password!");
            //return StatusCode(StatusCodes.Status204NoContent);
        }

        public async void AddCookies(string userName, string userId, string roleName, bool remember, string email)
        {
            var claim = new List<Claim>
            {
                new Claim(ClaimTypes.Name, userName),
                new Claim(ClaimTypes.Email, email),
                new Claim(ClaimTypes.NameIdentifier, userId),
                new Claim(ClaimTypes.Role, roleName),
            };

            var claimIdentity = new ClaimsIdentity(claim, CookieAuthenticationDefaults.AuthenticationScheme);
            if (remember)
            {
                var authProperties = new AuthenticationProperties
                {
                    AllowRefresh = true,
                    IsPersistent = true,
                    ExpiresUtc = DateTime.UtcNow.AddDays(10)
                };

                await HttpContext.SignInAsync
                    (
                        CookieAuthenticationDefaults.AuthenticationScheme,
                        new ClaimsPrincipal(claimIdentity),
                        authProperties
                    );
            }
            else
            {
                var authProperties = new AuthenticationProperties
                {
                    AllowRefresh = true,
                    IsPersistent = false,
                    ExpiresUtc = DateTime.UtcNow.AddMinutes(30)
                };

                await HttpContext.SignInAsync
                    (
                        CookieAuthenticationDefaults.AuthenticationScheme,
                        new ClaimsPrincipal(claimIdentity),
                        authProperties
                    );
            }
        }
    }

在 Startup.cs 中

 public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.Configure<CookiePolicyOptions>(options =>
            {
                options.CheckConsentNeeded = Context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });
            services.AddControllers();
            //services.AddControllersWithViews();
           
            services.AddDbContext<ApiSiteDbContext>();
            services.AddIdentity<AppUser, AppRole>(option =>
            {
                option.Password.RequireDigit = true;
                option.Password.RequiredLength = 6;
                option.Password.RequiredUniqueChars = 0;
                option.Password.RequireLowercase = true;
                option.Password.RequireNonAlphanumeric = true;
                option.Password.RequireUppercase = true;
                option.SignIn.RequireConfirmedEmail = true;
                option.Lockout.MaxFailedAccessAttempts = 5;
                option.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(10);
            }).AddEntityFrameworkStores<ApiSiteDbContext>()
          .AddDefaultTokenProviders();


            services.AddAuthentication(options =>
            {
                options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            })
            .AddCookie(options =>
            {
                options.Cookie.HttpOnly = true;
                options.ExpireTimeSpan = TimeSpan.FromMinutes(30);
                options.LogoutPath = "/api/Account/Logout";
                //options.LoginPath = "/api/Account/Login";
                //options.AccessDeniedPath = "/api/Account/accessDenied";
                options.SlidingExpiration = true;
            });


            services.AddMvc(options => options.EnableEndpointRouting = false)
              .SetCompatibilityVersion(Microsoft.AspNetCore.Mvc.CompatibilityVersion.Version_3_0);

            services.AddCors();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseHttpsRedirection();

            app.UseRouting();

            app.UseCors(x => x.WithOrigins("http://localhost:4200").AllowAnyHeader().AllowAnyMethod().AllowCredentials());
            app.UseMvc();
            app.UseCookiePolicy();

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

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }

当我在另一个控制器中使用这个变量之前检查 NameIdentifier 是否返回 id 时。

【问题讨论】:

  • 在您的Login 方法中,如果id != null,您将返回BadRequest。这意味着当您最终调用 AddCookies 方法(在其中添加 NameIdentifier 声明)时,id 被保证为 null。这就是为什么它总是null,对吧?
  • 请提供Minimal, Complete, and Verifiable example。我建议阅读How to Ask 一个好问题和the perfect question
  • @crgolden 它不是每次都必须返回 null ,我创建这个变量以确保返回值但它没有返回,它必须在第一次登录时为 null 并且如果用户登录返回错误请求有一条消息我把它测试了
  • @MohamedElSoufi 首次登录时确保调用了AddCookies 方法,否则不会有NameIdentifier 声明。

标签: c# asp.net-core asp.net-web-api


【解决方案1】:

确保 roleName 变量不为 null 或字符串为空,因为添加 cookie 取决于此条件

【讨论】:

    猜你喜欢
    • 2020-10-29
    • 2014-03-04
    • 2016-11-02
    • 2014-05-06
    • 2012-06-05
    • 2014-05-30
    • 2014-02-23
    • 2017-10-12
    • 2013-08-16
    相关资源
    最近更新 更多