Azure Function在不使用Active Directory的情况下创建和读取JWT

时间:2018-08-02 12:22:02

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

我正在尝试使用C#在Azure函数中创建和读取(验证)JSON Web令牌(JWT)。我碰到了这篇文章:

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

很好地概述了该过程。作为Azure函数的新手,我在project.json文件中添加了对“ System.IdentityModel.Tokens.Jwt”的引用,如下所示:

{
  "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指令或程序集引用?)”。 / p>

进一步研究,我发现了此页面: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中的代码示例。唯一的区别是我将其包装在Function App中。

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. 下次发生这种情况时,如何确定自己可以同时使用哪个版本?

2 个答案:

答案 0 :(得分: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,这是该软件包的最新版本。

答案 1 :(得分:0)

我知道了。它可以从各种站点和数百种版本组合中运行。 我希望我能解释一下原因,但是我将在这里发布工作代码以及列出的相应库。如果有人遇到这个问题,希望对您有所帮助。感谢您关注这个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个小时的繁琐试验和错误。