今天收到的隨堂測驗考題:

在使用IE以Windows驗證登入IIS的企業環境中,系統透過通知信件傳送某網頁的連結,而客戶希望使用IE開啟該連結時,無論當時是否已登入過該網站,也不管IE已記憶密碼或設定可用網域帳號自動登入,都需再次彈出登入對話框,要求使用者重新輸入帳號密碼後才可使用。

原本以為用Request.StatusCode = 401;的招術就可輕鬆解決,但後來發現沒這麼簡單: 若已用IE登入過該網站,即便透過ASP.NET傳回Status 401,IE私底下會先用剛才的帳號密碼嘗試登入(原本是貼心的設計,這下倒成了雞婆的舉動),一旦登入成功,便不再彈出詢問帳號密碼的對話框,砸了我的如意算盤。

爬文找到一個從沒用過的指令: ClearAuthenticationCache。IE6 SP1以後的IE瀏覽器都有支援,呼叫document.execCommand('ClearAuthenticationCache', false)後,IE會清掉身分認證相關的Cache資料,觸發重新登入。運用這項IE獨門的祕密武器,URL參數上再做點手腳配合,就可組合出有趣的結果。首先,在通知信件的連結裡加入&src=mail參數,當ASP.NET檢查URL中包含src=mail,判別為來自信件的連結,會進行兩個動作: 1) 執行ClearAuthenticationCache  2) 用location.href指向將src=mail置換成src=web的新URL。於是觸發IE重新登入,再度進入ASP.NET時,已是src=web,此時即可正常進入網頁介面。

以下是程式範例:

<%@ Page Language="C#" %>
<script runat="server">
    void Page_Load(object sender, EventArgs e)
    {
        string rawUrl = Request.RawUrl;
        if (rawUrl.Contains("src=mail"))
        {
            ClientScript.RegisterClientScriptBlock(
                this.GetType(), "redirect", string.Format(@"
document.execCommand('ClearAuthenticationCache', false);
location.href = '{0}';", rawUrl.Replace("src=mail", "src=web")), true);
        }
        else
            lblDisp.Text = string.Format("Hi, {0}!",
                Request.LogonUserIdentity.Name);
    }
        
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Relogon Test</title>
</head>
<body>
<form id="form1" runat="server">
    <asp:Label ID="lblDisp" runat="server"></asp:Label>
</form>
</body>
</html>

Comments

# by 小熊子

真是實用!!

# by LouisDeng

如果考慮到跨瀏覽器的話... 是不是可以從Server端在Src=Mail的時候判斷如果已經登入的話就進行登入再Redirect到Src=Web 是不是一樣的功效?@@

# by hectorlee369

這招會把所有的Cache清空, 包含親朋好友

# by Jeffrey

to LouisDeng, "如果已經登入的話就進行登入"<==我用IE9測試時,在這裡吃龞。過去唯一會的技巧是Response.StatusCode = 401; Response.End();但實測發現IE9並不會再次詢問使用者帳號密碼,而會直接用先前給過的密碼自動登入成功,結果就沒彈出帳密對話框,最後失敗收場。

# by Jeffrey

to hectorlee369, 的確,它會清除IE所有的認證Cache。例如: 先登入Hotmail,再另開頁籤執行document.execCommand('ClearAuthenticationCache', false),回到Hotmail重新整理,會發現Hotmail已被登出,看來是不小的副作用。

# by LouisDeng

抱歉...我筆誤 "如果已經登入的話就進行登入" -> 應該修正為"如果已經登入就進行登出" 然後再依照網站的登入流程就可以了?這樣會有問題嗎?

# by Jeffrey

to LouisDeng, 使用Windows驗證時(非Forms驗證),看來只能用Response.StatusCode=401的技巧模擬所謂的登出(因為登出的目的就是為了觸發重新登入),而重新登入時IE的會自動送出所記憶的認證身分而略過詢問帳密,就這層原理來看,除了設法關閉IE或清除記憶的驗證資料(即ClearAuthenticationCache在做的事),應該沒有更好的解決方法。

# by Kim

Dear 黑大 想請教以下設定 1.若iis設定為[整合式驗證] 2.ie-->[使用者驗證]設為[使用目前的使用者名稱及密碼來自動登入] 這樣的設定用了您介紹的方法後,都不會跳出視窗? 請問您有遇過嗎?

# by Jeffrey

to Kim, 依我的理解,設定成"使用目前的使用者名稱及密碼來自動登入"且當時的使用者身分有效,IE在需要認證時便會自動登入而不彈出視窗詢問帳號密碼。參考: http://technet.microsoft.com/en-us/library/dd346862.aspx The logon credential may be tried silently by Windows NT Challenge response (NTLM), an authentication protocol between an end-user client and application server, before prompting.

# by Fish.Siao

請教黑大: 在IE用document.execCommand('ClearAuthenticationCache'),但在Chrome或Firefox會失效,能否請教您Request.StatusCode = 401的用法? 我參考其他文章寫了之後,可以登出,但卻無法登入了...0.0

# by Jeffrey

to Fish.Siao, ClearAuthenticationCache的確只對IE有效,至於401登出後無法登入,感覺是程式邏輯問題,能提供實作的細節嗎?

# by Fish.Siao

Dear 黑大: 我在Button_Click 裡寫了 Response.StatusCode = 401 Response.End() 'Response.Redirect("Default.aspx") 原本有寫,後來拿掉了 一開始以為是又導向回原頁的關係,但其實不論有沒有導回原頁,點了登出之後就會跳出詢問帳密的視窗,打了帳密卻無法登入,必須瀏覽器關掉重開才能再次登入 感謝黑大不吝指教!!

# by Jeffrey

to Fish.Siao, "無法登入"是指輸完帳密送出又繼續出現登入對話框?

# by Fish.Siao

Dear 黑大: 是的,一直在輸入帳密的無限迴圈裡... 若是按「取消」跳過帳密就會出現 401 Error 了。 雖然 401 是我自己下的指令,但卡在無法登入看到 401 真是頭痛...QQ

# by Jeffrey

to Fish.Siao, 依我推測無限循環來自於Button_Click()傳回HTTP 401,驅使瀏覽器要求登入,但登入後又立即跳進Button_Click()的邏輯,再傳回HTTP 401,瀏覽器只好乖乖再問一次密碼。你可以用Visual Studio在 Response.StatusCode = 401設偵測點驗證是否是這個原因? 如果是,用Cookie之類的技巧,在第二次進入時不要回傳401而轉址到其他頁面,應該可以解決問題。

# by Fish.Siao

Dear 黑大: 用 VS 執行的話會因為 IIS 信任問題不會跳出詢問帳密的視窗 QQ 正在找 MIS 想辦法處理,或是嘗試用其他方法驗證是否又跳回Button_Click()裡。 非常謝謝你的指導~^^

# by Jeffrey

to Fish.Siao, 依我的測試,使用VS執行也可以要求IISExpress跳出帳密視窗,試試這個設定: https://www.facebook.com/photo.php?fbid=10201162917174326&set=gm.567458683338150&type=1&theater

Post a comment