una tutorial segura parte net jsonwebtoken from example construyendo con c# oauth oauth-2.0 jwt

c# - tutorial - jwt php



¿Hay algún ejemplo de JSON Web Token(JWT) en C#? (6)

Aquí hay un ejemplo de trabajo:

http://zavitax.wordpress.com/2012/12/17/logging-in-with-google-service-account-in-c-jwt/

Tomó bastante tiempo recoger las piezas esparcidas por la web, los documentos son bastante incompletos ...

Siento que estoy tomando pastillas locas aquí. Por lo general, siempre hay un millón de bibliotecas y muestras flotando en la web para cualquier tarea determinada. Estoy intentando implementar la autenticación con una "Cuenta de servicio" de Google mediante el uso de JSON Web Tokens (JWT) como se describe here .

Sin embargo, solo hay bibliotecas cliente en PHP, Python y Java. Incluso buscando ejemplos JWT fuera de la autenticación de Google, solo hay grillos y borradores en el concepto JWT. ¿Es esto realmente nuevo y posiblemente un sistema propietario de Google?

La muestra de Java que es lo más cerca que pude interpretar parece bastante intensa e intimidante. Tiene que haber algo en C # con el que al menos pueda empezar. ¡Cualquier ayuda con esto sería genial!




Esta es mi implementación de (Google) JWT Validation en .NET. Se basa en otras implementaciones en y 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; } } }

Tenga en cuenta que, para usarlo, necesita agregar una referencia al paquete NuGet System.Net.Http.Formatting.Extension . Sin esto, el compilador no reconocerá el método ReadAsAsync<> .


Gracias a todos. Encontré una implementación básica de un Json Web Token y lo amplié con el sabor de Google. Todavía no lo he trabajado del todo, pero está en un 97%. Este proyecto perdió su fuerza, así que con suerte esto ayudará a alguien más a tener una buena ventaja:

Nota: Los cambios que realicé en la implementación base (No recuerdo dónde la encontré) son:

  1. Cambió HS256 -> RS256
  2. Cambió el orden JWT y alg en el encabezado. No estoy seguro de quién lo entendió mal, Google o la especificación, pero google lo toma de la manera que se muestra a continuación según sus documentos.

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; } }

Y luego mi clase específica de 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); } }