簡單的One-Time Token方案,應用在整合各Web AP
前言
最近常常遇到整合的案子,Portal整來整去的! 原本想說那就全走Windows整合驗證就好了呀!
只是這樣到EIP要Key一次帳號密碼,進入我們的系統又要再Key一次帳號及密碼! 當然,如果將該網站加入近端的網站,就會用預設的帳號登入!
但是如果User在家是使用Win7 Home版本的話,那還是要Key 2次。
所以想說要連到其他Web AP時,將帳號一併傳送,所以就使用One-Time Token(類似One-Time Password(OTP))的方式來實作帳號的傳遞,讓別的Web AP可以吃到EIP的帳號。
實作
為了讓從EIP連過去的系統也能取到EIP的使用者帳號,就將帳號資訊放在QueryString之中傳遞過去,再讓另外的Web AP去解開取得使用者帳號。
因為是透過QueryString,所以使用One-Time Token(類似One-Time Password(OTP))的方式來實作帳號的傳遞,這樣就不怕該QueryString被竊取。
實作的步驟如下,
1.在Link到別Web AP(OTPWebAP2)時,產生一個Token,並將Token及使用者帳號存到DB之中。
2.在OTPWebAP2接到Request時,解析QueryString,取得使用者帳號,並將資料庫中該筆資料註記成失效。方案說明
1.OTP_LOG TABLE,記錄TOKEN與USER_ID的對應,IS_ACTIVE註記是否失效。
--OTP的TOKEN記錄 CREATE TABLE [dbo].[OTP_LOG]( [TOKEN] [varchar](128) NOT NULL, [IS_ACTIVE] [bit] NOT NULL DEFAULT(1), [USER_ID] [varchar](128) NOT NULL, CONSTRAINT [PK_OTP_LOG] PRIMARY KEY CLUSTERED ( [TOKEN] ASC ) )
2.OTPLib Class Library,負責產生Token及解析Token取得User_Id
StringHelpers:負責加解密
DBHelper:取得Connection String及資料庫的存取
OTPHelper:負責產生Token及解析Token取得User_Id,產生token的話,最簡單就是取GUID。public class OTPHelper{ /// <summary> /// 產生代表該user的token /// </summary> /// <param name="userId"></param> /// <returns></returns> public static string GenerateTokenByUserID(string userId) { return GenerateTokenByUserID(userId, string.Empty); } /// <summary> /// 產生代表該user的token /// </summary> /// <param name="userId"></param> /// <param name="extendQueryString">額外的QueryString</param> /// <returns></returns> public static string GenerateTokenByUserID(string userId, string extendQueryString) { //建立新的token string newToken = Guid.NewGuid().ToString(); //將資料新增到OTP_LOG之中 DBHelper.SaveTokenLog(newToken, userId); if (!string.IsNullOrEmpty(extendQueryString)) extendQueryString = "&" + extendQueryString; //透過QueryString,所以要加密比較好 string result = StringHelpers.EncryptQueryString("token=" + newToken + extendQueryString); return result; } /// <summary> /// 由QueryString取得UserID /// </summary> /// <param name="queryString"></param> /// <returns></returns> public static string ParseTokenQueryString(string queryString) { NameValueCollection paList = StringHelpers.DecryptQueryString(queryString); string result = string.Empty; if (paList != null && paList.Count > 0) { //取得token string token = paList["token"]; if (!string.IsNullOrEmpty(token)) { //取出userid & set IS_ACTIVE = 0 result = DBHelper.GetActiveUserIDByToken(token); } } return result; } }
3.OTPWebEIP Web Site,From驗證的EIP Web Site。
Login.aspx:使用者登入頁面。
Default.aspx:Portal頁面,可連接到不同的Web AP。<script language="javascript" type="text/javascript"> function __OpenOtherWebAP(vstrWinName, vstrURL) { var iScreenWidth, iScreenHeight, iTaskLine, itop, ileft; var strWinName = vstrWinName + "_Window"; iTaskLine = 100; iScreenWidth = (screen.width - iTaskLine); iScreenHeight = (screen.height - iTaskLine); itop = 20; ileft = 20; var sParams = "width=" + iScreenWidth.toString() + ",height=" + iScreenHeight.toString() + ",top=" + itop.toString() + ",left=" + ileft.toString() + ",location=yes,toolbar=yes,menubar=yes,resizable=yes,status=1,scrollbars=yes"; window.open(vstrURL, strWinName, sParams); } </script>
protected void btnLinkWebAP2_Click(object sender, EventArgs e){ //要連到WebAp2,所以要產生一個代表目前使用者的Token string tokenQueryString = OTPLib.OTPHelper.GenerateTokenByUserID(Context.User.Identity.Name); ClientScript.RegisterStartupScript(this.GetType(), "linkWebAp2", "__OpenOtherWebAP('WEBAP2', 'http://localhost:1401/OTPWebAP2/Login.aspx" + tokenQueryString + "');", true ); }
4.OTPWebAP2 Web Site,Form驗證的AP2 Web Site。
Login.aspx:使用者登入頁面。
protected void Page_Load(object sender, EventArgs e){ //string returnURL = FormsAuthentication.GetRedirectUrl("", false); //解析看看是否有token的QUERYSTRING,表示是OTP,所以要做登入的動作 string userId = OTPLib.OTPHelper.ParseTokenQueryString(Request.QueryString.ToString()); if (!string.IsNullOrEmpty(userId)) { //有Parse出UserID所以要導到預設網頁 FormsAuthentication.RedirectFromLoginPage(userId, false); } }
Default.aspx:AP2的預設頁面。
結論
以上是簡單的OTP方案,可應用在EIP整合各Web AP上面。當然,更可以將OTPLib專案做成Web Services給不同平台的Web AP來使用哦!
參考資料
範例程式
Hi,
亂馬客Blog已移到了 「亂馬客 : Re:從零開始的軟體開發生活」
請大家繼續支持 ^_^