讓 swagger 可以使用 IdentityServer 4 的測試驗證

IdentityServer 4 提供線上可以測試的網址: https://demo.identityserver.io 可以讓專案直接連上進行測試。以下採用 Swashbuckle.AspNetCore 範例說明。

首先,nuget 安裝 IdentityServer4.AccessTokenValidation & Swashbuckle.AspNetCore  因為設定的 web api 只使用 Access token 作為驗證的工具,因此不需要安裝整套 IdentityServer

IdentityServer 4 deom site:主要使用 implicit, api scope:

設定 WebAPI 使用 Identity Server Token
1. 註冊 Identity Server Authentication library in ConfigureService:

  services.AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)
    .AddIdentityServerAuthentication(options =>
    {
        options.Authority = "https://demo.identityserver.io";
        options.ApiName = "api";
    });

2.設定 Swagger 產生時候,加入 Oauth 的設定 in ConfigureService:

  services.AddSwaggerGen(s =>
{
    s.SwaggerDoc("v1", new Info { Title = "Test WebAPI", Version = "V1" });
    s.AddSecurityDefinition("oauth2", new OAuth2Scheme
    {
        Flow = "implicit",
        AuthorizationUrl = "https://demo.identityserver.io/connect/authorize",
        Scopes = new Dictionary<string, string> { { "api", "Access to the api" } }
    });
});

透過指定 identityserver 認證,將頁面導入 demo site,其中 flow & scope 對應前面設定的 client_id 的對應項目。

3.按下【Authorize】時候就會出現以下畫面,填寫之前指定的 client_id: implicit 即可導入登入頁面

輸入 demo site 上指定的使用者帳號:bob/bob 就完成登入:

4. swagger 設定 endpoint 需要認證,同時設定 Authorize 的錯誤 401, 403 回應。這裡透過實作 IOperationFilter & 加入 AddSwaggerGen:

public class AuthorizeCheckOperationFilter : IOperationFilter
{
    public void Apply(Operation operation, OperationFilterContext context)
    {
        var authAttrs = context.MethodInfo.DeclaringType.GetCustomAttributes(true)
            .Union(context.MethodInfo.GetCustomAttributes(true))
            .OfType<AuthorizeAttribute>();
 
        if (authAttrs.Any())
        {
            operation.Responses.Add("401", new Response { Description = "尚未被授權存取" });
            operation.Responses.Add("403", new Response { Description = "網頁禁止被存取" });
            operation.Security = new List<IDictionary<string, IEnumerable<string>>>
            {
                new Dictionary<string, IEnumerable<string>>{{"oauth2", new [] {"api"}}}
            };
        }
    }
}

簡單說明就是會將所有的介面檢查是否具備 Authorize Attribute,如果有,則加入 security 接受 access token: oauth2 與 api scope
在 AddSwaggerGen 加入:

s.OperationFilter<AuthorizeCheckOperationFilter>();

如此,當呼叫 swagger 頁面時候,就會出現以下錯誤:

最後在 Configure 中,設定 app 加入處理 swagger UI 的 middleware:

  // Enable Middleware to serve generated Swagger as a JSON endpoint.
app.UseSwagger();
 
// Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.),
// Specifying the Swagger JSON endpoint
app.UseSwaggerUI(s =>
{
    s.SwaggerEndpoint("/swagger/v1/swagger.json", "Rabbit framework WebAPI");
    s.OAuthClientId("implicit");
    s.OAuthAppName("Rabbit framework WebAPI");
});

參考文章:ASP.NET Core Swagger UI Authorization using IdentityServer4

angular 前端直接使用 xlxs 將資料直接轉換成 Excel

套件網址: https://github.com/SheetJS/js-xlsx/tree/19620da30be2a7d7b9801938a0b9b1fd3c4c4b00/demos/angular2
使用方式:

import { WorkBook, utils, writeFile, WorkSheet } from 'xlsx';

table = [
  {
    First: 'one',
    Second: 'two',
    Third: 'three',
    Forth: 'four',
    Fifth: 'five'
  },
  {
    First: 'un',
    Second: 'deux',
    Third: 'trois',
    Forth: 'quatre',
    Fifth: 'cinq'
  },
];
onClick() {
  const json = this.replaceHeader(this.table);
  /* generate worksheet */
  // const ws: WorkSheet = utils.json_to_sheet(json);
  const ws: WorkSheet = utils.aoa_to_sheet(this.setupAoa(this.table));
  /* generate workbook and add the worksheet */
  const wb: WorkBook = utils.book_new();
  utils.book_append_sheet(wb, ws, 'Sheet1');
  /* save to file */
  writeFile(wb, 'SheetJS.xlsx');
}
private setupAoa(table) {
  var jsonArray = [];
  jsonArray.push(["This is a Ttile"]);
  jsonArray.push(["第一", "第二", "第三", "第四", "第五"]);
  for(var i = 0; i < this.table.length; i++) {
    jsonArray.push([this.table[i].First, this.table[i].Second, this.table[i].Third, this.table[i].Forth, this.table[i].Fifth]);
  }
  return jsonArray;
}

其中 aoa_to_sheet 可以透過二維陣列對應 Excel 表格的內容(另外也可以使用 json_to_sheet,不過要自行加入表頭設定就比較困難)