在 .net core 3.1 中,如何从不记名令牌返回数据?

Posted

技术标签:

【中文标题】在 .net core 3.1 中,如何从不记名令牌返回数据?【英文标题】:In .net core 3.1 how can I return data from a bearer token? 【发布时间】:2020-08-12 18:28:30 【问题描述】:

我正在尝试从不记名令牌返回一些数据,以用作我在端点中调用的函数中的参数。目前,当我测试代码时,我需要作为参数的两个字符串 userName 和 applicationName 返回 null,所以我得到一个 500。这很好,但我需要 userName 和 applicationName 来存储数据以用作函数 GetAbsoluteTimeout() 中的参数; 我怎样才能做到这一点?

端点:

        [ProducesResponseType(typeof(int), StatusCodes.Status200OK)]
        [ProducesResponseType(typeof(StatusCodeResult), StatusCodes.Status401Unauthorized)]
        [ProducesResponseType(typeof(StatusCodeResult), StatusCodes.Status500InternalServerError)]
        [Consumes(MediaTypeNames.Application.Json)]
        [Produces(MediaTypeNames.Application.Json)]
        [IDMAuthorize]
        public IActionResult GetAbsoluteTimeoutForClaimsPrincipal()
        
            DateTime startTime = DateTime.Now;
            try
            
                string logText = LogFormatter.Format(
                                   WebUtilities.GetUser((ClaimsIdentity)HttpContext.User.Identity),
                                   startTime, DateTime.Now, Privilege.NotApplicable,
                                   "Get Absolute Timeout For Claims Principal", "Attempting to get the absolute timeout for the current user.");
                logger.LogInfo(logText);

                string userName = Convert.ToString(JsonConvert.DeserializeObject(HttpContext.Request.Headers["email"]));
                string applicationName = Convert.ToString(JsonConvert.DeserializeObject(HttpContext.Request.Headers["client_id"]));
                int timeout = 0;

                if (!string.IsNullOrEmpty(userName) && !string.IsNullOrEmpty(applicationName))
                
                    timeout = GetAbsoluteTimeout(userName, applicationName);
                

                logText = LogFormatter.Format(
                                   WebUtilities.GetUser((ClaimsIdentity)HttpContext.User.Identity),
                                   startTime, DateTime.Now, Privilege.NotApplicable,
                                   "Get Absolute Timeout For Claims Principal", "Successful retrieval of the absolute timeout for the current user.");
                logger.LogInfo(logText);

                return Ok(timeout);
            
            catch (Exception ex)
            
                string logText = LogFormatter.Format(
                                    WebUtilities.GetUser((ClaimsIdentity)HttpContext.User.Identity),
                                    startTime, DateTime.Now, Privilege.ViewIMUData,
                                     "Get Absolute Timeout For Claims Principal", ex.ToString());

                logger.LogError(logText, ex);
                return StatusCode(Constants.InternalServerErrorCode, "Failed to get absolute timeout for claims principal. Please check logs for more details. ");
            

        

这是来自 JWT 不记名令牌的数据:

"client_id": "JITWebAdmin",
  "scope": [
    "openid",
    "profile",
    "email",
    "jitwebapi"
  ],
  "sub": "dd458da9-5de6-4f79-8756-e4756fef63a3",
  "auth_time": 1588098606,
  "idp": "idm-JadenCCE21-8a9fa4f4-62c2-4c8f-afe6-4ffb740e2327",
  "updated_at": 1566433758,
  "tenant": "default",
  "preferred_username": "admin",
  "email": "admin@email.com",
  "email_verified": "true",
  "login_attempt": "\"LoginDate\":\"2020-04-28 18:28:46Z\",\"WasSuccessful\":true,\"IpAddress\":\"10.160.176.79\"",
  "name": "admin",
  "amr": [
    "external"
  ]

【问题讨论】:

【参考方案1】:

我使用此代码向jwt 添加声明并颁发令牌:

var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(EncryptionKey);
var tokenDescriptor = new SecurityTokenDescriptor

    Subject = new ClaimsIdentity(new Claim[]
    
        new Claim(ClaimTypes.Name, user.Username),
        new Claim(ClaimTypes.NameIdentifier , user.Id.ToString()),
    ),
    Expires = DateTime.UtcNow.AddDays(1),
    SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
;
var token = tokenHandler.CreateToken(tokenDescriptor);
var tokenString = tokenHandler.WriteToken(token);

例如,在new Claim(ClaimTypes.NameIdentifier , user.Id.ToString())这行代码中,您可以在令牌中放入任何您想要的东西。

当您想在控制器中读取该数据时,只需使用以下代码:

var userId = HttpContext.User.Claims.SingleOrDefault(x => x.Type == ClaimTypes.NameIdentifier).Value;

【讨论】:

以上是关于在 .net core 3.1 中,如何从不记名令牌返回数据?的主要内容,如果未能解决你的问题,请参考以下文章

不记名令牌出现 401 错误 - asp.net core 3.1

JWT 不记名令牌不适用于 ASP.Net Core 3.1 + Identity Server 4

如何在 Asp .Net Core SignalR Hub 中获取不记名令牌?

如何诊断尝试在 c# .NET Core 中获取 OAuth2 不记名令牌的 401 错误?

JwtSecurityToken 过期时间无效 .NET Core 3.1

尝试对 ASP.NET Core 3.1 使用多个身份验证方案时出现异常