我觉得我在这里吃了疯狂的药丸。通常,对于任何给定的任务,网络上总是有一百万个库和样本。我正在尝试使用JSON Web Tokens(JWT)使用Google“服务帐户”实现身份验证,如下所述。
然而,只有PHP、Python和Java的客户端库。即使在谷歌认证之外搜索JWT的例子,也只有关于JWT概念的蟋蟀和草稿。这真的这么新,可能是谷歌的专有系统吗?
我能解释的最接近的java示例看起来相当密集和吓人。C#中肯定有什么东西我至少可以从它开始。这方面的任何帮助都将是巨大的!
这是我在. NET中实现的(Google)JWT验证。它基于Stack Overflow和GitHub gists上的其他实现。
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Net.Http;
using System.Security.Claims;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
namespace QuapiNet.Service
{
public class JwtTokenValidation
{
public async Task<Dictionary<string, X509Certificate2>> FetchGoogleCertificates()
{
using (var http = new HttpClient())
{
var response = await http.GetAsync("https://www.googleapis.com/oauth2/v1/certs");
var dictionary = await response.Content.ReadAsAsync<Dictionary<string, string>>();
return dictionary.ToDictionary(x => x.Key, x => new X509Certificate2(Encoding.UTF8.GetBytes(x.Value)));
}
}
private string CLIENT_ID = "xxx.apps.googleusercontent.com";
public async Task<ClaimsPrincipal> ValidateToken(string idToken)
{
var certificates = await this.FetchGoogleCertificates();
TokenValidationParameters tvp = new TokenValidationParameters()
{
ValidateActor = false, // check the profile ID
ValidateAudience = true, // check the client ID
ValidAudience = CLIENT_ID,
ValidateIssuer = true, // check token came from Google
ValidIssuers = new List<string> { "accounts.google.com", "https://accounts.google.com" },
ValidateIssuerSigningKey = true,
RequireSignedTokens = true,
IssuerSigningKeys = certificates.Values.Select(x => new X509SecurityKey(x)),
IssuerSigningKeyResolver = (token, securityToken, kid, validationParameters) =>
{
return certificates
.Where(x => x.Key.ToUpper() == kid.ToUpper())
.Select(x => new X509SecurityKey(x.Value));
},
ValidateLifetime = true,
RequireExpirationTime = true,
ClockSkew = TimeSpan.FromHours(13)
};
JwtSecurityTokenHandler jsth = new JwtSecurityTokenHandler();
SecurityToken validatedToken;
ClaimsPrincipal cp = jsth.ValidateToken(idToken, tvp, out validatedToken);
return cp;
}
}
}
请注意,为了使用它,您需要添加对NuGet包System.Net.Http.Formatting.Extension
的引用。没有这个,编译器将无法识别ReadAsAsync
我从未使用过它,但是在NuGet上有一个JWT实现。
包装:https://nuget.org/packages/JWT
资料来源:https://github.com/johnsheehan/jwt
. NET 4.0兼容:https://www.nuget.org/packages/jose-jwt/
您也可以到这里:https://jwt.io/然后单击“库”。
我找到了一个Json Web令牌的基本实现,并用Google风格对其进行了扩展。我还没有完全解决这个问题,但它已经达到了97%。这个项目失去了它的蒸汽,所以希望这将帮助其他人获得一个良好的开端:
注意:我对基本实现所做的更改(不记得是在哪里找到的)如下:
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;
}
}
然后是我谷歌特定的JWT类:
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);
}
}
我正在尝试使用mysql数据库用C#(我的第一个C#应用程序)开发一个小的用户-用户消息传递系统。 我知道最好的做法是使用类似EF的东西来处理数据库,但是我用“愚蠢”的方式来写这个只是为了熟悉语法。 我来自一个vb背景,所以我基本上只是转换我通常在vb中所做的,这就是为什么我不能理解为什么尽管在我的数据库中有一个匹配的行,DataReader返回时总是没有行。见下文: 上面的代码对照数据库检查用户
我正在尝试实现Spring Security和Angular JS教程中的OAuth2示例,但是在没有JWT的情况下,我遇到了一个问题。示例的代码可以在这里找到。 我对这个例子做了以下修改,试图让它在没有JWT的情况下工作。 /resource/src/main/resources/application。性质 注释了jwt keyValue的属性。 /ui/src/main/resources/
问题内容: 我用C语言编写“ hello world”程序 程序编译时显示警告为 这怎么可能?OS如何在不包含任何标题的情况下链接库? 问题答案: 编译器使用对称为的函数的引用来构建源文件, 而无需 知道其实际使用的参数或其返回类型是什么。生成的程序集在程序的静态数据区域中包含字符串地址的,后跟到。 将您的目标文件链接到可执行文件时,链接器会看到对它的引用并提供C标准库函数。通过 巧合 ,你传递的
下面的代码试图创建一个jwt令牌。每当它尝试执行SignatureAlgorithm SignatureAlgorithm=SignatureAlgorithm.hs256时,总会出现如下所示的错误; 我已经手动删除了jwt jar文件,并再次更新maven以重新安装jar,但问题仍然存在。 错误日志 POM依赖项
我试图遵循以下步骤: 带JPA的Spring靴 创建数据库并填充数据,但当应用程序结束时,数据将被删除。我尝试了各种事务解决方案。 如果我能得到一个完整的例子,我会非常充分。 当做 安德斯
类型参数不能用于在方法中实例化其对象。 public static <T> void add(Box<T> box) { //compiler error //Cannot instantiate the type T //T item = new T(); //box.add(item); } 要实现此类功能,请使用反射。 public static <T> voi