ASP.NET MVC:表單身分識別驗證及角色許可權管理樣本

來源:互聯網
上載者:User

標籤:time   錯誤   file   內容   移除   地址   redirect   member   create   

 


前言

  本來使用Forms Authentication進行使用者驗證的方式是最常見的,但系統地闡明其方法的文章並不多見,網上更多的文章都是介紹其中某一部分的使用方法或實現原理,而更多的朋友則發文詢問如何從頭到尾完整第實現使用者的註冊、登入。因此,Anders Liu在這一系列文章中計劃通過一個實際的例子,介紹如何基於Forms Authentication實現:

l  使用者註冊(包括密碼的加密儲存)

l  使用者登入(包括密碼的驗證、設定安全Cookie)

l  使用者實體替換(使用自己的類型作為HttpContext.User的類型)

  有關Forms Authentication的原理等內容不屬於本文的討論範疇,大家可以通過在Google等搜尋引擎中輸入“Forms Authentication”、“Forms身分識別驗證”、“表單身分識別驗證”等關鍵詞來查看更多資源。本文僅從實用的角度介紹如何使用這一技術。

 

不使用Membership

  本文介紹的實現方式不依賴ASP.NET 2.0提供的Membership功能。這主要是因為,如果使用Membership,就必須用aspnet_regsql.exe工具 + 生產力設定資料庫,否則就得自己寫自訂的MembershipProvider。

  如果用aspnet_regsql.exe設定資料庫,就會導致資料庫中出現很多我們實際並不需要的表或欄位。此外更重要的是,預設的SqlMembershipProvider給很多資料表添加了ApplicationID列,其初衷可能是希望可以將多個應用程式的使用者全部放在一個庫裡,但又能彼此隔離。但實際情況是,每個應用程式都在其自身的資料庫中儲存使用者資料。因此,引入這個ApplicationID無端地在每次尋找使用者時增加了額外的條件。

  另一方面,如果考慮自己實現一個MembershipProvider,因為工作量巨大,有點得不償失。

  但是,如果不使用Membership,也就無法享受ASP.NET 2.0中新增的Login等控制項的便利了。

 

與Forms Authentication相關的配置

  在web.config檔案中,<system.web>/<authentication>配置節用於對驗證進行配置。為<authentication>節點提供mode="Forms"屬性可以啟用Forms Authentication。一個典型的<authentication>配置節如下所示:

 

<authentication mode="Forms">

     <forms

         name=".ASPXAUTH"

         loginUrl="login.aspx"

         defaultUrl="default.aspx"

         protection="All"

         timeout="30"

         path="/"

         requireSSL="false"

         slidingExpiration="false"

         enableCrossAppRedirects="false"

         cookieless="UseDeviceProfile"

         domain=""

     />

</authentication>

 

  以上代碼使用的均是預設設定,換言之,如果你的哪項配置屬性與上述代碼一致,則可以省略該屬性例如<forms name="MyAppAuth" />。下面依次介紹一下各種屬性:

l  name——Cookie的名字。Forms Authentication可能會在驗證後將使用者憑證放在Cookie中,name屬性決定了該Cookie的名字。通過FormsAuthentication.FormsCookieName屬性可以得到該配置值(稍後介紹FromsAuthentication類)。

l  loginUrl——登入頁的URL。通過FormsAuthentication.LoginUrl屬性可以得到該配置值。當調用FormsAuthentication.RedirectToLoginPage()方法時,用戶端請求將被重新導向到該屬性所指定的頁面。loginUrl的預設值為“login.aspx”,這表明即便不提供該屬性值,ASP.NET也會嘗試到網站根目錄下尋找名為login.aspx的頁面。

l  defaultUrl——預設頁的URL。通過FormsAuthentication.DefaultUrl屬性得到該配置值。

l  protection——Cookie的保護模式,可取值包括All(同時進行加密和資料驗證)、Encryption(僅加密)、Validation(僅進行資料驗證)和None。為了安全,該屬性通常從不設定為None。

l  timeout——Cookie的到期時間。

l  path——Cookie的路徑。可以通過FormsAuthentication.FormsCookiePath屬性得到該配置值。

l  requireSSL——在進行Forms Authentication時,與伺服器互動是否要求使用SSL。可以通過FormsAuthentication.RequireSSL屬性得到該配置值。

l  slidingExpiration——是否啟用“彈性到期時間”,如果該屬性設定為false,從首次驗證之後過timeout時間後Cookie即到期;如果該屬性為true,則從上次請求該開始過timeout時間才到期,這意味著,在首次驗證後,如果保證每timeout時間內至少發送一個請求,則Cookie將永遠不會到期。通過FormsAuthentication.SlidingExpiration屬性可以得到該配置值。

l  enableCrossAppRedirects——是否可以將以進行了身分識別驗證的使用者重新導向到其他應用程式中。通過FormsAuthentication.EnableCrossAppRedirects屬性可以得到該配置值。為了安全考慮,通常總是將該屬性設定為false。

