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

如何让当前用户进入。NET Core Web API(来自JWT令牌)

  •  74
  • monty  · 技术社区  · 8 年前

    令牌将用户id存储为子声明。

    我还成功地设置了Web API,以在方法使用Authorize注释时验证这些令牌。

     app.UseJwtBearerAuthentication(...)

    如何在控制器(Web API)中读取用户id(存储在主题声明中)?

    基本上是这个问题( How do I get current user in ASP .NET Core )但我需要一个web api的答案。我没有用户管理器。所以我需要从某处阅读主题声明。

    9 回复  |  直到 8 年前
        1
  •  80
  •   Honza Kalfus    8 年前

    被接受的答案对我来说并不适用。我不确定这是不是因为我使用了。NET Core 2.0或其他版本,但它看起来像是框架将主题声明映射到了NameIdentifier声明。因此,以下几点对我很有用:

    string userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
    

    注意,这假设了主题 sub 声明在JWT中设置,其值是用户的id。

    默认情况下,中的JWT身份验证处理程序。NET将JWT访问令牌的子声明映射到 System.Security.Claims.ClaimTypes.NameIdentifier 索赔类型。 [Source]

    还有一个 discussion thread on GitHub

        2
  •  44
  •   Ateik    8 年前

    var email = User.FindFirst("sub")?.Value;
    

    就我而言,我将电子邮件作为一种独特的价值

        3
  •  43
  •   marc_s MisterSmith    7 年前

    似乎很多人都在关注这个问题,所以我想分享一些我之前问这个问题后学到的更多信息。 它让一些事情变得更清楚(至少对我来说),而且不那么明显(对我这个.NET新手来说)。

    评论中提到:

    “web api”也应该如此。。在ASP。NET核心Mvc和Web Api合并使用同一控制器。

    这绝对正确。


    因为这一切都是一样的。NET和。净核心。

    System.Security.Claims 名称空间及其索赔实体、索赔原则和索赔。属性。因此在这两种情况下都使用。NET Core控制器类型(API和MVC或Razor或…)并且可以通过 HttpContext.User .

    重要的一点是,所有教程都没有讲出来。

    ClaimsIdentity , ClaimsPrinciple Claim.Properties . 都是这样。现在你知道了。这是由 海瑞歌


    全部 基于声明的认证中间件(如果正确实现)将填充 在身份验证期间收到的声明。

    HttpContext。使用者 . 但是等等 .UseJwtAuthentication() ).

    使用小型自定义扩展方法,您现在可以像这样获取当前用户id(主题声明更准确)

     public static string SubjectId(this ClaimsPrincipal user) { return user?.Claims?.FirstOrDefault(c => c.Type.Equals("sub", StringComparison.OrdinalIgnoreCase))?.Value; }
    

    或者你在回答


    但是等等 :有一件奇怪的事

    Honza Kalfus公司 在他的回答中做不到。

    因为微软“有时”有些不同。或者至少他们做了更多(意想不到的)事情。例如,原始问题中提到的官方Microsoft JWT承载身份验证中间件。 微软决定在其所有官方认证中间件中转换声明(声明的名称)(出于兼容性原因,我不知道更多细节)。

    您将找不到“sub”声明(尽管它是由OpenID Connect指定的单个声明)。因为它被转换成了 these fancy ClaimTypes

    要么坚持使用Microsoft命名(并且在添加/使用非Microsoft中间件时必须注意),要么了解如何为Microsoft中间件转换声明映射。

    对于JwtBearerAuthentication,它已完成(在启动早期或至少在添加中间件之前完成):

    JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
    

    如果您想坚持使用Microsoft namings主题声明(不要打败我,我现在不确定名称是否是正确的映射):

        public static string SubjectId(this ClaimsPrincipal user) { return user?.Claims?.FirstOrDefault(c => c.Type.Equals(ClaimTypes.NameIdentifier, StringComparison.OrdinalIgnoreCase))?.Value; }
    

    FindFirst 方法虽然我的代码示例显示了这一点,但如果没有这些示例,您可能应该使用它们。

    HttpContext。使用者


    但我的代币呢?

    我不知道是否有其他中间件,但JWT承载身份验证允许为每个请求保存令牌。但这需要激活(在 StartUp.ConfigureServices(... ).

    services
      .AddAuthentication("Bearer")
      .AddJwtBearer("Bearer", options => options.SaveToken = true);
    

    HttpContext.GetTokenAsync("Bearer", "access_token")
    

    这种方法有一个较旧的版本(这在.NETCore2.2中适用,没有不推荐的警告)。

    如果需要从这个字符串中解析和提取值,可能会有问题 How to decode JWT token 有帮助。


    嗯,我希望这个总结也能帮助你。

        4
  •  27
  •   ViRuSTriNiTy    6 年前

    如果您使用 Name ID 在这里:

    var tokenDescriptor = new SecurityTokenDescriptor
    {
        Subject = new ClaimsIdentity(new Claim[]
                    {
                        new Claim(ClaimTypes.Name, user.Id.ToString())
                    }),
        Expires = DateTime.UtcNow.AddDays(7),
        SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
    };
    

    var claimsIdentity = this.User.Identity as ClaimsIdentity;
    var userId = claimsIdentity.FindFirst(ClaimTypes.Name)?.Value;
    
        5
  •  7
  •   Imamul Karim Tonmoy    7 年前

    您可以使用。

    使用者身份名称

        6
  •  6
  •   Wariored    6 年前

    我使用了HttpContext,它运行良好:

    var email = string.Empty;
    if (HttpContext.User.Identity is ClaimsIdentity identity)
    {
        email = identity.FindFirst(ClaimTypes.Name).Value;
    }
    
        7
  •  5
  •   nikolai.serdiuk    6 年前

    在我的例子中,我设置了索赔类型。生成JWT令牌之前将名称命名为唯一用户电子邮件:

    claims.Add(new Claim(ClaimTypes.Name, user.UserName));
    

    然后,我将唯一的用户id存储到ClaimTypes。名称标识符:

    claims.Add(new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()));
    

    然后在控制器代码中:

    int GetLoggedUserId()
            {
                if (!User.Identity.IsAuthenticated)
                    throw new AuthenticationException();
    
                string userId = User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier).Value;
    
                return int.Parse(userId);
            }
    
        8
  •  3
  •   Anmol Maini    5 年前

    我在中使用了以下代码。net core 5 web api

    User.Claims.First(x => x.Type == "id").Value;
    
        9
  •  1
  •   Reza Faghani    4 年前

    asp。net core identity获取用户id

     public async Task<IActionResult> YourMethodName()
    {
        var userId =  User.FindFirstValue(ClaimTypes.NameIdentifier) // will give the user's userId
        var userName =  User.FindFirstValue(ClaimTypes.Name) // will give the user's userName
    
        ApplicationUser applicationUser = await _userManager.GetUserAsync(User);
        string userEmail = applicationUser?.Email; // will give the user's Email
    }
    

    .net core identity获取用户id

     public static class ClaimsPrincipalExtensions
    {
        public static T GetLoggedInUserId<T>(this ClaimsPrincipal principal)
        {
            if (principal == null)
                throw new ArgumentNullException(nameof(principal));
    
            var loggedInUserId = principal.FindFirstValue(ClaimTypes.NameIdentifier);
    
            if (typeof(T) == typeof(string))
            {
                return (T)Convert.ChangeType(loggedInUserId, typeof(T));
            }
            else if (typeof(T) == typeof(int) || typeof(T) == typeof(long))
            {
                return loggedInUserId != null ? (T)Convert.ChangeType(loggedInUserId, typeof(T)) : (T)Convert.ChangeType(0, typeof(T));
            }
            else
            {
                throw new Exception("Invalid type provided");
            }
        }
    
        public static string GetLoggedInUserName(this ClaimsPrincipal principal)
        {
            if (principal == null)
                throw new ArgumentNullException(nameof(principal));
    
            return principal.FindFirstValue(ClaimTypes.Name);
        }
    
        public static string GetLoggedInUserEmail(this ClaimsPrincipal principal)
        {
            if (principal == null)
                throw new ArgumentNullException(nameof(principal));
    
            return principal.FindFirstValue(ClaimTypes.Email);
        }
    }