一、什么是身份验证和授权
人们有时对用户身份验证和用户授权之间的区别感到疑惑。用户身份验证是指通过某种形式的登录机制(包括用户名/密码、OpenID、OAuth等说明身份的项)来核实用户的身份。授权验证是用来核实登录站点的用户是否在他们所具有的权限内执行操作,这通常使用一些基于角色或者基于声明的系统来实现。
二、AuthorizeAttribute的使用
1、MVC5只要将属性[Authorize]置于相关的action之前就行,那么在调用Buy action之前,就会运用Authorize过滤器。
[Authorize] public ActionResult Index(int id) { //其它相关逻辑代码放在这里 }
2、MVC5将属性[Authorize]置于整个Controller之上。这样位于此控制器下的所有action就都运用了此过滤器。
[Authorize] public class HomeController:Controller { public active Index { } //其他action }
3、MVC5将Authorize应用到全部的应用程序的范围内,要使AuthorizeAttribute成为全局过滤器,只要将其加入全局过滤器集合RegisterGlobalFilters方法。
对于大部分网站而言,基本上整个应用程序都需要身份验证,当然我们不可能在每个控制器上添加Authorize特性。此时,把AuthorizeAttribute配置为全局过滤器,并使用AllowAnonymous特性来允许匿名访问某些控制器或方法。修改App_Start/FilterConfig.cs文件中的RegisterGlobalFilters方法:
public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new AuthorizeAttribute()); filters.Add(new HandleErrorAttribute()); }
(1)注意,在LoginController中的Login方法,系统已经帮我们添加了AllowAnonymous特性,不然是无法正常登陆的。
[AllowAnonymous] public ActionResult Login(string returnUrl) { return View(); }
(2)全局控制器的应用只适用于MVC的Controller和Action,对于Web Forms,静态页面,和其它的HTTP handlers 都不适用。
三、重写(扩展)授权过滤器
扩展授权过滤器可以定义继承自AuthorizeAttribute的类,也可以定义同时继承自FilterAttribute, IAuthorizationFilter接口的类。
//预定义特性 AttributeUsage 描述了如何使用一个自定义特性类。它规定了特性可应用到的项目的类型。 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)] public class AuthorizeAttribute : FilterAttribute, IAuthorizationFilter {
//重写时,提供一个入口点用于进行自定义授权检查 // 返回结果: 如果用户已经过授权,则为 true;否则为 false。 // 异常:System.ArgumentNullException:httpContext 参数为 null。 protected virtual bool AuthorizeCore(HttpContextBase httpContext); //处理未能授权的 HTTP 请求。 protected virtual void HandleUnauthorizedRequest(AuthorizationContext filterContext); //在过程请求授权时调用。 // 异常: System.ArgumentNullException: //filterContext 参数为 null。 public virtual void OnAuthorization(AuthorizationContext filterContext); }
AuthorizeAttribute提供了三个可重新的虚方法AuthorizeCore,HandleUnauthorizedRequest,OnAuthorization,那么在执行授权动作的过程中他们是如何被调用的呢?看下源码的OnAuthorization方法,发现在这个方法中先调用AuthorizeCore,然后调用HandleUnauthorizedRequest被调用了。
public void OnAuthorization(AuthorizationContext filterContext) { if (filterContext == null) { throw new ArgumentNullException("filterContext"); } //如果子操作的缓存处于活动状态,那么就抛出异常 if (OutputCacheAttribute.IsChildActionCacheActive(filterContext)) { throw new InvalidOperationException(MvcResources.AuthorizeAttribute_CannotUseWithinChildActionCache); } //判断控制器或控制器操作是否允许匿名访问,如果可以就return bool skipAuthorization = filterContext.ActionDescriptor.IsDefined(typeof(AllowAnonymousAttribute), inherit: true)|| filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(AllowAnonymousAttribute), inherit: true); if (skipAuthorization) { return; } //进行权限验证 if (AuthorizeCore(filterContext.HttpContext)) { HttpCachePolicyBase cachePolicy = filterContext.HttpContext.Response.Cache; cachePolicy.SetProxyMaxAge(new TimeSpan(0)); cachePolicy.AddValidationCallback(CacheValidateHandler, null /* data */); } else {//处理未通过权限验证的情形 HandleUnauthorizedRequest(filterContext); } }
源码下载https://github.com/qiuxianhu/SimpleLoginAuthorization