我正在尝试使用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");
}
所以,我的问题是:
答案 0 :(得分:1)
我只是尝试了一下,看到了同样的东西。您缺少对System.IdentityModel
和using 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个小时的繁琐试验和错误。