[Swagger] 使用 Api_Key + JWT 測試受保護的 Web API

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<stringIEnumerable<string>>>();
            }
 
            var auth = new Dictionary<stringIEnumerable<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

Image result for microsoft+mvp+logo