ASP.Net Core JWT登录未设置HttpContext.User.Claims

时间:2018-11-10 10:01:25

标签: c# asp.net-core jwt

我的登录代码有以下内容,还有另一种在另一个呼叫中检索用户ID的方法。

        // POST: /api/Account/Login
    [HttpPost]
    [AllowAnonymous]
    public async Task<IActionResult> Login([FromBody]LoginViewModel model)
    {
        if (ModelState.IsValid)
        {
            var user = await _userManager.FindByEmailAsync(model.Email);
            if (user != null)
            {
                if (!await _userManager.IsEmailConfirmedAsync(user))
                {
                    ModelState.AddModelError(string.Empty, 
                                "You must have a confirmed email to log in.");
                    return BadRequest(Errors.AddErrorToModelState("Email", "You must have a confirmed email to log in.", ModelState));
                }
            }

            var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: false);

            if (result.Succeeded)
            {
                // IS THIS NEEDED? --> // HttpContext.User = await _userClaimsPrincipalFactory.CreateAsync(user);
                var tokens = _antiforgery.GetAndStoreTokens(HttpContext);

                var identity = _jwtFactory.GenerateClaimsIdentity(model.Email, user.Id);
                _logger.LogInformation(1, "User logged in.");
                var jwt = await Tokens.GenerateJwt(identity, _jwtFactory, model.Email, _jwtOptions, new JsonSerializerSettings { Formatting = Formatting.Indented });
                return new OkObjectResult(jwt);
            }

            if (result.RequiresTwoFactor)
            {
                //return RedirectToAction(nameof(SendCode), new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
            }

            if (result.IsLockedOut)
            {
                string message = "User account locked out.";
                _logger.LogWarning(2, message);
                return BadRequest(Errors.AddErrorToModelState("Email", message, ModelState));
            }

            if (result.IsNotAllowed)
            {
                string message = "User account is not allowed to sign in.";
                _logger.LogWarning(2, message);
                return BadRequest(Errors.AddErrorToModelState("Email", message, ModelState));
            }

            return BadRequest(Errors.AddErrorToModelState("", "Sign in failed.", ModelState));
        }

        return BadRequest(Errors.AddErrorToModelState("", "", ModelState));            
    }

    public string GetUserId()
    {
        string username = string.Empty;

        ClaimsPrincipal principal = HttpContext.User as ClaimsPrincipal;  

        if (HttpContext.User != null)
        {
            var id = HttpContext.User.FindFirst(ClaimTypes.NameIdentifier);

            if (id != null)
            {
                username = id.Value;
            }
        }

        return username;
    }

这是GenerateJwt的代码。 (这些字段是标准字段吗?我看到其他字段已在其他代码中设置,例如在https://code-maze.com/authentication-aspnetcore-jwt-1/中。)

  public static async Task<string> GenerateJwt(ClaimsIdentity identity, IJwtFactory jwtFactory,string userName, JwtIssuerOptions jwtOptions, JsonSerializerSettings serializerSettings)
  {
    var response = new
    {
      id = identity.Claims.Single(c => c.Type == "id").Value,
      auth_token = await jwtFactory.GenerateEncodedToken(userName, identity),
      expires_in = (int)jwtOptions.ValidFor.TotalSeconds
    }; // see GenerateEncodedToken pasted below.

    return JsonConvert.SerializeObject(response, serializerSettings);
  }

    public async Task<string> GenerateEncodedToken(string userName, ClaimsIdentity identity)
    {
        var claims = new[]
     {
             new Claim(JwtRegisteredClaimNames.Sub, userName),
             new Claim(JwtRegisteredClaimNames.Jti, await _jwtOptions.JtiGenerator()),
             new Claim(JwtRegisteredClaimNames.Iat, ToUnixEpochDate(_jwtOptions.IssuedAt).ToString(), ClaimValueTypes.Integer64),
             identity.FindFirst(Helpers.Constants.Strings.JwtClaimIdentifiers.Rol),
             identity.FindFirst(Helpers.Constants.Strings.JwtClaimIdentifiers.Id)
         };

        // Create the JWT security token and encode it.
        var jwt = new JwtSecurityToken(
            issuer: _jwtOptions.Issuer,
            audience: _jwtOptions.Audience,
            claims: claims,
            notBefore: _jwtOptions.NotBefore,
            expires: _jwtOptions.Expiration,
            signingCredentials: _jwtOptions.SigningCredentials);

        var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);

        return encodedJwt;
    }

