標籤:
ASP.NET MVC 建立 ASP.NET 基礎之上,很多 ASP.NET 的特性(如表單身分識別驗證、成員資格)在 MVC 中可以直接使用。本文旨在提供可參考的代碼,不會涉及這方面太多理論的知識。
本文僅使用 ASP.NET 的表單身分識別驗證,不會使用它的 成員資格(Membership) 和 角色管理 (RoleManager),原因有二:一是不靈活,二是和 MVC 關係不太。
一、樣本項目
User.cs 是模型檔案,其中包含了 User 類:
public class User{ public int ID { get; set; } public string Name { get; set; } public string Password { get; set; } public string[] Roles { get; set; }}
UserRepository 為資料存取類,為了示範方便,並沒有串連資料庫,而是使用一個數組來作為資料來源:
public class UserRepository{ private static User[] usersForTest = new[]{ new User{ ID = 1, Name = "bob", Password = "bob", Roles = new []{"employee"}}, new User{ ID = 2, Name = "tom", Password = "tom", Roles = new []{"manager"}}, new User{ ID = 3, Name = "admin", Password = "admin", Roles = new[]{"admin"}}, }; public bool ValidateUser(string userName, string password) { return usersForTest .Any(u => u.Name == userName && u.Password == password); } public string[] GetRoles(string userName) { return usersForTest .Where(u => u.Name == userName) .Select(u => u.Roles) .FirstOrDefault(); } public User GetByNameAndPassword(string name, string password) { return usersForTest .FirstOrDefault(u => u.Name == name && u.Password == password); }}
二、使用者登入及身分識別驗證方式一
修改 AccountController:原有 AccountController 為了實現控制反轉,對表單身分識別驗證進行了抽象。為了示範方便,我去除了這部分(以及註冊及修改密碼部分):
public class AccountController : Controller{ private UserRepository repository = new UserRepository(); public ActionResult LogOn() { return View(); } [HttpPost] public ActionResult LogOn(LogOnModel model, string returnUrl) { if (ModelState.IsValid) { if (repository.ValidateUser(model.UserName, model.Password)) { FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe); if (!String.IsNullOrEmpty(returnUrl)) return Redirect(returnUrl); else return RedirectToAction("Index", "Home"); } else ModelState.AddModelError("", "使用者名稱或密碼不正確!"); } return View(model); } public ActionResult LogOff() { FormsAuthentication.SignOut(); return RedirectToAction("Index", "Home"); }}
修改 Global.asax:
public class MvcApplication : System.Web.HttpApplication{ public MvcApplication() { AuthorizeRequest += new EventHandler(MvcApplication_AuthorizeRequest); } void MvcApplication_AuthorizeRequest(object sender, EventArgs e) { IIdentity id = Context.User.Identity; if (id.IsAuthenticated) { var roles = new UserRepository().GetRoles(id.Name); Context.User = new GenericPrincipal(id, roles); } } //...}
給 MvcApplication 增加建構函式,在其中增加 AuthorizeRequest 事件的處理函數。
方式二
此方式將使用者的角色儲存至使用者 Cookie,使用到了 FormsAuthenticationTicket。
修改 AccountController:
public class AccountController : Controller{ private UserRepository repository = new UserRepository(); public ActionResult LogOn() { return View(); } [HttpPost] public ActionResult LogOn(LogOnModel model, string returnUrl) { if (ModelState.IsValid) { User user = repository.GetByNameAndPassword(model.UserName, model.Password); if (user != null) { FormsAuthenticationTicket ticket = new FormsAuthenticationTicket( 1, user.Name, DateTime.Now, DateTime.Now.Add(FormsAuthentication.Timeout), model.RememberMe, user.Roles.Aggregate((i,j)=>i+","+j) ); HttpCookie cookie = new HttpCookie( FormsAuthentication.FormsCookieName, FormsAuthentication.Encrypt(ticket)); Response.Cookies.Add(cookie); if (!String.IsNullOrEmpty(returnUrl)) return Redirect(returnUrl); else return RedirectToAction("Index", "Home"); } else ModelState.AddModelError("", "使用者名稱或密碼不正確!"); } return View(model); } public ActionResult LogOff() { FormsAuthentication.SignOut(); return RedirectToAction("Index", "Home"); }}
修改 Global.asax:
public class MvcApplication : System.Web.HttpApplication{ public MvcApplication() { AuthorizeRequest += new EventHandler(MvcApplication_AuthorizeRequest); } void MvcApplication_AuthorizeRequest(object sender, EventArgs e) { var id = Context.User.Identity as FormsIdentity; if (id != null && id.IsAuthenticated) { var roles = id.Ticket.UserData.Split(‘,‘); Context.User = new GenericPrincipal(id, roles); } } //...}
三、角色許可權
使用任一種方式後,我們就可以在 Controller 中使用 AuthorizeAttribute 實現基於角色的許可權管理了:
[Authorize(Roles = "employee,manager")]public ActionResult Index1(){ return View();}[Authorize(Roles = "manager")]public ActionResult Index2(){ return View();}[Authorize(Users="admin", Roles = "admin")]public ActionResult Index3(){ return View();}
四、簡要說明
MVC 使用 HttpContext.User 屬性進行來進行實現身分識別驗證及角色管理,同樣 AuthorizeAttribute 也根據 HttpContext.User 進行角色許可權驗證。
因些不要在使用者登入後,將相關使用者資訊儲存在 Session 中(網上經常看到這種做法),將使用者儲存在 Session 中是一種非常不好的做法。
也不要在 Action 中進行角色許可權判斷,應該使用 AuthorizeAttribute 或它的子類,以下的方式都是錯誤的:
public ActionResult Action1(){ if (Session["User"] == null) { /**/} /**/}public ActionResult Action2(){ if (User.Identity == null) { /**/} if (User.Identity.IsAuthenticated == false) { /**/} if (User.IsInRole("admin") == false) { /**/} /**/}
ASP.NET MVC:表單身分識別驗證及角色許可權管理樣本