通常情况下,应用程序都是要求用户登录系统之后才能访问某些特定的部分。在 ASP.NET MVC 中,可以通过使用 Authorize 特性来实现,甚至可以对整个应用程序全局使用 Authorize 特性。
本节以一个添加产品的示例来说明 Authorize 的使用方法。首先,创建 Product 类、添加属性(如下所示)并创建 ProductsController(MVC5 Controller with views,using Entity Framework)。
- public class Product {
- //产品编号
- public int Id {
- get;
- set;
- }
- //产品名称
- public string ProductName {
- get;
- set;
- }
- //产品描述
- public string Description {
- get;
- set;
- }
- //产品价格
- public decimal Price {
- get;
- set;
- }
- }
运行程序,将 Url 定位到 / Products/Create,添加如下产品。
此时收到用户需求,必须是已经登录的用户才可以添加产品,如匿名用户请求访问产品创建页面,则直接定位到登录界面。修改 ProdutsController,只需要在 Create 动作上添加 Authorize 特性。
- [Authorize]
- public ActionResult Create()
- {
- return View();
- }
这时,我们在未登录状态下请求访问产品创建页面时,系统自动跳转到登录页面。下面,我们来看一看 Authorize 特性的的工作原理。当用户请求一个 Action 时,会调用 OnAuthorization 方法:
- public virtual void OnAuthorization(AuthorizationContext filterContext)
- {
- if (filterContext == null)
- {
- throw new ArgumentNullException("filterContext");
- }
- if (OutputCacheAttribute.IsChildActionCacheActive(filterContext))
- {
- // If a child action cache block is active, we need to fail immediately, even if authorization
- // would have succeeded. The reason is that there's no way to hook a callback to rerun
- // authorization before the fragment is served from the cache, so we can't guarantee that this
- // filter will be re-run on subsequent requests.
- throw new InvalidOperationException(MvcResources.AuthorizeAttribute_CannotUseWithinChildActionCache);
- }
- bool skipAuthorization = filterContext.ActionDescriptor.IsDefined(typeof(AllowAnonymousAttribute), inherit: true)
- || filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(AllowAnonymousAttribute), inherit: true);
- if (skipAuthorization)
- {
- return;
- }
- if (AuthorizeCore(filterContext.HttpContext))
- {
- // ** IMPORTANT **
- // Since we're performing authorization at the action level, the authorization code runs
- // after the output caching module. In the worst case this could allow an authorized user
- // to cause the page to be cached, then an unauthorized user would later be served the
- // cached page. We work around this by telling proxies not to cache the sensitive page,
- // then we hook our custom authorization code into the caching mechanism so that we have
- // the final say on whether a page should be served from the cache.
- HttpCachePolicyBase cachePolicy = filterContext.HttpContext.Response.Cache;
- cachePolicy.SetProxyMaxAge(new TimeSpan(0));
- cachePolicy.AddValidationCallback(CacheValidateHandler, null /* data */);
- }
- else
- {
- HandleUnauthorizedRequest(filterContext);
- }
- }
skipAuthorization 代表是否跳过验证,如果 Action 或 Controller 定义了 AllowAnonymous 特性,则跳过验证。若不跳过验证,则会判断 AuthorizeCore 方法的执行结果,再来看看 AuthorizeCore 方法的源码:
- protected virtual bool AuthorizeCore(HttpContextBase httpContext)
- {
- if (httpContext == null)
- {
- throw new ArgumentNullException("httpContext");
- }
- IPrincipal user = httpContext.User;
- if (!user.Identity.IsAuthenticated)
- {
- return false;
- }
- if (_usersSplit.Length > 0 && !_usersSplit.Contains(user.Identity.Name, StringComparer.OrdinalIgnoreCase))
- {
- return false;
- }
- if (_rolesSplit.Length > 0 && !_rolesSplit.Any(user.IsInRole))
- {
- return false;
- }
- return true;
- }
如果用户没有登录,则返回 False;如果用户组长度大于 0 且不包括当前用户,则返回 False;如果授权角色长度大于 0 且不包含当前用户,返回 False;否则返回 True 。
- ★Authorize特性不仅可以用在Action上,同样可以使用在Controller上
对于大部分网站而言,基本上整个应用程序都需要身份验证,当然我们不可能在每个控制器上添加 Authorize 特性。此时,把 AuthorizeAttribute 配置为全局过滤器,并使用 AllowAnonymous 特性来允许匿名访问某些控制器或方法。修改 App_Start/FilterConfig.cs 文件中的 RegisterGlobalFilters 方法:
- public static void RegisterGlobalFilters(GlobalFilterCollection filters)
- {
- filters.Add(new AuthorizeAttribute());
- filters.Add(new HandleErrorAttribute());
- }
注意,在 AccountController 中的 Login 方法,系统已经帮我们添加了 AllowAnonymous 特性,不然是无法正常登陆的。
- [AllowAnonymous]
- public ActionResult Login(string returnUrl)
- {
- ViewBag.ReturnUrl = returnUrl;
- return View();
- }
目前为止,已经介绍了使用 Authorize 特性禁止匿名用户访问控制器或方法。同样的,我们也可以使用 Authorize 特性来限定特定用户或角色的访问。上一节中的示例,新增只有 Administrator 角色用户才能够编辑产品的功能。
- [Authorize(Roles ="Administrator")]
- public ActionResult Edit(int? id)
- {
- if (id == null)
- {
- return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
- }
- Product product = db.Products.Find(id);
- if (product == null)
- {
- return HttpNotFound();
- }
- return View(product);
- }
当然,我们也可以通过指定用户的方式来限定访问:
- [Authorize(Users = "Jack,Mike,July")]
- public ActionResult Edit(int? id)
- {
- if (id == null)
- {
- return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
- }
- Product product = db.Products.Find(id);
- if (product == null)
- {
- return HttpNotFound();
- }
- return View(product);
- }
来源: http://www.cnblogs.com/Answer-Geng/p/7074094.html