这些是ConfigureServices中的相关行。

  // jwt wire up
  // Get options from app settings
  var jwtAppSettingOptions = Configuration.GetSection(nameof(JwtIssuerOptions));

  // Configure JwtIssuerOptions
  services.Configure<JwtIssuerOptions>(options =>
  {
    options.Issuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)];
    options.Audience = jwtAppSettingOptions[nameof(JwtIssuerOptions.Audience)];
    options.SigningCredentials = new SigningCredentials(_signingKey, SecurityAlgorithms.HmacSha256);
  });

  var tokenValidationParameters = new TokenValidationParameters
  {
    ValidateIssuer = true,
    ValidIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)],

    ValidateAudience = true,
    ValidAudience = jwtAppSettingOptions[nameof(JwtIssuerOptions.Audience)],

    ValidateIssuerSigningKey = true,
    IssuerSigningKey = _signingKey,

    RequireExpirationTime = false,
    ValidateLifetime = true,
    ClockSkew = TimeSpan.Zero
  };

  services.AddAuthentication(options =>
  {
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;

  }).AddJwtBearer(configureOptions =>
  {
    configureOptions.ClaimsIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)];
    configureOptions.TokenValidationParameters = tokenValidationParameters;
    configureOptions.SaveToken = true;
    configureOptions.RequireHttpsMetadata = false;
  });

  // api user claim policy
  services.AddAuthorization(options =>
  {
    options.AddPolicy("ApiUser", policy => policy.RequireClaim(Constants.Strings.JwtClaimIdentifiers.Rol, Constants.Strings.JwtClaims.ApiAccess));
  });

  // add identity
  var builder = services.AddIdentity<AppUser, AppRole>(o =>
  {
    // configure identity options
    o.Password.RequireDigit = false;
    o.Password.RequireLowercase = false;
    o.Password.RequireUppercase = false;
    o.Password.RequireNonAlphanumeric = false;
    o.Password.RequiredLength = 6;
  })
  .AddSignInManager<SignInManager<AppUser>>()
  .AddEntityFrameworkStores<AppIdentityDbContext>()
  .AddDefaultTokenProviders();

我正在使用以下代码从Angular传递令牌。

  private authHeader(): HttpHeaders {
  let headers = new HttpHeaders();
  if (isPlatformBrowser(this.platformId)) {
    headers = headers.set('Content-Type', 'application/json');
    let authToken = this.windowRefService.nativeWindow.localStorage.getItem('auth_token');
    headers = headers.set('Authorization', authToken);
    headers = headers.set('X-XSRF-TOKEN', this.getCookie('XSRF-TOKEN'));
  }

  return headers;
}

  protected jsonAuthRequestOptions = { headers: this.authHeader() };

public loggedInAs(): Observable<string> {
    return this.http.post<any>(this.baseUrl + "api/Account/GetUserId", { } , this.jsonAuthRequestOptions)
    .map(data => {
        if (data) {
            return data;
        }

        return '';
    })
    .catch(this.handleError);
}

JWT身份验证是否自动设置HttpContext.User?还是我必须明确地做到这一点?

我的后续呼叫失败。 (用户没有声明,尽管HttpContext.User不为null。)我不知道问题是否在于依赖HttpContext.User,或者令牌生成/使用是否有问题。

1 个答案:

答案 0 :(得分:-1)

有类似的问题。来自令牌的声明未传递给HttpContext.User.Identity.Claims。 就我而言,更改添加服务的顺序很有帮助。在添加身份验证之前添加身份。

在startup.cs中,我现在有:

services.AddIdentity(); services.AddAuthentication();