【问题标题】:Azure Function create and read JWT without using Active DirectoryAzure Function 在不使用 Active Directory 的情况下创建和读取 JWT
【发布时间】:2019-01-10 05:19:03
【问题描述】:

我正在尝试使用 C# 在 Azure 函数中创建和读取(验证)JSON Web 令牌 (JWT)。我偶然发现了这个帖子:

https://www.codeproject.com/Tips/1208535/Create-And-Consume-JWT-Tokens-in-csharp

很好地概述了这个过程。由于对 Azure Functions 来说相对较新,因此我将“System.IdentityModel.Tokens.Jwt”的引用放在我的 project.json 文件中,如下所示:

{
  "frameworks": {
    "net46":{
      "dependencies": {
        "System.IdentityModel.Tokens.Jwt" : "5.0"
      }
    }
   }
}

我使用的版本来自这篇文章:Namespaces for .NET JWT token validation: System vs. Microsoft,它谈到了 2016 年的版本控制问题。

很遗憾,这不起作用。对 SecurityAlgorithms、JwtHeader、JwtPayload、JwtSecurityToken 和 JwtSecurityTokenHandler 的引用都报告,“[run.csx] 找不到类型或命名空间名称‘类名’(您是否缺少 using 指令或程序集引用?)”。

进一步研究,我发现了这个页面:https://www.nuget.org/packages/System.IdentityModel.Tokens.Jwt/,它显示了 System.IdentityModel.Tokens.Jwt 的 Nuget 版本信息。在尝试了几个版本之后(通过更改我的 project.json 文件中的版本),我仍然没有运气让 Function App 识别我需要的类。

我认为这是一个版本问题。如果是这样,我在哪里可以确定哪个版本的“System.IdentityModel.Tokens.Jwt”与“net46”兼容?我已经好几年没有写过 C# 代码了(我是一名 Java 开发人员),所以我可能对版本控制假设有误。

顺便说一句,我的函数中的代码如下所示,它与以下代码示例完全相同:https://www.codeproject.com/Tips/1208535/Create-And-Consume-JWT-Tokens-in-csharp。唯一的区别是我将它包装在一个函数应用程序中。

using System.Net;
using Microsoft.Azure.Documents;
using Microsoft.Azure.Documents.Client;
using System.IdentityModel;  
using System.Security; 
using System.Text;
using System.IdentityModel.Tokens;

public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{
    // Define const Key this should be private secret key  stored in some safe place
           string key = "401b09eab3c013d4ca54922bb802bec8fd5318192b0a75f201d8b3727429090fb337591abd3e44453b954555b7a0812e1081c39b740293f765eae731f5a65ed1";

           // Create Security key  using private key above:
           // not that latest version of JWT using Microsoft namespace instead of System
           var securityKey = new Microsoft
               .IdentityModel.Tokens.SymmetricSecurityKey(Encoding.UTF8.GetBytes(key));

           // Also note that securityKey length should be >256b
           // so you have to make sure that your private key has a proper length
           //
           var credentials = new Microsoft.IdentityModel.Tokens.SigningCredentials
                             (securityKey, SecurityAlgorithms.HmacSha256Signature);

           //  Finally create a Token
           var header = new JwtHeader(credentials);

           //Some PayLoad that contain information about the  customer
           var payload = new JwtPayload
           {
               { "some ", "hello "},
               { "scope", "http://dummy.com/"},
           };


           //
           var secToken = new JwtSecurityToken(header, payload);
           var handler = new JwtSecurityTokenHandler();

           // Token to String so you can use it in your client
           var tokenString = handler.WriteToken(secToken);

           // And finally when  you received token from client
           // you can  either validate it or try to  read
           var token = handler.ReadJwtToken(tokenString);

    return req.CreateResponse(HttpStatusCode.Created, "test");
}

所以,我的问题是:

  1. 我应该在我的项目文件中使用哪个版本的 System.IdentityModel.Tokens 和“net46”?
  2. 下次发生这种情况时,我如何确定哪些版本可以协同工作?

【问题讨论】:

  • 如果您从软件包列表中删除 DocumentDB.Core 会怎样?我想知道你是否遇到了冲突,所以安装不正确。
  • 谢谢brettsam。我在发完这篇文章后确实删除了它。我还删除了对 Console 的引用。这些变化没有任何影响。

