Asp.NET Core 2.0 API 控制器中的 User.Identity.Name 为空

Posted

技术标签:

【中文标题】Asp.NET Core 2.0 API 控制器中的 User.Identity.Name 为空【英文标题】:User.Identity.Name is empty in Asp.NET Core 2.0 API Controller 【发布时间】:2018-03-30 22:52:00 【问题描述】:

我是 ASP.NET 核心本身的新手。但是,我在 ASP.NET Core 2.0 中创建 WebAPI。我已经配置了基于 JWT Bearer Token 的身份验证。下面是我的控制器,它返回令牌。

    [AllowAnonymous]
[Route("api/[controller]")]
public class TokenController : Controller

    private readonly UserManager<UserEntity> userManager;
    private readonly SignInManager<UserEntity> signInManager;

    public TokenController(UserManager<UserEntity> userManager, SignInManager<UserEntity> signInManager)
    
        this.userManager = userManager;
        this.signInManager = signInManager;
    

    // GET: api/values
    [HttpGet]
    public async Task<IActionResult> Get(string username, string password, string grant_type)
    
        
            var user = await userManager.FindByEmailAsync(username);

            if (user != null)
            
                var result =await signInManager.CheckPasswordSignInAsync(user, password, false);
                if (result.Succeeded)
                

                    var claims = new[]
                    
                        new Claim( JwtRegisteredClaimNames.Sub, username),
                        new Claim( JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
                        new Claim( JwtRegisteredClaimNames.GivenName, "SomeUserID")
                    ;

                    var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("secretesecretesecretesecretesecretesecrete"));
                    var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

                    var token = new JwtSecurityToken( issuer: "test",
                                                     audience: "test",
                                                     claims: claims,
                                                      expires: DateTime.Now.AddDays(15),
                                                      signingCredentials: creds);

                    return Ok(new  access_token = new JwtSecurityTokenHandler().WriteToken(token), expires_on=DateTime.Now.AddDays(15) );

                
            
        

        return BadRequest("Could not create token");
    



但是当调用带有 [Authorize] 属性的 ValuesController API 时。我得到 User.Identity.Name 为空。我没有得到任何关于用户的信息。我不确定,我的令牌控制器是否正确编写。只要它保护我的 ValuesController,我认为它是正确的。但是,我可能会遗漏一些东西。请帮忙。

注意:我正在使用带有 Mac 社区的 Visual Studio 2017 进行开发 加法

【问题讨论】:

【参考方案1】:

是的,您需要指定转换为 user.identity.name 的唯一名称的声明:

new Claim(JwtRegisteredClaimNames.UniqueName, user.UserName)

【讨论】:

在此之后我遇到了另一个问题。 userManager.GetUserAsyc(User) 返回 null。但是 User.Identity.Name 正在返回正确的值。我在这里错过了什么? 尝试 GetUserByName 或电子邮件 我最后使用了 FindByNameAsync 方法。谢谢,我尝试了上述方法,因为用户填充了值。但我想,它不适用于 JWT 令牌。 我认为我们不必特别使用 user.UserName 来访问 Identity.Name。但它奏效了。 我试过了,但它仍然无法正常工作,仍然为空,并且 User.Claims 也得到空数组。【参考方案2】:

我在使用 ASP.Net Core 2 时也遇到过这个问题,我真的很惊讶没有人发现这个问题的其他原因。

当我的 webapp 部署到 IIS 时,“User.Identity.Name”总是返回 null。 IIS 站点禁用了匿名访问,并启用了 Windows 身份验证。

但是。

我没有意识到我的 ASP.Net Core 2 有一个“launchSettings.json”文件,悄悄地隐藏在Properties 文件夹下,里面还有一些 iisSettings,这里是“windowsAuthentication”奇怪的是,默认设置为 false。

将“windowsAuthentication”更改为 true,将“anonymousAuthentication”更改为 false,解决了我的问题。

这样做之后,“User.Identity.Name”终于包含了正确的用户名。

但是这个设置到底是什么?为什么这个会优先于我们在 IIS 管理器中设置的实际设置?!

【讨论】:

为什么这被否决了?这与所提出的问题完全相关,并且此答案尚未在其他任何地方提供。这不是 *** 的重点吗? 也许它并没有为每个人解决问题,就像我在尝试了你建议的修复后仍然坏了。 因为它没有为每个人解决问题并不意味着它不是一个有效的原因。我认为这不值得反对。不过,我不同意 Mike 的论点——launchSettings.json 中的设置应该总是 覆盖 IIS 服务器上的设置。您如何设置一般条件并允许某些应用程序覆盖它们?所以,这是对原始问题的一个很好的回答,但最后一段是不必要的。 @MikeGledhill 在我的情况下,它也运行良好。 *** 必须在投票前征求意见.. 那根手指在某种程度上令人不安【参考方案3】:

使用“DefaultIdentity”(个人用户帐户)也有这个问题(Core 3.1)。 User.Identity.Name 为空,User.Identity.IsAuthenticated = true。 通过使用 httpContextAccessor,您可以获得带有该 ID 的 userId,您可以找到用户和 UserName。 在你的控制器中添加

using System.Security.Claims;
...
private readonly IHttpContextAccessor _httpContextAccessor;
public MyController(MyContext context, IHttpContextAccessor httpContextAccessor)

  _context = context;
  _httpContextAccessor = httpContextAccessor;


// Any method username needed
[HttpGet("id")]
public async Task<ActionResult<MyInfo>> GetMyInfo(int id)

  var userId = _httpContextAccessor.HttpContext.User.FindFirst(ClaimTypes.NameIdentifier).Value;
  var user = _context.AspNetUsers.Find(userId);
  var userName = user.UserName;
  ...

在 Startup.cs 添加以下行:

services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

【讨论】:

谢谢,为我节省了很多时间! 你不需要在Controller中使用HttpContextAccessor。您已经在控制器中有 HttpContext.User。【参考方案4】:

对于 Azure OAuth v2,使用首选用户名而不是唯一名称(see this 和 this)。

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.Extensions.DependencyInjection;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;

serviceCollection.Configure<OpenIdConnectOptions>(OpenIdConnectDefaults.AuthenticationScheme, options =>

    options.TokenValidationParameters.RoleClaimType = "roles";
    options.TokenValidationParameters.NameClaimType = "preferred_username";
    //options.TokenValidationParameters.NameClaimType = "email"; // or if you want to use user's email for User.Identity.Name

    //below lines of code can be removed. just there if you want some code to be executed right after user is validated. 
    options.Events.OnTokenValidated = async context =>
    
        var personFirstName = context.Principal.FindFirstValue("given_name") ?? string.Empty;
        var personLastName = context.Principal.FindFirstValue("family_name") ?? string.Empty;
        var personEmail = context.Principal.FindFirstValue("email")?.ToLower();
        var personName = context.Principal.Identity.Name;
    ;
);

然后在您的控制器中,您将从 User.Identity.Name 获取用户名

【讨论】:

以上是关于Asp.NET Core 2.0 API 控制器中的 User.Identity.Name 为空的主要内容,如果未能解决你的问题,请参考以下文章