天天看點

IE11下Forms身份認證無法儲存Cookie的問題

  ASP.NET中使用Forms身份認證常見的做法如下:

1. 網站根目錄下的Web.config添加authentication節點

<authentication mode="Forms">
  <forms name="MyAuth" loginUrl="manager/Login.aspx" defaultUrl="manager/default.aspx" protection="All" timeout="60" />
</authentication>      

2. 在manager子目錄下添加Web.config檔案并加入下面的内容:

<?xml version="1.0"?>
<configuration>
    <system.web>
      <authorization>
        <allow roles="Admin" />
        <deny users="*" />
      </authorization>
    </system.web>
</configuration>      

  這樣,使用者在沒有Forms認證的情況下通路manager子目錄下的任何頁面均會自動跳轉到manager/Login.aspx頁面。如果認證成功,則會預設回到manager/default.aspx頁面。認證有效期為60分鐘。

3. 添加認證代碼。登入按鈕中添加下面的代碼:

if (!snCheckCode.CheckSN(txt_ValidateCode.Text))
{
    snCheckCode.Create();
    Utility.ShowMessage("校驗碼錯誤!");
    return;
}

string strUserName = txt_Username.Text.Trim();
string md5Pwd = Helper.MD5ForPHP(Helper.MD5ForPHP(txt_Password.Text));
lc_admin admin = null;
bool logined = false;

using (var context = new dbEntities())
{
    admin = context.tb_admin.Where(n => n.username == strUserName).FirstOrDefault();

    if (admin != null)
    {
        if (admin.checkadmin != "true")
        {
            snCheckCode.Create();
            Utility.ShowMessage("抱歉,該賬号被禁止登入!");
            return;
        }

        if (admin.password == md5Pwd)
        {
            // Update Admin Info
            admin.loginip = Request.UserHostAddress.ToString();
            admin.logintime = CndingUtility.DateTimeToUnixTimeStamp(DateTime.Now);
            context.SaveChanges();

            logined = true;
        }
    }
}

if (logined)
{
    // Login
    FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
        1,
        admin.id.ToString(),
        DateTime.Now,
        DateTime.Now.AddMinutes(60),
        false,
        "Admin",
        FormsAuthentication.FormsCookiePath
        );
    string hashTicket = FormsAuthentication.Encrypt(ticket);
    HttpCookie userCookie = new HttpCookie(FormsAuthentication.FormsCookieName, hashTicket);
    HttpContext.Current.Response.Cookies.Add(userCookie);

    if (Request["ReturnUrl"] != null)
    {
        Response.Redirect(HttpUtility.HtmlDecode(Request["ReturnUrl"]));
    }
    else
    {
        Response.Redirect("/manager/default.aspx");
    }
}
else
{
    snCheckCode.Create();
    CndingUtility.ShowMessage("使用者名或密碼不正确!");
}      

MD5加密代碼:

public static string MD5ForPHP(string stringToHash)
{
    var md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
    byte[] emailBytes = Encoding.UTF8.GetBytes(stringToHash.ToLower());
    byte[] hashedEmailBytes = md5.ComputeHash(emailBytes);
    StringBuilder sb = new StringBuilder();
    foreach (var b in hashedEmailBytes)
    {
        sb.Append(b.ToString("x2").ToLower());
    }
    return sb.ToString();
}      

  認證成功後預設會将使用者登入資訊以Cookie的形式存放到用戶端,有效期為60分鐘。UserData被設定為使用者的角色,在判斷使用者是否登入時會用到。如下面的代碼:

if (HttpContext.Current.User.Identity.IsAuthenticated)
{
    int adminId = -1;
    FormsIdentity identity = (FormsIdentity)HttpContext.Current.User.Identity;
    FormsAuthenticationTicket ticket = identity.Ticket;
    string userData = ticket.UserData;
    if (userData == "Admin")
    {
        // To do something
    }
}      

   上述代碼在Visual Studio中運作一切正常!但是将網站釋出到伺服器的IIS (可能會是較低版本的IIS,如IIS 6)後,發現登入功能異常。輸入使用者名和密碼後點選登入按鈕,頁面postback但并不能正确跳轉,嘗試手動通路受保護的頁面會被自動跳轉回登入頁面。更奇怪的是該問題隻出現在IE11浏覽器上,嘗試用Firefox或Chrome通路登入功能運作正常。初步懷疑是IIS設定的問題,可是IIS 6上并沒有與Cookie相關的設定,好像記得IIS 7上倒是有這個設定。但因為隻有IE 11存在該問題,是以可以否定代碼本身存在任何問題。

  此外,還嘗試了降低IE 11的安全級别,重新安裝伺服器上的.net framework以及下載下傳最新的更新檔等等,均不能解決問題。後來發現其實隻需要簡單修改Web.config中authentication節點的設定就可以了,給forms添加cookieless="UseCookies"屬性即可。

<authentication mode="Forms">
  <forms name="MyAuth" cookieless="UseCookies" loginUrl="manager/Login.aspx" defaultUrl="manager/default.aspx" protection="All" timeout="60" />
</authentication>      

  用以明确告訴伺服器使用Cookie來儲存使用者驗證資訊。問題解決!