Swagger UI 上方有一個 api_key,這次我要利用他加上 JWT 來驗證
開發環境
- VS 2017 Enterprise 15.9.5
- Swashbuckle 5.6.0
續上篇 [Swagger] 使用 Basic Auth 測試受保護的 Web API
實作步驟
這裡我寫了一個 JWT 的授權方式,可以參考之前的文章了解甚麼是 JWT
https://dotblogs.com.tw/yc421206/2019/01/07/what_is_jwt
https://dotblogs.com.tw/yc421206/2019/01/07/authentication_via_jwt-dotnet
https://dotblogs.com.tw/yc421206/2019/01/08/authentication_via_ms_system_identitymodel_tokens_jwt
public class JwtAuthorizeAttribute : AuthorizeAttribute { public override async Task OnAuthorizationAsync(HttpActionContext actionContext, CancellationToken cancellationToken) { var authorization = actionContext.Request.Headers.Authorization; if (authorization != null && authorization.Scheme.ToLower() == "bearer") { var token = authorization.Parameter; if (JwtManager.TryValidateToken(token, out var principal)) { Thread.CurrentPrincipal = principal; if (HttpContext.Current != null) { HttpContext.Current.User = principal; } actionContext.Request.GetRequestContext().Principal = principal; } } await base.OnAuthorizationAsync(actionContext, cancellationToken); } }
全域套用
config.Filters.Add(new JwtAuthorizeAttribute());
頒發 JWT
[AllowAnonymous] public IHttpActionResult Post(LoginData loginData) { if (this.CheckUser(loginData.UserName, loginData.Password)) { var token = JwtManager.GenerateToken(loginData.UserName); return new ResponseMessageResult(new HttpResponseMessage { StatusCode = HttpStatusCode.OK, Content = new StringContent(token, Encoding.UTF8) }); } throw new HttpResponseException(HttpStatusCode.Unauthorized); }
Swagger UI
@ SwaggerConfig.cs
把這一段解開,apiKey 是 header name
c.EnableApiKeySupport("apiKey", "header");
server 的驗證 header name 是 Authorization,所以我把 apiKey 改成 Authorization
c.EnableApiKeySupport("Authorization", "header");
然後 api_key 輸入 jwt,再訪問受保護的資源
OperationFilter
除了使用可以用上方的 API Key 之外,我們也可以像上篇那樣,為每一個 Action 加上授權圖示
@ SwaggerConfig.cs
把這一段解開,我解釋一下這個屬性,這是用來訂定授權的 UI
c.ApiKey("apiKey") .Description("API Key Authentication") .Name("apiKey") .In("header");
- ApiKey:apiKey 的 name ,隨便取
- Name:header name,這要跟 server 配合
- In:當然就是用 header 把 key 傳給 server
授權的 header 叫 Authorization,所以我把他換掉
c.ApiKey("apiKey") .Description("Standard Authorization header using the Bearer scheme. Example: \"bearer {token}\"") .Name("Authorization") .In("header");
完成之後會長這個樣子
@ SwaggerAuthorizeOperationFilter.cs
c.ApiKey 需要實作 OperationFilter,且要對應到 apiKey name,代表這個 Action 要用這個授權,可以是一個或多個
public class SwaggerAuthorizeOperationFilter : IOperationFilter { public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription) { var filterPipeline = apiDescription.ActionDescriptor.GetFilterPipeline(); // check if authorization is required var isAuthorized = filterPipeline .Select(filterInfo => filterInfo.Instance) .Any(filter => filter is IAuthorizationFilter); // check if anonymous access is allowed var allowAnonymous = apiDescription.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any(); if (isAuthorized && !allowAnonymous) { if (operation.security == null) { operation.security = new List<IDictionary<string, IEnumerable<string>>>(); } var auth = new Dictionary<string, IEnumerable<string>> { {"apiKey", Enumerable.Empty<string>()}, //{"basic", Enumerable.Empty<string>()} }; operation.security.Add(auth); } } }
@ SwaggerConfig.cs
套用
c.OperationFilter<SwaggerAuthorizeOperationFilter>();
執行結果如下圖:
啟用此功能 Swagger 上方的 ApiKey 工具列就失效了
專案位置
https://github.com/yaochangyu/sample.dotblog/tree/master/WebAPI/Swagger/JWT%20Authorization
若有謬誤,煩請告知,新手發帖請多包涵
Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2022 .NET