l  cookieless——定義是否使用Cookie以及Cookie的行為。Forms Authentication可以採用兩種方式在會話中儲存使用者憑證資訊,一種是使用Cookie,即將使用者憑證記錄到Cookie中,每次發送請求時瀏覽器都會將該Cookie提供給伺服器。另一種方式是使用URI,即將使用者憑證當作URL中額外的查詢字串傳遞給伺服器。該屬性有四種取值——UseCookies(無論何時都使用Cookie)、UseUri(從不使用Cookie,僅使用URI)、AutoDetect(檢測裝置和瀏覽器,只有當裝置支援Cookie並且在瀏覽器中啟用了Cookie時才使用Cookie)和UseDeviceProfile(只檢測裝置,只要裝置支援Cookie不管瀏覽器是否支援,都是用Cookie)。通過FormsAuthentication.CookieMode屬性可以得到該配置值。通過FormsAuthentication.CookiesSupported屬性可以得到對於當前請求是否使用Cookie傳遞使用者憑證。

l  domain——Cookie的域。通過FormsAuthentication.CookieDomain屬性可以得到該配置值。

  以上針對<system.web>/<authentication>/<forms>節點的介紹非常簡略,基本上是Anders Liu個人對於文檔進行的額外說明。有關<forms>節點的更多說明,請參見MSDN文檔(http://msdn2.microsoft.com/zh-cn/library/1d3t3c61(VS.85).aspx)。

 

FormsAuthentication類

  FormsAuthentication類用於輔助我們完成表單驗證,並進一步完成使用者登入等功能。該類位於system.web.dll程式集的System.Web.Security命名空間中。通常在Web網站項目中可以直接使用這個類,如果是在類庫項目中使用這個類,請確保引用了system.web.dll。

  前一節已經介紹了FormsAuthentication類的所有屬性。這一節將介紹該類少數幾個常用的方法。

  RedirectToLoginPage方法用於從任何頁面重新導向到登入頁,該方法有兩種重載方式:

 

public static void RedirectToLoginPage ()

public static void RedirectToLoginPage (string extraQueryString)

 

  兩種方式均會使瀏覽器重新導向到登入頁(登入頁的URL由<forms>節點的loginUrl屬性指出)。第二種重載方式還能夠提供額外的查詢字串。

  RedirectToLoginPage通常在任何非登入頁的頁面中調用。該方法除了進行重新導向之外,還會向URL中附加一個ReturnUrl參數,該參數即為調用該方法時所在的頁面的URL地址。這是為了方便登入後能夠自動回到登入前所在的頁面。

  RedirectFromLoginPage方法用於從登入頁跳回登入前頁面。這個“登入前”頁面即由訪問登入頁時提供的ReturnUrl參數指定。如果沒有提供ReturnUrl參數(例如,不是使用RedirectToLoginPage方法而是用其他手段重新導向到或直接存取登入頁時),則該方法會自動跳轉到由<forms>節點的defaultUrl屬性所指定的預設頁。

  此外,如果<forms>節點的enableCrossAppRedirects屬性被設定為false,ReturnUrl參數所指定的路徑必須是當前Web應用程式中的路徑,否則(如提供其他網站下的路徑)也將返回到預設頁。

  RedirectFromLoginPage方法有兩種重載形式:

 

public static void RedirectFromLoginPage (string userName, bool createPersistentCookie)

public static void RedirectFromLoginPage (string userName, bool createPersistentCookie, string strCookiePath)

 

  userName參數表示使用者的標識(如使用者名稱、使用者ID等);createPersistentCookie參數表示是否“記住我”;strCookiePath參數表示Cookie路徑。

  RedirectFromLoginPage方法除了完成重新導向之外,還會將經過加密(是否加密取決於<forms>節點的protection屬性)的使用者憑證存放到Cookie或Uri中。在後續訪問中,只要Cookie沒有到期,則將可以通過HttpContext.User.Identity.Name屬性得到這裡傳入的userName屬性。

  此外,FormsAuthentication還有一個SignOut方法,用於完成使用者登出。其原理是從Cookie或Uri中移除使用者憑證。

  

  好了,至此所需要掌握的基礎知識就齊備了,接下來我們將實現使用者註冊、登入等功能:

 

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 事件的處理函數。

代碼下載:Mvc-FormsAuthentication-RolesAuthorization-1.rar (243KB)

方式二

此方式將使用者的角色儲存至使用者 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);        }    }    //...}

代碼下載:Mvc-FormsAuthentication-RolesAuthorization-2.rar (244KB)

三、角色許可權

使用任一種方式後,我們就可以在 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) { /**/}    /**/}

若本文中有錯誤或不妥之處,敬請指正,謝謝!

 

已下為項目中用到的代碼:

 

身分識別驗證

後台:DateTime expiredTime = DateTime.Now.AddMonths(1);

string ssoData = userName + "," + saveLogin.ToString();

 

FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, userName,

DateTime.Now,

expiredTime,

saveLogin,

ssoData,

FormsAuthentication.FormsCookiePath);

 

string authTicket = FormsAuthentication.Encrypt(ticket);

HttpCookie lcookie = new HttpCookie(FormsAuthentication.FormsCookieName, authTicket);

lcookie.Expires = DateTime.Now.AddMonths(1);//勾選自動登入時

 

Response.Cookies.Add(lcookie);

 

前台if (!User.Identity.IsAuthenticated)

 

退出登入:

public ActionResult LogOff()

{

FormsAuthentication.SignOut(); 

return Redirect(FormsAuthentication.LoginUrl);//<system.web>後添加<authentication mode="Forms"><forms loginUrl="~/Portal" timeout="2880" name=".DASHBOARDNETAUTH"></forms></authentication>

}

 

ASP.NET MVC:表單身分識別驗證及角色許可權管理樣本

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.