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 为空的主要内容,如果未能解决你的问题,请参考以下文章

没有身份的 ASP.NET Core 2.0 承载身份验证

Asp.net Core 2.0 web api 基础框架 详解

从头编写 asp.net core 2.0 web api 基础框架

asp.net core 2.0 web api基于JWT自定义策略授权

在控制器中更改 ASP.NET Core 2.0 标识连接字符串

用VSCode开发一个asp.net core2.0+angular5项目: Angular5+asp.net core 2.0 web api文件上传