MVC身份驗證及權限管理(轉載)

from?https://www.cnblogs.com/asks/p/4372783.html

MVC自帶的ActionFilter

在Asp.Net WebForm的中要做到身份認證微軟為我們提供了三種方式,其中最常用的就是我們的Form認證,需要配置相應的信息。例如下面的配置信息:

復制代碼
<authentication mode="Forms"><forms loginUrl="Login.aspx" defaultUrl="Default.aspx" protection="All" />
</authentication>
<authorization><deny users="?"/><allow users="*"/>
</authorization>
復制代碼

說明我們登錄頁面是Login.aspx,登錄成功后的默認頁面是Default.aspx,而我們用戶信息采用驗證和加密兩種方式。而且最重要的 是我們要寫好授權方式(下面的授權一定要寫否則只說明使用Forms認證然后設置相關屬性是沒有用的),拒絕所有匿名用戶,只有登錄用戶可以正常訪問。這 樣之后我們設置點擊登錄按鈕將用戶名寫進cookie(也就是執行FormsAuthentication.SetAuthCookie(name, false);)就可以了。

在Asp.Net MVC中我們同樣可以使用Forms認證,但是如果你按照WebForm中的做法去做就不行了。例如你這樣配置信息:

復制代碼
<authentication mode="Forms"><forms loginUrl="~/Account/Login" defaultUrl="~/Home/Index" protection="All"/>
</authentication>
<authorization><deny users="?"/><allow users="*"/>
</authorization>
復制代碼

你在Login.aspx中設置登錄來觸發AccountController中的Logon來登錄,其中Logon代碼:

復制代碼
public ActionResult Logon(string name,string password)    
{    if (name == "jianxin160" && password == "160796")    {    FormsAuthentication.SetAuthCookie(name, false);    return Redirect("~/Home/Index");    }    else{    return Redirect("/");    }    
}
復制代碼

這樣的操作之后你會發現你的Logon是不會執行的。原因是什么呢?怎么同樣的設置為什么到了MVC中就不行了?原因就是二者機制不同,因為你設置的授權方式讓Logon無法訪問了。那么我們怎么來做呢?

其實在Asp.Net MVC中我們有更好的方式來做這一切,我們不需要授權方式,也就是說我們的配置信息像這樣:

<authentication mode="Forms"><forms loginUrl="~/Account/Login" defaultUrl="~/Home/Index" protection="All"/>
</authentication>

不需要說明匿名用戶不能登錄等。當然了,你會發現僅僅就這樣做肯定不行的我們還要換一種方式告訴系統哪些是需要登錄才能訪問的。你或許 想,o(︶︿︶)o 唉,那太麻煩了吧。其實不是這樣的,很簡單,我們只需要在需要認證的Action上標記[Authorize]就可以了。例如我在Home文件夾中有兩個 頁面Index和Home,我現在想讓Index經過認證才能訪問,而Home不需要,那么只需要給Index這個Action標記 [Authorize],也就是:

復制代碼
[Authorize]    
public ActionResult Index()    
{    return View();    
}    public ActionResult Home()    
{    return View();    
}
復制代碼

這樣Index就必須登錄之后才能訪問,而Home是不需要登錄的。如果你需要進行角色授權那么您就可以在標記Authorize的時候指明角色 (例如[Authorize(Role=Administrators)] ),不過您這是就必須使用微軟給我們提供的Membership機制了,因為您的Role不可能是平白無故有的,而是存在于對應的數據庫中的,這個我在另 一篇博客中提到過就不多說了。

自定義ActionFilter

有時候這樣的認證或許您還不能夠滿足,或者說您覺得不夠靈活,那么也沒有關系,Asp.Net MVC是允許您自定義ActionFilter的。例如我現在自定義身份認證:

復制代碼
using System;   
using System.Collections.Generic;   
using System.Linq;   
using System.Web;   
using System.Web.Mvc;   
using System.Web.Security;    namespace FormFormsAuthenticationMvc   
{   public class RequiresAuthenticationAttribute:ActionFilterAttribute   {   public override void  OnActionExecuting(ActionExecutingContext filterContext)   {   if (!filterContext.HttpContext.User.Identity.IsAuthenticated)   {   string returnUrl = filterContext.HttpContext.Request.Url.AbsolutePath;   string redirectUrl = string.Format("?ReturnUrl={0}", returnUrl);   string loginUrl = FormsAuthentication.LoginUrl + redirectUrl;   filterContext.HttpContext.Response.Redirect(loginUrl, true);   }   }    }   
}
復制代碼

如果需要進行用戶管理,我再定義角色相關的Filter:

