簡單的One-Time Token方案,應用在整合各Web AP

簡單的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的帳號。

image

image

image

實作

為了讓從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,取得使用者帳號,並將資料庫中該筆資料註記成失效。

方案說明

image

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來使用哦!

參考資料

HOW TO:實作簡單表格驗證

Anatomy of ASP.NET Forms Authentication Return URL

使用單次密碼解決方案實現更安全的驗證機制

範例程式

OTPDemoProjects.rar

Hi, 

亂馬客Blog已移到了 「亂馬客​ : Re:從零開始的軟體開發生活

請大家繼續支持 ^_^