问题描述
我觉得我在这里吃疯了的药.通常,对于任何给定的任务,网络上总会有一百万个图书馆和样本.我正在尝试使用 JSON 网络令牌 (JWT) 来实现对 Google服务帐户"的身份验证,如 此处.
然而,只有 PHP、Python 和 Java 的客户端库.即使在 Google 身份验证之外搜索 JWT 示例,也只有关于 JWT 概念的蟋蟀和草稿.这真的很新,可能是谷歌专有系统吗?
我能解释的最接近的 java 示例看起来非常密集和令人生畏.在 C# 中必须有一些我至少可以开始的东西.对此有任何帮助都会很棒!
谢谢大家.我找到了 Json Web Token 的基本实现,并使用 Google 风格对其进行了扩展.我还没有完全搞定,但已经 97% 了.这个项目失去了动力,所以希望这能帮助其他人获得良好的开端:
注意:我对基本实现所做的更改(不记得在哪里找到的)是:
- 更改了 HS256 -> RS256
- 交换了标头中的 JWT 和 alg 顺序.不确定是谁弄错了,谷歌还是规范,但谷歌按照他们的文档采取了下面的方式.
公共枚举 JwtHashAlgorithm{RS256,HS384,HS512}公共类 JsonWebToken{private static Dictionary>哈希算法;静态 JsonWebToken(){HashAlgorithms = new Dictionary>{{ JwtHashAlgorithm.RS256, (key, value) =>{ using (var sha = new HMACSHA256(key)) { return sha.ComputeHash(value);} } },{ JwtHashAlgorithm.HS384, (key, value) =>{ using (var sha = new HMACSHA384(key)) { return sha.ComputeHash(value);} } },{ JwtHashAlgorithm.HS512, (key, value) =>{ using (var sha = new HMACSHA512(key)) { return sha.ComputeHash(value);} } }};}公共静态字符串编码(对象负载,字符串键,JwtHashAlgorithm 算法){return Encode(payload, Encoding.UTF8.GetBytes(key), algorithm);}公共静态字符串编码(对象负载,字节[] keyBytes,JwtHashAlgorithm 算法){var segment = new List();var header = new { alg = algorithm.ToString(), typ = "JWT" };byte[] headerBytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(header, Formatting.None));byte[] payloadBytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(payload, Formatting.None));//byte[] payloadBytes = Encoding.UTF8.GetBytes(@"{"iss":"761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com","scope":"https://www.googleapis.com/auth/pred","aud":"https://accounts.google.com/o/oauth2/token","exp":1328554385,"iat":1328550785}");segment.Add(Base64UrlEncode(headerBytes));segment.Add(Base64UrlEncode(payloadBytes));var stringToSign = string.Join(".",segments.ToArray());var bytesToSign = Encoding.UTF8.GetBytes(stringToSign);byte[] 签名 = HashAlgorithms[algorithm](keyBytes, bytesToSign);segment.Add(Base64UrlEncode(signature));return string.Join(".",segments.ToArray());}公共静态字符串解码(字符串令牌,字符串键){返回解码(令牌,密钥,真);}公共静态字符串解码(字符串令牌,字符串密钥,布尔验证){var 部分 = token.Split('.');var 标头 = 零件 [0];var 有效载荷 = 部分 [1];字节 [] 加密 = Base64UrlDecode(parts[2]);var headerJson = Encoding.UTF8.GetString(Base64UrlDecode(header));var headerData = JObject.Parse(headerJson);var payloadJson = Encoding.UTF8.GetString(Base64UrlDecode(payload));var payloadData = JObject.Parse(payloadJson);如果(验证){var bytesToSign = Encoding.UTF8.GetBytes(string.Concat(header, ".", payload));var keyBytes = Encoding.UTF8.GetBytes(key);var algorithm = (string)headerData["alg"];var 签名 = HashAlgorithms[GetHashAlgorithm(algorithm)](keyBytes, bytesToSign);var decodedCrypto = Convert.ToBase64String(crypto);var decodedSignature = Convert.ToBase64String(signature);if (decodedCrypto != decodedSignature){throw new ApplicationException(string.Format("Invalid signature. Expected {0} got {1}", decodedCrypto, decodedSignature));}}返回payloadData.ToString();}私有静态 JwtHashAlgorithm GetHashAlgorithm(字符串算法){切换(算法){案例RS256":返回JwtHashAlgorithm.RS256;案例HS384":返回JwtHashAlgorithm.HS384;案例HS512":返回JwtHashAlgorithm.HS512;默认值: throw new InvalidOperationException("不支持算法.");}}//来自 JWT 规范私有静态字符串 Base64UrlEncode(byte[] 输入){var 输出 = Convert.ToBase64String(input);output = output.Split('=')[0];//删除任何尾随的 '='soutput = output.Replace('+', '-');//编码的第 62 个字符output = output.Replace('/', '_');//编码的第 63 个字符返回输出;}//来自 JWT 规范私有静态字节[] Base64UrlDecode(字符串输入){var 输出 = 输入;output = output.Replace('-', '+');//编码的第 62 个字符output = output.Replace('_', '/');//编码的第 63 个字符switch (output.Length % 4)//用尾随的 '='s 填充{情况0:中断;//在这种情况下没有填充字符情况2:输出+===";休息;//两个填充字符情况3:输出+==";休息;//一个填充字符默认值: throw new System.Exception("非法的 base64url 字符串!");}var 转换 = Convert.FromBase64String(output);//标准 base64 解码器回报转换;}}
然后是我的 google 特定 JWT 类:
公共类 GoogleJsonWebToken{公共静态字符串编码(字符串电子邮件,字符串证书文件路径){var utc0 = new DateTime(1970,1,1,0,0,0,0, DateTimeKind.Utc);var issueTime = DateTime.Now;var iat = (int)issueTime.Subtract(utc0).TotalSeconds;var exp = (int)issueTime.AddMinutes(55).Subtract(utc0).TotalSeconds;//过期时间长达 1 小时,但让我们安全地玩var 有效载荷 = 新{iss = 电子邮件,scope = "https://www.googleapis.com/auth/gan.readonly",aud = "https://accounts.google.com/o/oauth2/token",exp = exp,iat = iat};var certificate = new X509Certificate2(certificateFilePath, "notasecret");var privateKey = certificate.Export(X509ContentType.Cert);返回 JsonWebToken.Encode(payload, privateKey, JwtHashAlgorithm.RS256);}}
I feel like I'm taking crazy pills here. Usually there's always a million library and samples floating around the web for any given task. I'm trying to implement authentication with a Google "Service Account" by use of JSON Web Tokens (JWT) as described here.
However there is only client libraries in PHP, Python, and Java. Even searching for JWT examples outside of Google's authentication, there is only crickets and drafts on the JWT concept. Is this really so new and possibly a Google proprietary system?
The java sample which is the closest I could manage to interpret looks pretty intensive and intimidating. There's got to be something out there in C# that I could at least start with. Any help with this would be great!
Thanks everyone. I found a base implementation of a Json Web Token and expanded on it with the Google flavor. I still haven't gotten it completely worked out but it's 97% there. This project lost it's steam, so hopefully this will help someone else get a good head-start:
Note:Changes I made to the base implementation (Can't remember where I found it,) are:
public enum JwtHashAlgorithm
{
RS256,
HS384,
HS512
}
public class JsonWebToken
{
private static Dictionary<JwtHashAlgorithm, Func<byte[], byte[], byte[]>> HashAlgorithms;
static JsonWebToken()
{
HashAlgorithms = new Dictionary<JwtHashAlgorithm, Func<byte[], byte[], byte[]>>
{
{ JwtHashAlgorithm.RS256, (key, value) => { using (var sha = new HMACSHA256(key)) { return sha.ComputeHash(value); } } },
{ JwtHashAlgorithm.HS384, (key, value) => { using (var sha = new HMACSHA384(key)) { return sha.ComputeHash(value); } } },
{ JwtHashAlgorithm.HS512, (key, value) => { using (var sha = new HMACSHA512(key)) { return sha.ComputeHash(value); } } }
};
}
public static string Encode(object payload, string key, JwtHashAlgorithm algorithm)
{
return Encode(payload, Encoding.UTF8.GetBytes(key), algorithm);
}
public static string Encode(object payload, byte[] keyBytes, JwtHashAlgorithm algorithm)
{
var segments = new List<string>();
var header = new { alg = algorithm.ToString(), typ = "JWT" };
byte[] headerBytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(header, Formatting.None));
byte[] payloadBytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(payload, Formatting.None));
//byte[] payloadBytes = Encoding.UTF8.GetBytes(@"{"iss":"761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com","scope":"https://www.googleapis.com/auth/prediction","aud":"https://accounts.google.com/o/oauth2/token","exp":1328554385,"iat":1328550785}");
segments.Add(Base64UrlEncode(headerBytes));
segments.Add(Base64UrlEncode(payloadBytes));
var stringToSign = string.Join(".", segments.ToArray());
var bytesToSign = Encoding.UTF8.GetBytes(stringToSign);
byte[] signature = HashAlgorithms[algorithm](keyBytes, bytesToSign);
segments.Add(Base64UrlEncode(signature));
return string.Join(".", segments.ToArray());
}
public static string Decode(string token, string key)
{
return Decode(token, key, true);
}
public static string Decode(string token, string key, bool verify)
{
var parts = token.Split('.');
var header = parts[0];
var payload = parts[1];
byte[] crypto = Base64UrlDecode(parts[2]);
var headerJson = Encoding.UTF8.GetString(Base64UrlDecode(header));
var headerData = JObject.Parse(headerJson);
var payloadJson = Encoding.UTF8.GetString(Base64UrlDecode(payload));
var payloadData = JObject.Parse(payloadJson);
if (verify)
{
var bytesToSign = Encoding.UTF8.GetBytes(string.Concat(header, ".", payload));
var keyBytes = Encoding.UTF8.GetBytes(key);
var algorithm = (string)headerData["alg"];
var signature = HashAlgorithms[GetHashAlgorithm(algorithm)](keyBytes, bytesToSign);
var decodedCrypto = Convert.ToBase64String(crypto);
var decodedSignature = Convert.ToBase64String(signature);
if (decodedCrypto != decodedSignature)
{
throw new ApplicationException(string.Format("Invalid signature. Expected {0} got {1}", decodedCrypto, decodedSignature));
}
}
return payloadData.ToString();
}
private static JwtHashAlgorithm GetHashAlgorithm(string algorithm)
{
switch (algorithm)
{
case "RS256": return JwtHashAlgorithm.RS256;
case "HS384": return JwtHashAlgorithm.HS384;
case "HS512": return JwtHashAlgorithm.HS512;
default: throw new InvalidOperationException("Algorithm not supported.");
}
}
// from JWT spec
private static string Base64UrlEncode(byte[] input)
{
var output = Convert.ToBase64String(input);
output = output.Split('=')[0]; // Remove any trailing '='s
output = output.Replace('+', '-'); // 62nd char of encoding
output = output.Replace('/', '_'); // 63rd char of encoding
return output;
}
// from JWT spec
private static byte[] Base64UrlDecode(string input)
{
var output = input;
output = output.Replace('-', '+'); // 62nd char of encoding
output = output.Replace('_', '/'); // 63rd char of encoding
switch (output.Length % 4) // Pad with trailing '='s
{
case 0: break; // No pad chars in this case
case 2: output += "=="; break; // Two pad chars
case 3: output += "="; break; // One pad char
default: throw new System.Exception("Illegal base64url string!");
}
var converted = Convert.FromBase64String(output); // Standard base64 decoder
return converted;
}
}
And then my google specific JWT class:
public class GoogleJsonWebToken
{
public static string Encode(string email, string certificateFilePath)
{
var utc0 = new DateTime(1970,1,1,0,0,0,0, DateTimeKind.Utc);
var issueTime = DateTime.Now;
var iat = (int)issueTime.Subtract(utc0).TotalSeconds;
var exp = (int)issueTime.AddMinutes(55).Subtract(utc0).TotalSeconds; // Expiration time is up to 1 hour, but lets play on safe side
var payload = new
{
iss = email,
scope = "https://www.googleapis.com/auth/gan.readonly",
aud = "https://accounts.google.com/o/oauth2/token",
exp = exp,
iat = iat
};
var certificate = new X509Certificate2(certificateFilePath, "notasecret");
var privateKey = certificate.Export(X509ContentType.Cert);
return JsonWebToken.Encode(payload, privateKey, JwtHashAlgorithm.RS256);
}
}
这篇关于C# 中是否有任何 JSON Web Token (JWT) 示例?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!