復制代碼
using System;    
using System.Collections.Generic;    
using System.Linq;    
using System.Web;    
using System.Web.Mvc;    
using System.Web.Security;    namespace MvcApplication1.MyClass    
{    public class RequiresRoleAttribute:ActionFilterAttribute    {    public string Role { get; set; }    public override void OnActionExecuting(ActionExecutingContext filterContext)    {    if (!string.IsNullOrEmpty(Role))    {    if (!filterContext.HttpContext.User.Identity.IsAuthenticated)    {    string returnUrl = filterContext.HttpContext.Request.Url.AbsolutePath;    string redirectUrl = string.Format("?ReturnUrl={0}", returnUrl);    string loginUrl = FormsAuthentication.LoginUrl + redirectUrl;    filterContext.HttpContext.Response.Redirect(loginUrl, true);    }    else{    bool isAuthenticated = filterContext.HttpContext.User.IsInRole(Role);    if (!isAuthenticated)    {    throw new UnauthorizedAccessException("You have no right to view the page!");    }    }    }    else{    throw new InvalidOperationException("No Role Specified!");    }    }    }    
}
復制代碼

其實您會發現上面兩個Attribute其實MVC自帶的Authorized已經解決了,這里主要告訴大家如果有需要您是可以擴展的。

好了,今天就到這里吧!源代碼下載:FormFormsAuthenticationMvc

?

ASP.NET MVC 建立 ASP.NET 基礎之上,很多 ASP.NET 的特性(如窗體身份驗證、成員資格)在 MVC 中可以直接使用。本文旨在提供可參考的代碼,不會涉及這方面太多理論的知識。

本文僅使用 ASP.NET 的窗體身份驗證,不會使用它的 成員資格(Membership) 和 角色管理 (RoleManager),原因有二:一是不靈活,二是和 MVC 關系不太。

一、示例項目

image

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");}elseModelState.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");}elseModelState.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) { /**/}/**/
}
復制代碼

轉載于:https://www.cnblogs.com/huangzelin/p/10613301.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/279808.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/279808.shtml
英文地址,請注明出處:http://en.pswp.cn/news/279808.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

面試問題總結

面試了兩家公司&#xff0c;第一家沒有筆試直接面試&#xff0c;第二家筆試面試&#xff0c;將記得住的問題記錄下來&#xff0c;答案自己找的&#xff0c;有好的答案歡迎提出。 1、響應式布局 一家公司問了em和rem的區別&#xff0c;另一家公司先問了一下px,em,rem的區別&…

WPF-23 基于Timer任務調度

.NET的FCL中提供了幾個計時器&#xff0c;大多數初學者都不清楚他們有什么不同&#xff0c;那我們這節來剖解一下每個計時器的本質&#xff1a;1.System.Threading.Timer如果在一個線程池上執行一個定時的周期性的后臺線程任務他是最好的選擇&#xff0c;這個類是和線程池相關聯…

在.NET中不安裝Office使用EPPlus生成帶圖表(Chart)的Excel報表

在開發.NET應用中可能會遇到需要生成帶圖表(Chart)的Excel報表的需求&#xff0c;特別是在一些ASP.NET網站中&#xff0c;有時候我們并不能保證Web服務器上一定安裝了Office組件&#xff0c;所以使用微軟的Office來生成Excel并不保證在所有情況下都使用&#xff0c;有時候即使W…

facebook 邀請好友_如何在Facebook上與某人解除好友

facebook 邀請好友It’s very easy for your Facebook News Feed to get cluttered. After a few years adding ukulele playing magicians you meet wandering the street and the bar staff at every bar you go to regularly, it gets overrun with people you’ll never se…

mac下npm/node的安裝和卸載、升級;node、npm升級后最后刪掉node_modules重新安裝

mac還是使用brew install簡單一些&#xff1b;最好使用一種安裝方式&#xff0c;不要多種方式互用&#xff1b; 更新npm到最新版本npm install -g npm更新npm到指定版本 npm -g install npm2.9.1指定安裝目錄npm install --prefix /usr/local -g npm 1、從官網https://nodejs.o…

軟件工程小組第三次正式會議

會議主題&#xff1a;主要確定數據庫具體內容與會時間&#xff1a;3月29日與會地點&#xff1a;圖書館小組研究室雨水612與會成員&#xff1a;尚卓燃、張世豪、王昊鈺、傅宇豪會議記錄&#xff1a; 小組成員一起討論數據庫&#xff0c;確定了數據庫中的實體、屬性、聯系&#…

Edison的2022年終總結

大家好&#xff0c;我是Edison。2022年即將結束&#xff0c;又到了做年終總結的時候&#xff0c;它是我每年的一個習慣&#xff0c;意味著又要開始新的征途&#xff0c;在開始新的征途之前回顧一下很有必要。艱難抉擇&#xff1a;從互聯網到制造業今年最大的變化就是又換了份工…

JNI