标签: azure c#-4.0 jwt azure-functions


【解决方案1】:

我刚试过这个,看到同样的事情。您缺少对 System.IdentityModelusing System.IdentityModel.Tokens.Jwt; 的引用

改成这样让事情变得更好:

#r "System.IdentityModel"

using System.Net;
using System.IdentityModel;
using System.Security;
using System.Text;
using System.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;

我还建议您将 JWT 包参考升级到 5.2.4,这是该包的最新版本。

【讨论】:

    【解决方案2】:

    我想通了。从不同的站点和数百种版本的组合,它可以工作。 我希望我能解释原因,但我会在此处发布工作代码,并列出相应的库。如果其他人遇到这个问题,我希望它有所帮助。感谢您调查此 brettsam!

    Function App 如下所示:

    using System;
    using System.Net; 
    using System.Text;
    using System.IdentityModel.Tokens.Jwt;
    using System.Security.Claims;
    using Microsoft.IdentityModel.Tokens;
    using System.Configuration;
    
    
    public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
    {
        string token = JwtManager.GenerateToken("rbivens@mydomain.com", 60);
        ClaimsPrincipal simplePrinciple = JwtManager.GetPrincipal(token);
    
        var identity = simplePrinciple.Identity as ClaimsIdentity;  
        log.Info(identity.IsAuthenticated.ToString());
    
        var usernameClaim = identity.FindFirst(ClaimTypes.Name);  
        var username = usernameClaim ? .Value;
        log.Info(username);
    
        return req.CreateResponse(HttpStatusCode.Created, token);
    }
    
    
    public static class JwtManager
    {
        private static string secret = ConfigurationManager.AppSettings["FunctionsJwtSecret"];
    
        public static string GenerateToken(string username, int expireMinutes = 60)
        {
            var symmetricKey = Convert.FromBase64String(secret);
            var tokenHandler = new JwtSecurityTokenHandler();
            var now = DateTime.UtcNow;
    
            var tokenDescriptor = new SecurityTokenDescriptor
            {
                Subject = new ClaimsIdentity(new[]
                {
                    new Claim(ClaimTypes.Name, username)
                }),
    
                Expires = now.AddMinutes(Convert.ToInt32(expireMinutes)),
                SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(symmetricKey), SecurityAlgorithms.HmacSha256Signature)
            };
    
            var stoken = tokenHandler.CreateToken(tokenDescriptor);
            var token = tokenHandler.WriteToken(stoken);
            return token;
        }
    
        public static ClaimsPrincipal GetPrincipal(string token)
        {
            try
            {
                var tokenHandler = new JwtSecurityTokenHandler();
                var jwtToken = tokenHandler.ReadToken(token) as JwtSecurityToken;
    
                if (jwtToken == null)
                    return null;
    
                var symmetricKey = Convert.FromBase64String(secret);
    
                var validationParameters = new TokenValidationParameters()
                {
                    RequireExpirationTime = true,
                    ValidateIssuer = false,
                    ValidateAudience = false,
                    IssuerSigningKey = new SymmetricSecurityKey(symmetricKey)
                };
    
                SecurityToken securityToken;
                var principal = tokenHandler.ValidateToken(token, validationParameters, out securityToken);
                // log.Info(securityToken.ToString());
    
                return principal;
            }
    
            catch (Exception)
            {
                return null;
            }
        }
    }
    

    project.json 看起来像这样:

    {
      "frameworks": {
        "net46":{
          "dependencies": {
            "Microsoft.IdentityModel.Logging" : "1.0.0.127",
            "Microsoft.IdentityModel.Tokens" : "5.0.0.127",
            "Newtonsoft.Json" : "9.0.0.0",
            "System.IdentityModel.Tokens.Jwt" : "5.0.0.127"
          }
        }
       }
    }
    

    同样,我不知道为什么这些版本组合可以一起工作,但我希望这可以为其他人节省 20 个小时的繁琐试验和错误。

    【讨论】:

      猜你喜欢
      • 2018-10-08
      • 1970-01-01
      • 1970-01-01
      • 2015-11-15
      • 1970-01-01
      • 2016-09-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多