1. 程式人生 > >MVC身份驗證及權限管理

MVC身份驗證及權限管理

font word 註入 方法 web應用 com 保存 account ipa

本文旨在簡單介紹mvc的權限驗證。

一、Forms認證

1、首先是建一個asp.net web應用程序

技術分享圖片

為了實現身份驗證,所以必須要添加一個登陸頁面,同時還需要有對應的用戶類型,所以添加了以下代碼

IUserDb接口。其實這個接口可以不用,但是在這裏我用的是MEF組件來實現依賴註入。所以有了這個接口
namespace QuanXianYanZheng.Interface
{
    interface IUserDb
    {
        bool ValidateUser(string userName, string password);
        
string[] GetRoles(string userName); Models.User GetByNameAndPassword(string name, string password); } }

UserDb,這個類實際上是模擬數據庫操作的。export是MEF組件實現依賴註入的,可以看看前一篇隨筆了解。
namespace QuanXianYanZheng.DB
{
    [Export("UserDb",typeof(IUserDb))]
    public class UserDb: IUserDb
    {
        
//模擬數據庫,用戶表 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"}}, }; /// <summary> /// 驗證用戶密碼 /// </summary> /// <param name="userName"></param> /// <param name="password"></param> /// <returns></returns> public bool ValidateUser(string userName, string password) { return usersForTest .Any(u => u.Name == userName && u.Password == password); } /// <summary> /// 獲取用戶的角色 /// </summary> /// <param name="userName"></param> /// <returns></returns> public string[] GetRoles(string userName) { return usersForTest .Where(u => u.Name == userName) .Select(u => u.Roles) .FirstOrDefault(); } /// <summary> /// 獲取用戶 /// </summary> /// <param name="name"></param> /// <param name="password"></param> /// <returns></returns> public User GetByNameAndPassword(string name, string password) { return usersForTest .FirstOrDefault(u => u.Name == name && u.Password == password); } } }

User,用戶模型

namespace QuanXianYanZheng.Models
{
    public class User
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public string Password { get; set; }
        public string[] Roles { get; set; }
    }
}
AccountController 登陸頁面的控制器
namespace QuanXianYanZheng.Controllers
{
    public class AccountController : Controller
    {
        [Import("UserDb")]
        private IUserDb Repository { set; get; }


        public ActionResult LogOn()
        {
            return View();
        }
        [HttpPost]
        public ActionResult LogOn(LogOnModel model, string returnUrl)
        {
            if (ModelState.IsValid)
            {
                if(null==Repository) CustomTool.Compose(this);
                if (Repository.ValidateUser(model.UserName, model.Password))
                {
                    //將用戶信息保存到cookie,如果不能使用cookie則添加到URL
                    FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
                    if (!String.IsNullOrEmpty(returnUrl)) return Redirect(returnUrl);
                    else return RedirectToAction("Index", "Home");
                }
                else
                    ModelState.AddModelError("", "用戶名或密碼不正確!");
            }
            return View(model);
        }

    }
}
Compose,這個是為了實現依賴註入來實例化對象專門寫的一段公共代碼,如果不用這種方式來實例化對象,可以不要這段。
namespace QuanXianYanZheng
{
    public class CustomTool
    {
        /// <summary>
        /// 這個是為了實現依賴註入的方式來實例化對象而必須要執行的一段代碼
        /// </summary>
        /// <param name="o"></param>
        public static void Compose(object o)
        {
            var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
            CompositionContainer container = new CompositionContainer(catalog);
            container.ComposeParts(o);
        }
    }
}

LogOnModel類太簡單了,就不貼代碼了。然後創建登陸頁面,就兩個文本框一個登陸按鈕,也沒什麽難度了。然後就是Global.asax,在類MvcApplication中添加一個構造函數,代碼如下:

     [Import("UserDb")]
        private IUserDb Repository { set; get; }
        /// <summary>
        /// 添加構造函數
        /// </summary>
        public MvcApplication()
        {
            AuthorizeRequest += new EventHandler(MvcApplication_AuthorizeRequest);
        }
        void MvcApplication_AuthorizeRequest(object sender, EventArgs e)
        {
            IIdentity id = Context.User.Identity;
            if(null== Repository) CustomTool.Compose(this);//這個是為了實現依賴註入的方式而調用的
            if (id.IsAuthenticated)//這裏判斷訪問者是否成功進行了身份驗證
            {
                var roles = Repository.GetRoles(id.Name);
                Context.User = new GenericPrincipal(id, roles);
            }            
        }

至此,代碼基本寫好了,然後運行程序,將斷點打在此處:

技術分享圖片

會發現程序每次進入後臺控制器之前,都會經過這裏,不管你有沒有進行成功的登錄,這個if語句的判斷條件都是false。這很顯然不符合我的要求,我要的是在成功登錄後,這個判斷是true。之所以出現現在的情況,是因為配置文件還沒有相關的配置:

技術分享圖片

有了這段配置之後,再次運行程序。默認還是進入了home/index頁面,這與我的要求是有出入的,我要求在用戶沒登陸的情況下,默認進入登陸頁面。這個問題先放著,後面會解決。這裏之所以進入的是home/index頁面,是因為路由的配置是這樣的,沒什麽可說的。

運行程序後,在沒有登錄的情況下,上面的斷點一直是false,但如果登錄成功後,就會變成true了。有這樣的變化,是因為執行了下面這條語句

技術分享圖片

現在來處理剛才提到的在沒有登錄的時候默認進入了home/index頁面的問題,解決這個問題不需要去修改路由的配置,只需要在HomeController的index方法上添加特性 [Authorize]即可。

技術分享圖片

再次運行程序之前記得清空瀏覽器緩存,因為剛才已經成功登陸過了,使得上面斷點的地方判斷的是true,默認的是已經驗證過了,因此還是會進入home/index頁面,所以必須清空緩存。這樣就可以看到再次默認進入的是登陸頁面了。

未完待續....

MVC身份驗證及權限管理