The Will Will Web

記載著 Will 在網路世界的學習心得與技術分享

ASP.NET 自訂角色的方式(不用實做 Role Provider)

我之前講過一篇文章叫做概略解釋 Forms Authentication 的運作,但若要使用 Forms Authentication 來驗證使用者又要自行指派使用者的角色時那就麻煩了,通常要實做角色提供者(Role Provider) 才行,不過通常很麻煩,我今天介紹一個更簡單、方便的自訂角色方法。

若使用 Forms Authentication 我常用的登入程式碼如下:

/// <summary>
/// 設定要存在 FormsAuthenticationTicket 中的資料,這裡用來儲存角色資訊
/// </summary>
string userData = "";

protected void Login_Button_Click(object sender, EventArgs e)
{
    // 登入時清空所有 Session 資料
    Session.RemoveAll();

    // 登入的密碼(以 SHA1 加密)
    string strPassword = FormsAuthentication.HashPasswordForStoringInConfigFile(txtPassword.Text, "SHA1");

    if (ValidateLogin(txtAccount.Text, strPassword))
    {
        // 將管理者登入的 Cookie 設定成 Session Cookie
        bool isPersistent = false;

        FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1,
          txtAccount.Text,
          DateTime.Now,
          DateTime.Now.AddMinutes(30),
          isPersistent,
          userData,
          FormsAuthentication.FormsCookiePath);

        string encTicket = FormsAuthentication.Encrypt(ticket);

        // Create the cookie.
        Response.Cookies.Add(new HttpCookie(FormsAuthentication.FormsCookieName, encTicket));

        Response.Redirect("~/Members/", true);
    }
    else
    {
        Page.ClientScript.RegisterStartupScript(Page.GetType(), "LoginFail", "alert('登入失敗,請重新登入!');", true);
    }
}

/// <summary>
/// 驗證使用者是否登入成功
/// </summary>
/// <param name="strUsername">登入帳號</param>
/// <param name="strPassword">登入密碼</param>
/// <returns></returns>
private bool ValidateLogin(string strUsername, string strPassword)
{
    // 驗證
    
        // 請自行寫 Code 檢查 Username, Password 是否正確
    
    // 授權:設定角色到 userData 
    userData = "gold_member,board_admin";
    
    return true;
}

而這段程式的重點在於我將 userData 儲存在 FormsAuthenticationTicket 中,讓使用者登入資訊包括「角色」的定義,但是如果你要在程式中使用 User.IsInRole 或要在 SiteMap 檔中啟用 securityTrimmingEnabled 的話,還需要在 Global.asax 中新增 Application_AuthenticateRequest 事件,才能讓 ASP.NET 知道該使用者擁有什麼角色,如下:

void Application_AuthenticateRequest(object sender, EventArgs e){
    if (Request.IsAuthenticated) {
        // 先取得該使用者的 FormsIdentity
        FormsIdentity id = (FormsIdentity)User.Identity;
        // 再取出使用者的 FormsAuthenticationTicket
        FormsAuthenticationTicket ticket = id.Ticket;
        // 將儲存在 FormsAuthenticationTicket 中的角色定義取出,並轉成字串陣列
        string[] roles = ticket.UserData.Split(new char[] { ',' });
        // 指派角色到目前這個 HttpContext 的 User 物件去
        Context.User = new GenericPrincipal(Context.User.Identity, roles);
    }
}

這段程式碼我可是研究好久才整理出來的,但我覺得透過這種方式自訂「角色」感覺簡單多了,而且也不需要自己實做 Role Provider 或在資料庫中多建立一個表格,整體的效能也應該不差才是。

P.S. 若要啟用 SiteMap 安全限制的功能必須要在 web.config 中設定該 sitemap 定義的 securityTrimmingEnabled 屬性為 True 才行,如下:

<siteMap defaultProvider="SiteMapProvider" enabled="true">
    <providers>
        <add name="SiteMapProvider" description="設的 SiteMap 定義檔"
             type="System.Web.XmlSiteMapProvider " siteMapFile="~/Web.sitemap" 
             securityTrimmingEnabled="true"/>
    </providers>
</siteMap>