JWT et Web API (JwtAuthForWebAPI?) – Recherche d’un exemple

J’ai un projet d’API Web dirigé par Angular et je souhaite le sécuriser à l’aide d’un jeton JWT. J’ai déjà la validation utilisateur / passe en cours, donc je pense que je dois juste implémenter la partie JWT.

Je crois avoir choisi JwtAuthForWebAPI, un exemple d’utilisation serait donc formidable.

Je suppose que toute méthode non décorée avec [Autoriser] se comportera comme toujours et que toute méthode décorée avec [Autoriser] 401 si le jeton transmis par le client ne correspond pas.

Ce que je n’arrive pas encore à comprendre, c’est comment renvoyer le jeton au client lors de l’authentification initiale.

J’essaie juste d’utiliser une chaîne magique pour commencer, alors j’ai ce code:

RegisterRoutes(GlobalConfiguration.Configuration.Routes); var builder = new SecurityTokenBuilder(); var jwtHandler = new JwtAuthenticationMessageHandler { AllowedAudience = "http://xxxx.com", Issuer = "corp", SigningToken = builder.CreateFromKey(Convert.ToBase64Ssortingng(new byte[]{4,2,2,6})) }; GlobalConfiguration.Configuration.MessageHandlers.Add(jwtHandler); 

Mais je ne sais pas comment cela revient au client au départ. Je pense que je comprends comment gérer cela sur le client, mais des points bonus si vous pouvez également montrer le côté angular de cette interaction.

J’ai fini par avoir à prendre des informations de plusieurs endroits différents pour créer une solution qui fonctionne pour moi (en réalité, les débuts d’une solution de production viable – mais cela fonctionne!)

Je me suis débarrassé de JwtAuthForWebAPI (bien que j’en ai emprunté un morceau pour permettre aux demandes sans en-tête Authorization de passer aux méthodes du contrôleur WebAPI non protégées par [Authorize]).

J’utilise plutôt la bibliothèque JWT de Microsoft ( gestionnaire de jetons Web JSON pour Microsoft .NET Framework – de NuGet).

Dans ma méthode d’authentification, après avoir effectué l’authentification proprement dite, je crée la version chaîne du jeton et le renvoie avec le nom authentifié (le même nom d’utilisateur m’a été transmis, dans ce cas) et un rôle qui, en réalité, risquerait être dérivé lors de l’authentification.

Voici la méthode:

 [HttpPost] public LoginResult PostSignIn([FromBody] Credentials credentials) { var auth = new LoginResult() { Authenticated = false }; if (TryLogon(credentials.UserName, credentials.Password)) { var tokenDescriptor = new SecurityTokenDescriptor { Subject = new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, credentials.UserName), new Claim(ClaimTypes.Role, "Admin") }), AppliesToAddress = ConfigurationManager.AppSettings["JwtAllowedAudience"], TokenIssuerName = ConfigurationManager.AppSettings["JwtValidIssuer"], SigningCredentials = new SigningCredentials(new InMemorySymmesortingcSecurityKey(JwtTokenValidationHandler.SymmesortingcKey), "http://www.w3.org/2001/04/xmldsig-more#hmac-sha256", "http://www.w3.org/2001/04/xmlenc#sha256") }; var tokenHandler = new JwtSecurityTokenHandler(); var token = tokenHandler.CreateToken(tokenDescriptor); var tokenSsortingng = tokenHandler.WriteToken(token); auth.Token = tokenSsortingng; auth.Authenticated = true; } return auth; } 

METTRE À JOUR

Il y avait une question sur la gestion du jeton sur les demandes suivantes. Ce que j’ai fait était de créer un DelegatingHandler pour essayer de lire / décoder le jeton, puis de créer un principal et de le définir dans Thread.CurrentPrincipal et HttpContext.Current.User (vous devez le définir dans les deux). Enfin, je décore les méthodes du contrôleur avec les ressortingctions d’access appropriées.

Voici la viande du DelegatingHandler:

 private static bool TryResortingeveToken(HttpRequestMessage request, out ssortingng token) { token = null; IEnumerable authzHeaders; if (!request.Headers.TryGetValues("Authorization", out authzHeaders) || authzHeaders.Count() > 1) { return false; } var bearerToken = authzHeaders.ElementAt(0); token = bearerToken.StartsWith("Bearer ") ? bearerToken.Subssortingng(7) : bearerToken; return true; } protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { HttpStatusCode statusCode; ssortingng token; var authHeader = request.Headers.Authorization; if (authHeader == null) { // missing authorization header return base.SendAsync(request, cancellationToken); } if (!TryResortingeveToken(request, out token)) { statusCode = HttpStatusCode.Unauthorized; return Task.Factory.StartNew(() => new HttpResponseMessage(statusCode)); } try { JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler(); TokenValidationParameters validationParameters = new TokenValidationParameters() { AllowedAudience = ConfigurationManager.AppSettings["JwtAllowedAudience"], ValidIssuer = ConfigurationManager.AppSettings["JwtValidIssuer"], SigningToken = new BinarySecretSecurityToken(SymmesortingcKey) }; IPrincipal principal = tokenHandler.ValidateToken(token, validationParameters); Thread.CurrentPrincipal = principal; HttpContext.Current.User = principal; return base.SendAsync(request, cancellationToken); } catch (SecurityTokenValidationException e) { statusCode = HttpStatusCode.Unauthorized; } catch (Exception) { statusCode = HttpStatusCode.InternalServerError; } return Task.Factory.StartNew(() => new HttpResponseMessage(statusCode)); } 

N’oubliez pas de l’append au pipeline MessageHandlers:

 public static void Start() { GlobalConfiguration.Configuration.MessageHandlers.Add(new JwtTokenValidationHandler()); } 

Enfin, décorez vos méthodes de contrôleur:

 [Authorize(Roles = "OneRoleHere")] [GET("/api/admin/settings/product/allorgs")] [HttpGet] public List GetAllOrganizations() { return QueryableDependencies.GetMergedOrganizations().ToList(); } [Authorize(Roles = "ADifferentRoleHere")] [GET("/api/admin/settings/product/allorgswithapproval")] [HttpGet] public List GetAllOrganizationsWithApproval() { return QueryableDependencies.GetMergedOrganizationsWithApproval().ToList(); } 

J’ai fait JwtAuthForWebAPI simple implémentation et ça marche 🙂

Jeton JWT non accepté par l’authentification Web APi2 avec JwtAuthForWebAPI