問題描述
我有一個以 Angular 為前端的 Web API 項目,我想使用 JWT 令牌保護它.我已經進行了用戶/通行證驗證,所以我認為我只需要實現 JWT 部分.
I've got a Web API project fronted by Angular, and I want to secure it using a JWT token. I've already got user/pass validation happening, so I think i just need to implement the JWT part.
我相信我已經選擇了 JwtAuthForWebAPI,所以一個使用它的例子會很棒.
I believe I've settled on JwtAuthForWebAPI so an example using that would be great.
我假設任何沒有用 [Authorize] 修飾的方法都會像往常一樣運行,并且如果客戶端傳遞的令牌不匹配,任何用 [Authorize] 修飾的方法都會 401.
I assume any method not decorated with [Authorize] will behave as it always does, and that any method decorated with [Authorize] will 401 if the token passed by the client doesn't match.
我還不知道如何在初始身份驗證時將令牌發送回客戶端.
What I can't yet figure out it how to send the token back to the client upon initial authentication.
我試圖只使用一個魔術字符串開始,所以我有這個代碼:
I'm trying to just use a magic string to begin, so I have this code:
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 方面,那么我會加分.
But I'm not sure how that gets back to the client initially. I think I understand how to handle this on the client, but bonus points if you can also show the Angular side of this interaction.
推薦答案
我最終不得不從幾個不同的地方獲取信息來創建一個適合我的解決方案(實際上,生產可行解決方案的開始 -但它有效!)
I ended-up having to take a information from several different places to create a solution that works for me (in reality, the beginnings of a production viable solution - but it works!)
我擺脫了 JwtAuthForWebAPI (盡管我確實從中借了一件,以允許沒有授權標頭的請求流向不受 [Authorize] 保護的 WebAPI 控制器方法).
I got rid of JwtAuthForWebAPI (though I did borrow one piece from it to allow requests with no Authorization header to flow through to WebAPI Controller methods not guarded by [Authorize]).
相反,我使用的是 Microsoft 的 JWT 庫 (Microsoft 的 JSON Web 令牌處理程序.NET 框架 - 來自 NuGet).
Instead I'm using Microsoft's JWT Library (JSON Web Token Handler for the Microsoft .NET Framework - from NuGet).
在我的身份驗證方法中,在進行實際身份驗證后,我創建了令牌的字符串版本,并將其與經過身份驗證的名稱(在這種情況下傳遞給我的用戶名相同)和一個角色一起傳回,實際上, 可能是在身份驗證期間派生的.
In my authentication method, after doing the actual authentication, I create the string version of the token and pass it back along with the authenticated name (the same username passed into me, in this case) and a role which, in reality, would likely be derived during authentication.
方法如下:
[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;
}
更新
有一個關于在后續請求中處理令牌的問題.我所做的是創建一個 DelegatingHandler 來嘗試讀取/解碼令牌,然后創建一個 Principal 并將其設置為 Thread.CurrentPrincipal 和 HttpContext.Current.User (您需要將其設置為兩者).最后,我用適當的訪問限制來裝飾控制器方法.
There was a question about handling the token on subsequent requests. What I did was create a DelegatingHandler to try and read/decode the token, then create a Principal and set it into Thread.CurrentPrincipal and HttpContext.Current.User (you need to set it into both). Finally, I decorate the controller methods with the appropriate access restrictions.
這是 DelegatingHandler 的主要內容:
Here's the meat of the DelegatingHandler:
private static bool TryRetrieveToken(HttpRequestMessage request, out string token)
{
token = null;
IEnumerable<string> 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<HttpResponseMessage> 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<HttpResponseMessage>.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<HttpResponseMessage>.Factory.StartNew(() => new HttpResponseMessage(statusCode));
}
不要忘記將其添加到 MessageHandlers 管道中:
Don't forget to add it into the MessageHandlers pipeline:
public static void Start()
{
GlobalConfiguration.Configuration.MessageHandlers.Add(new JwtTokenValidationHandler());
}
最后,裝飾你的控制器方法:
Finally, decorate your controller methods:
[Authorize(Roles = "OneRoleHere")]
[GET("/api/admin/settings/product/allorgs")]
[HttpGet]
public List<Org> GetAllOrganizations()
{
return QueryableDependencies.GetMergedOrganizations().ToList();
}
[Authorize(Roles = "ADifferentRoleHere")]
[GET("/api/admin/settings/product/allorgswithapproval")]
[HttpGet]
public List<ApprovableOrg> GetAllOrganizationsWithApproval()
{
return QueryableDependencies.GetMergedOrganizationsWithApproval().ToList();
}
這篇關于JWT 和 Web API (JwtAuthForWebAPI?) - 尋找示例的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!