現在軟體開發使用 API 架構的設計越來越常見了,針對現有或遺留的舊有 API 可以夠過 Azure API Management 來管理,可以快速的加入驗證或是把 API 變成 Paas 服務,可以設計產品套組和不同訂閱,也提供使用者一個開發者介面,可以申請帳號和測試 API,這次針對沒有驗證的 API 來實做套用驗證。
前言
現在軟體開發使用 API 架構的設計越來越常見了,針對現有或遺留的舊有 API 可以夠過 Azure API Management 來管理,可以快速的加入驗證或是把 API 變成 Paas 服務,可以設計產品套組和不同訂閱,也提供使用者一個開發者介面,可以申請帳號和測試 API,這次針對沒有驗證的 API 來實做套用驗證。
實做
建立 API Management 服務
在 Azure Portal 點選建立資源,搜尋 API 管理或 API Management ,可以找到如下的服務,即是這次的主角服務。
針對比較重要的定價層特別說明幾個點:
- Developer 沒有 SLA
- Consumption 不支援 Scale 和開發者網站也無法切換成其它定價層
另外還有一件重要的點就是建置過程約需 30 分鐘,點選建立之後需要一點時間。
新增 API
這邊用一個微軟 Host 的 Demo Conference API 服務來示範新增 API
在服務的左邊選單找到 API -> Add Api -> OpenAPI
在 OpenAPI specification 輸入 https://conferenceapi.azurewebsites.net/ ,稍待一會就會自動抓取資訊填入下面的欄位。
建立之後就可以看到 API 已經被匯入了。
新增 API 驗證
再來針對這一個沒有做授權驗證的 API 來新增驗證上去。
首先新增個一個驗證用的 API 程式碼非常的簡單,新增一個 AuthController 取得 Header 中的 Authorization 當作結果的 status 參數回傳。這邊可以改成大家自己的驗證邏輯,取得驗證的 Token 和資料庫資料比對等等。
[Route("api/[controller]")]
[ApiController]
public class AuthController : ControllerBase
{
public IActionResult Get()
{
var status = Request.Headers["Authorization"].ToString();
return new JsonResult(new { status = status });
}
}
針對 Inbound 新增 Policy,這邊直接點選原則編輯器。
參考官方的 外部授權範例內的程式碼,貼到原則編輯器內。然後將 {{authorizer-url}} 取代成我們自己的驗證網址。底下範例稍微解釋一下,是針對 API 的 Header 取出 Authorization ,將他當作參數一樣放到 Header 之後去呼叫我們設定的驗證網址,取得驗證結果的 Json 判斷回應的 status 欄位看驗證的狀態是否是授權通過的。如果 status 等於 403 API Management 也會回傳 403 授權失敗。
<policies>
<inbound>
<base/>
<!-- Ensure presence of Authorization header -->
<choose>
<when condition="@(!context.Request.Headers.ContainsKey("Authorization"))">
<return-response>
<set-status code="401" reason="Unauthorized" />
<set-header name="WWW-Authenticate" exists-action="append">
<value>@("Bearer realm="+context.Request.OriginalUrl.Host)</value>
</set-header>
</return-response>
</when>
</choose>
<!-- Check for cached authorization status for the subject -->
<cache-lookup-value key="@(context.Request.Headers.GetValueOrDefault("Authorization"))" variable-name="status"/>
<choose>
<!--
If a cache miss call external authorizer
-->
<when condition="@(!context.Variables.ContainsKey("status"))">
<!-- Invoke -->
<send-request mode="new" response-variable-name="response" timeout="10" ignore-error="false">
<set-url>{{authorizer-url}}</set-url>
<set-method>GET</set-method>
<set-header name="Authorization" exists-action="override">
<value>@(context.Request.Headers.GetValueOrDefault("Authorization"))</value>
</set-header>
</send-request>
<!-- Extract authorization status from authorizer's response -->
<set-variable name="status" value="@(((IResponse)context.Variables["response"]).Body.As<JObject>()["status"].ToString())"/>
<!-- Cache authorization result -->
<cache-store-value key="@(context.Request.Headers.GetValueOrDefault("Authorization"))" value="@((string)context.Variables["status"])" duration="5"/>
</when>
</choose>
<!-- Authorize the request -->
<choose>
<when condition="@((string)context.Variables["status"] == "403")">
<return-response>
<set-status code="403" reason="Forbidden" />
</return-response>
</when>
</choose>
</inbound>
<backend>
<base/>
</backend>
<outbound>
<base/>
</outbound>
</policies>
測試
在沒有任何驗證資訊的時候會得到 401 的回應。
這邊輸入 200 模擬驗證成功,就可以正確的取得 API 結果。
再來模擬 403 驗證失敗,可以如預期的得到 403 Forbidden。
結論
API Management 還有很多實用的功能,在時間不允許且預算允許下,可以很快幫現有 API 加上許多的功能,也可以將 API 藏在 API Management 之後。透過 API Management 還可以設定使用者連線的次數,或是將不同的 API 整合成一個方案,方便針對不同使用者提供不同方案,和限制呼叫 API 的限制,這些都不需要在額外花時間開發了。