配置NDK&#xff0c;調用JNI最終會生成一個so庫&#xff0c;如果so庫生成了。直接在項目中使用so庫即可調用本地方法。注意&#xff1a;api的包名要與so庫定義的包名一致。 1什么是jni jni java native interface java本地開發接口&#xff0c;是JAVA和C互相調用的橋梁。 2jni有…

dvd vlc 復制_如何使用VLC翻錄DVD

dvd vlc 復制There are many ways to rip a DVD to your computer, but if you’re looking for the most straightforward option, VLC is easy and free. Besides, you probably already have VLC on your computer (and if you don’t, you should). Here, we’ll show you …

新年芯事 | 龍芯物聯網主控芯片龍芯1C102和龍芯1C103流片成功

前言近期&#xff0c;龍芯中科面向物聯網領域研制的主控芯片--龍芯1C102和龍芯1C103流片成功&#xff0c;兩款微控制器芯片各項功能測試正常&#xff0c;符合設計預期。 龍芯1C102主要面向智能家居以及其他物聯網設備詳細介紹龍芯1C102采用龍芯LA132處理器核心&#xff0c;是一…

Javascript基礎學習20問(二)

1.函數&#xff08;方法&#xff09;&#xff1a;封裝執行一項專門任務的步驟的代碼序列--》重用2.參數&#xff1a;方法內獨有的變量&#xff0c;接受傳入數據&#xff0c;在方法中處理3.作用域&#xff1a;一個變量的可用范圍 全局作用域&#xff1a;全局變量 局部作用…

Thrift第三課 編寫腳本

警告 盡量使用tutorial下面的模板&#xff0c;注意腳本的格式&#xff0c;否則生成錯誤 使用thrift-0.9.0生成C/csharp代碼 使用的指令如下: thrift-0.9.0.exe --gen cpp thriftcom.thrift thrift-0.9.0.exe --gen csharp thriftcom.thrift 1 注釋 有如下的三種方式 1&#xff…

【加更】搭建基于chatgpt的釘釘聊天機器人

應某些小伙伴的加更請求&#xff0c;出一期基于釘釘上的聊天機器人&#xff0c;我順便加更一期&#xff0c;搭建一個釘釘聊天機器人的小教程。首先進入到釘釘開放平臺的后臺管理系統&#xff1a;https://open.dingtalk.com/進入到 應用開發->企業內部開發->機器人右上角選…

word中 有注釋標簽嗎_如何在Word中注釋圖像

word中 有注釋標簽嗎If you’re writing a document that includes images, you may want to add annotations to those images to clarify what they represent. You can add callouts to your images to point out particular parts of the image and add text to describe t…

Lang.String

StringBuilder 原文&#xff1a; public final class StringBuilder extends Object implements Serializable, CharSequence A mutable sequence of characters. This class provides an API compatible with StringBuffer, but with no guarantee of synchronization. This c…

牛客網暑期ACM多校訓練營(第二場)J farm (二維樹狀數組)

題目鏈接&#xff1a; https://www.nowcoder.com/acm/contest/140/J 思路&#xff1a; 都寫在代碼注釋里了&#xff0c;非常好懂。。 for_each函數可以去看一下&#xff0c;遍歷起vector數組比較方便&#xff0c;用for(int i 0;i < q[i].size();i)的話&#xff0c;是會有一…

微軟IE 9 Beta全程體驗圖集

微軟剛剛更新了IE 9 Beta的新頁面&#xff0c;此次發布的Beta版本一共有27個國家的語言&#xff0c;其中也包括了簡體中文和香港和臺灣的繁體中文版。 點擊此處進入下載頁面&#xff1a; http://windows.microsoft.com/zh-CN/internet-explorer/download/ie-9/worldwide IE9的熱…

.net core中Quartz的使用方法

我們在日常開發中&#xff0c;總會遇到這樣的需求&#xff1a;每隔一段時間&#xff0c;執行一次某個任務。固定某個時間執行任務&#xff0c;例如凌晨12點對當天的數據進行統計。每個月的第幾天&#xff0c;執行某個任務。Quartz.Net是根據Java的Quartz用C#改寫而來&#xff0…

AspectJ學習筆記

介紹 AspectJ是一個基于Java語言的AOP框架Spring2.0以后新增了對AspectJ切點表達支持AspectJ是AspectJ1.5新增功能&#xff0c;通過JDK5注解技術&#xff0c;允許Bean類中定義切面&#xff0c;新版本Spring框架&#xff0c;建議使用AspectJ方式來開發AOP主要用途&#xff1a;自…

windows10訪客_如何在Windows 10中創建訪客帳戶

windows10訪客If you find that your guests are asking fairly often to use your computer temporarily to check their email or look something up on the web, you don’t have to let them use your personal account or create a special account for each guest. 如果發…