IIS 整合式 Windows 驗證之極簡風 SSO 整合
4 |
遇到特殊 SSO 整合需求,在 Windows 上執行的第三方網站服務,登入部分允許客製但不支援整合式 Windows 驗證,如何借用 IIS 的整合式 Windows 簡單實現 SSO 整合呢?
我做了一個超精簡版本,只需一個資料夾三個檔案(sso.aspx、validate.aspx、web.config)搞定。
運作流程如下:
- 使用者以 Windows/AD 帳號登入 sso.aspx
- sso.aspx 取得使用者帳號,將其存入 Cache 並隨機產生對映 GUID
- sso.aspx 將瀏覽器重新導向第三方網站網址並加上「?t=對映GUID」參數
- 第三方網站取出對映 GUID 呼叫 validate.aspx 進行驗證
- validate.aspx 依對映 GUID 從 Cache 取出使用者帳號回傳給第三方網站,並將資料自 Cache 清除防止重複使用
- 第三方網站由 validate.aspx 取得使用者帳號資訊,切換登入身分
這裡有個眉角,sso.aspx 需啟用整合式 Windows 驗證以取得使用者帳號,而 validate.aspx 屬 WebAPI 性質需開放匿名存取,故 IIS 必須「同時」開放匿名驗證及Windows驗證(參考:在 Windows 驗證網站設定部分匿名存取),並從 web.config 設定:
<configuration>
<appSettings>
<add key="RedirectUrl" value="http://localhost/AspNet/TinySso/test.aspx" />
</appSettings>
<location path="sso.aspx">
<system.web>
<authorization>
<deny users="?" />
</authorization>
</system.web>
</location>
<location path="validate.aspx">
<system.web>
<authorization>
<allow users="*" />
</authorization>
</system.web>
</location>
</configuration>
以下是 sso.aspx 程式。邏輯很單純,由 Request.LogonUserIdentity.Name 取得登入者帳號,產生 GUID 為 Key 存入 Cache,導向 appSetting 所指定的 URL 並附上 GUID 參數。
<%@ Page Language="C#"%>
<script runat="server">
void Page_Load(object sender, EventArgs e)
{
var ssoRedirect = System.Configuration.ConfigurationManager.AppSettings["RedirectUrl"];
var token = Guid.NewGuid().ToString();
Cache.Add(token, Request.LogonUserIdentity.Name, null, DateTime.Now.AddSeconds(30),
Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.High, null);
Response.Redirect(ssoRedirect + "?t=" + token);
}
</script>
validate.aspx 程式也很簡單,依據 GUID 從 Cache 取出帳號資訊回傳,帳號資訊讀取後立即從 Cache 清除,避免 GUID 被拿來多次登入。另外,它限定本機存取及 POST 方法,減少被誤用風險。
<%@ Page Language="C#"%>
<script runat="server">
void Page_Load(object sender, EventArgs e)
{
var identity = "";
if (Request.HttpMethod == "POST")
{
var token = Request["t"];
if (!string.IsNullOrEmpty(token) && Request.IsLocal)
{
identity = (string)Cache[token];
if (identity != null) Cache.Remove(token);
}
}
Response.Write(identity);
}
</script>
至於第三方網站要怎麼做,我用一支 test.aspx 示範:
<%@ Page Language="C#"%>
<script runat="server">
void Page_Load(object sender, EventArgs e)
{
var tinySsoCheck = "http://localhost/aspnet/tinysso/validate.aspx";
var token = Request["t"];
var identity = new System.Net.WebClient().UploadString(tinySsoCheck + "?t=" + token, "");
if (!string.IsNullOrEmpty(identity))
Response.Write("Welcome, " + identity.Split('\\').Last());
else
Response.Write("Unkown User");
}
</script>
測試成功。
不過,test.aspx 自己就能做整合式 Windows 驗證了,測起來像脫褲子放屁。
我想到前陣子練習的 Python Django,改一下 views.py:
from django.shortcuts import render
import requests
# Create your views here.
def index(request):
resp = requests.post('http://localhost/aspnet/tinysso/validate.aspx?t=' + request.GET.get('t', ''))
if resp.status_code == requests.codes.ok:
u = resp.text
context = {
'name': u
}
return render(request, 'index.html', context=context)
這樣子 Python 網站也能用整合式 Windows 驗證登入了,酷吧!
第三方網站可以裝在另一台機器甚至非 Windows 上嗎?可以,但 validate.aspx 需稍加改寫。習慣上我會限定呼叫 validate.aspx 的來源 IP,本機時可用 Request.IsLocal 檢查,若第三方網站不在同一台,可在 web.config 加入 <add key="ClientIps" value="192.168.1.1,192.168.1.2" /> 列舉會呼叫 validate.aspx 的來源,validate.aspx 則改為:
<%@ Page Language="C#"%>
<script runat="server">
void Page_Load(object sender, EventArgs e)
{
var identity = "";
var clientIps = System.Configuration.ConfigurationManager.AppSettings["ClientIps"].Split(',');
if (Request.HttpMethod == "POST")
{
var token = Request["t"];
if (!string.IsNullOrEmpty(token) && clientIps.Contains(Request.UserHostAddress))
{
identity = (string)Cache[token];
if (identity != null) Cache.Remove(token);
}
}
Response.Write(identity);
}
</script>
不用建專案,免安裝,不依賴程式庫,就能實現 IIS 整合式 Windows 驗證 SSO,符合我偏愛的極簡風,提供大家參考。
A extremely simple implementation of SSO to make 3rd party web support integrated Windows authenticaion.
Comments
# by Ted
黑大您好 我想要請教如果今天情境是有超過2個以上第三方網站 如果第三方A網站驗證成功後有功能需求去第三方B網站 但因為Cache已被清空.....是否就需要再驗證一次
# by Jeffrey
to Ted, 如果不想驗證兩次,你可以改寫程式,sso.aspx 一次產生兩組 Guid 轉交 A 網站,A 網站接收後一組自用,一組交給 B 網站。另一種解法是讓 sso.aspx 有轉 A 網站與 B 網站兩種版本,連去 B 網站時一樣從 sso.aspx 轉過去,因為之前連 A 網站時已 Windows 整合式驗證過,不需要再 Key 帳密就可導到 B 網站。
# by Ted
To 黑大 謝謝您的答覆,受益良多
# by SAM
感謝樓主,省了很多自己研究的時間。