• ASP.NET MVC5(五):身份验证、授权


    使用Authorize特性进行身份验证


      通常情况下,应用程序都是要求用户登录系统之后才能访问某些特定的部分。在ASP.NET MVC中,可以通过使用Authorize特性来实现,甚至可以对整个应用程序全局使用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特性禁止匿名用户访问控制器或方法。同样的,我们也可以使用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);
        }
  • 相关阅读:
    hdu3457(有向图的dp问题)
    nyoj16矩形嵌套(第一道dp关于dag的题目)
    noj1475(递推题)统计多少个1
    hdu1331(记忆化搜索)
    hdu1142(dj+记忆化搜索)
    hdu1978(记忆化搜索)
    用广搜实现的spfa
    hdu1428(记忆化搜索)
    hdu1078(记忆化搜索)
    poj3261(后缀数组)
  • 原文地址:https://www.cnblogs.com/yujihaia/p/7367559.html
Copyright © 2020-2023  润新知