我記得我最早在 2008 年就因為一個標案串接過 e 政府服務平臺的單一登入機制,事隔多年後,竟然什麼也沒有變,還是一樣透過 SOAP Web Service 來進行驗證。今天這篇文章我就來說說如何透過 .NET 7 實作 e 政府服務平臺的單一簽入機制,以及說明如何用 .NET 呼叫以 SOAP 為基礎的 Web Service 服務。
大致整合步驟
關於單一登入暨多因子驗證的相關文件,可以參考這裡:https://www.gsp.gov.tw/index-download-2.htm
基本上要完成單一簽入機制,只需要以下幾個步驟:
-
組成一個單一簽入網址,將使用者導向至 e 政府服務平臺單一登入網頁
網址結構如下:
https://www.cp.gov.tw/portal/Clogin.aspx?ReturnUrl={回呼網址}&level={驗證等級}
注意: 這裡的 回呼網址 不能隨便填寫,在 e 政府服務平台會做域名驗證,你必須在機關單位申請單一簽入時就要指定好,未指定的網址將無法完成單一簽入作業。這裡只會驗證 Hostname
(域名) 部分,不會驗證 Scheme
或 Port
或 Pathinfo
等部分。
我是這樣實作的:
void Main()
{
var url = GetLoginUrl("https://mysite.com.tw/callback", AuthLevel.帳號登入);
//var url = GetLoginUrl("https://mysite.com.tw/callback", LoginType.憑證登入);
}
public string GetLoginUrl(string returnUrl, AuthLevel level)
{
var loginUrl = "https://www.cp.gov.tw/portal/Clogin.aspx";
// 需安裝 Microsoft.AspNetCore.Http.Extensions 套件
var qb = new QueryBuilder();
qb.Add("ReturnUrl", returnUrl);
qb.Add("level", level.ToString("D"));
return $"{loginUrl}{qb.ToQueryString().Value}";
}
public enum AuthLevel
{
帳號登入 = 1,
憑證登入 = 2
}
-
使用者登入成功後,會透過 HTTP POST 回到 ReturnUrl
指定的網址,你要透過 application/x-www-form-urlencoded
的方式取得 twGovT1
傳入欄位的值。
以下我用 ASP.NET Core 7 Minimal API 的語法示範如何取得 twGovT1
欄位的值 (也就是所謂的 Token1
值):
app.MapPost("/callback", async Task<string> (HttpRequest request) =>
{
var formData = await request.ReadFormAsync();
var formDataDictionary = formData.ToDictionary(x => x.Key, x => x.Value.ToString());
return formDataDictionary["twGovT1"];
})
注意: 直到 ASP.NET Core 7.0 的 Minimal API 都還沒有支援 [FromForm]
的繫結方式,必須等 ASP.NET Core 8.0 才開始有支援 Binding to forms。
-
取得 Token1 之後,還要呼叫一個以 SOAP 為主的 Web Service,取得使用者基本資料,這才算完成單一簽入流程。
這個步驟稍微複雜些,我將在下一小節說明。
注意: 由於 ServiceID
必須要透過機關單位申請後才能取得,而且該 Web Service 在呼叫時會驗證指定的來源 IP 地址,若申請單一簽入時沒有申請到正確的 IP 地址,將無法正確的呼叫該 Web 服務。
如何透過 .NET 呼叫以 SOAP 為主的 Web Service
其實你要撰寫 SOAP 的 Client 端,透過 Visual Studio 2022 其實蠻容易的,大致步驟如下:
-
開啟 Connected Service 視窗
-
點擊 Add a service reference
-
選擇 WCF Web Service
-
輸入 URI ( e 政府服務平臺的單一登入機制的 Web Service 網址為 https://www.cp.gov.tw/gsp2ws/rsmediator01.asmx )
-
查看 Web Service 內容,並按下 Next 進入下一步
-
按下 Next 進入下一步
-
按下 Finish 完成
-
按下 Close 關閉對話框
-
完成後會自動產生一個 Connected Services\ServiceReference1\Reference.cs
檔案
如果不用 Visual Studio 2022 的話,就要透過 dotnet-svcutil 全域工具來快速產生程式碼:
-
安裝全域工具
dotnet tool install --global dotnet-svcutil
-
產生參考類別
dotnet svcutil https://www.cp.gov.tw/gsp2ws/rsmediator01.asmx
這個命令會產生 ServiceReference\Reference.cs
程式碼內容,其內容跟 Visual Studio 2022 產生的程式碼一樣。
-
將 ServiceReference\Reference.cs
程式碼複製到你的專案下即可!
當我們擁有了 SOAP 的 Client 函式庫,剩下的就很簡單了,要呼叫 Web Service 只需要以下幾個步驟:
-
建立 Web Service 的 Client 實例
var client = new GSP2_RS_Service_01SoapClient(GSP2_RS_Service_01SoapClient.EndpointConfiguration.GSP2_RS_Service_01Soap);
-
呼叫並傳入 AuthHeader
參數
var result = await client.GetProfileColumns2Async(new AuthHeader()
{
ServiceID = "APP0000001",
Token1 = "7c2232c2ca3a4a002fc4127d4c2ca8a9"
});
-
判斷是否有成功取得使用者基本資料
if (result.GetProfileColumns2Result.Code == 0)
{
Console.WriteLine("成功取得個人資料");
}
相關連結