Есть ли пример JSON Web Token (JWT) в C#?
Я чувствую, что я принимаю сумасшедшие таблетки здесь. Обычно всегда есть миллион библиотек и образцов, плавающих по сети для любой заданной задачи. Я пытаюсь реализовать аутентификацию с помощью "учетной записи службы" Google с помощью веб-токенов JSON (JWT), как описано здесь.
однако есть только клиентские библиотеки в PHP, Python и Java. Даже поиск примеров JWT вне аутентификации Google, есть только сверчки и черновики на концепции JWT. Есть это действительно так новая и, возможно, проприетарная система Google?
образец java, который ближе всего мне удалось интерпретировать, выглядит довольно интенсивным и пугающим. Там должно быть что-то в C#, с чего я мог бы, по крайней мере, начать. Любая помощь с этим будет здорово!
6 ответов:
спасибо всем. Я нашел базовую реализацию веб-токена Json и расширил ее с помощью Google flavor. Я до сих пор не получил его полностью разработан, но это 97% там. Этот проект потерял свой steam, поэтому, надеюсь, это поможет кому-то еще получить хороший старт:
Примечание.: Изменения, которые я внес в базовую реализацию (не могу вспомнить, где я ее нашел):
- изменен HS256 - > RS256
- поменял порядок JWT и alg в заголовке. Не уверен, кто ошибся, Google или спецификация, но google принимает это так, как это показано ниже в соответствии с их документами.
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; } }а затем мой google конкретный класс 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); } }
после того, как все эти месяцы прошли после первоначального вопроса, теперь стоит отметить, что Microsoft разработала собственное решение. См.http://blogs.msdn.com/b/vbertocci/archive/2012/11/20/introducing-the-developer-preview-of-the-json-web-token-handler-for-the-microsoft-net-framework-4-5.aspx подробнее.
Я никогда не использовал его, но есть реализация JWT на NuGet.
пакет:https://nuget.org/packages/JWT
Источник:https://github.com/johnsheehan/jwt
совместимость с .NET 4.0:https://www.nuget.org/packages/jose-jwt/
вы также можете пойти сюда:https://jwt.io/ и нажмите кнопку "библиотеки".
вот пример:
http://zavitax.wordpress.com/2012/12/17/logging-in-with-google-service-account-in-c-jwt/
потребовалось довольно много времени, чтобы собрать части, разбросанные по сети, документы довольно неполные...
Это моя реализация (Google) проверки JWT в .NET. Он основан на других реализациях на 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<>метод.
посмотри клиентская библиотека Google для .NET.
Comments