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

若使用 Forms Authentication 我常用的登入程式碼如下:
string userData = "";
protected void Login_Button_Click(object sender, EventArgs e)
{
Session.RemoveAll();
string strPassword = FormsAuthentication.HashPasswordForStoringInConfigFile(txtPassword.Text, "SHA1");
if (ValidateLogin(txtAccount.Text, strPassword))
{
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);
var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);
cookie.HttpOnly = true;
Response.Cookies.Add(cookie);
Response.Redirect("~/Members/", true);
}
else
{
Page.ClientScript.RegisterStartupScript(Page.GetType(), "LoginFail", "alert('登入失敗,請重新登入!');", true);
}
}
private bool ValidateLogin(string strUsername, string strPassword)
{
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 id = (FormsIdentity)User.Identity;
FormsAuthenticationTicket ticket = id.Ticket;
string[] roles = ticket.UserData.Split(new char[] { ',' });
Context.User = new GenericPrincipal(Context.User.Identity, roles);
}
}
這段程式碼我可是研究好久才整理出來的,但我覺得透過這種方式自訂「角色」感覺簡單多了,而且也不需要自己實做 Role Provider 或在資料庫中多建立一個表格。
若要啟用 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>