JWT和Web API(JwtAuthForWebAPI?) – 寻找一个例子

我有一个Angular前面的Web API项目,我想使用JWT令牌来保护它。 我已经进行了用户/通过validation,所以我认为我只需要实现JWT部分。

我相信我已经确定了JwtAuthForWebAPI所以使用它的一个例子会很棒。

我假设任何未使用[Authorize]修饰的方法都会像往常一样运行,并且如果客户端传递的令牌不匹配,则[Authorize]修饰的任何方法都将为401。

我还不知道如何在初始身份validation时将令牌发送回客户端。

我正在尝试使用魔术字符串开始,所以我有这个代码:

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

但我不确定最初是如何回到客户端的。 我想我理解如何在客户端上处理这个问题,但是如果你还可以展示这种交互的Angular方面,还可以获得奖励积分。

我最终不得不从几个不同的地方获取信息,以创建一个适合我的解决方案(实际上,生产可行的解决方案的开始 – 但它的工作原理!)

我摆脱了JwtAuthForWebAPI(尽管我从它那里借了一块来允许没有Authorization标头的请求流到没有[Authorize]保护的WebAPI Controller方法)。

相反,我正在使用Microsoft的JWT库(来自NuGet 的Microsoft .NET Framework的JSON Web令牌处理程序 )。

在我的身份validation方法中,在进行实际身份validation之后,我创建了令牌的字符串版本并将其与经过身份validation的名称(在这种情况下传递给我的用户名相同)和实际可能的角色一起传回在身份validation期间派生。

这是方法:

 [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 InMemorySymmetricSecurityKey(JwtTokenValidationHandler.SymmetricKey), "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 tokenString = tokenHandler.WriteToken(token); auth.Token = tokenString; auth.Authenticated = true; } return auth; } 

UPDATE

有一个关于在后续请求中处理令牌的问题。 我所做的是创建一个DelegatingHandler来尝试读取/解码令牌,然后创建一个Principal并将其设置为Thread.CurrentPrincipal和HttpContext.Current.User(您需要将其设置为两者)。 最后,我用适当的访问限制来装饰控制器方法。

这是DelegatingHandler的主要内容:

 private static bool TryRetrieveToken(HttpRequestMessage request, out string 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.Substring(7) : bearerToken; return true; } protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { HttpStatusCode statusCode; string token; var authHeader = request.Headers.Authorization; if (authHeader == null) { // missing authorization header return base.SendAsync(request, cancellationToken); } if (!TryRetrieveToken(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(SymmetricKey) }; 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)); } 

不要忘记将其添加到MessageHandlers管道中:

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

最后,装饰你的控制器方法:

 [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(); } 

我做了JwtAuthForWebAPI简单的实现,它的工作原理:)

使用JwtAuthForWebAPI的Web APi2身份validation不接受JWT令牌