ASP.NET MVC Custom Authorization

前端 未结 3 700
孤城傲影
孤城傲影 2020-12-22 18:51

I have a question about custom authorization in MVC.

I have a site that I want to limit access to certain pages, depending on their group membership. Now I have see

相关标签:
3条回答
  • 2020-12-22 19:12

    My answer isn't great, because it kills unit testing, but I'm pulling values from System.Web.HttpContext.Current.Session. The singleton is available throughout the project. By saving the current user in session, you can get to it from anywhere, including utility classes like AuthorizeAttribute.

    I'd love to see a unit-testable solution, though.

    0 讨论(0)
  • 2020-12-22 19:20

    The AuthorizationContext (parameter to OnAuthorize) provides access to the Controller, RouteData, HttpContext, etc. You should be able to use these in a custom authorization filter to do what you want. Below is a sample of code from a RoleOrOwnerAttribute derived from AuthorizeAttribute.

    public override void OnAuthorization( AuthorizationContext filterContext )
    {
        if (filterContext == null)
        {
            throw new ArgumentNullException( "filterContext" );
        }
    
        if (AuthorizeCore( filterContext.HttpContext )) // checks roles/users
        {
            SetCachePolicy( filterContext );
        }
        else if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
        {
            // auth failed, redirect to login page
            filterContext.Result = new HttpUnauthorizedResult();
        }
        // custom check for global role or ownership
        else if (filterContext.HttpContext.User.IsInRole( "SuperUser" ) || IsOwner( filterContext ))
        {
            SetCachePolicy( filterContext );
        }
        else
        {
            ViewDataDictionary viewData = new ViewDataDictionary();
            viewData.Add( "Message", "You do not have sufficient privileges for this operation." );
            filterContext.Result = new ViewResult { MasterName = this.MasterName, ViewName = this.ViewName, ViewData = viewData };
        }
    
    }
    
    // helper method to determine ownership, uses factory to get data context,
    // then check the specified route parameter (property on the attribute)
    // corresponds to the id of the current user in the database.
    private bool IsOwner( AuthorizationContext filterContext )
    {
        using (IAuditableDataContextWrapper dc = this.ContextFactory.GetDataContextWrapper())
        {
            int id = -1;
            if (filterContext.RouteData.Values.ContainsKey( this.RouteParameter ))
            {
                id = Convert.ToInt32( filterContext.RouteData.Values[this.RouteParameter] );
            }
    
            string userName = filterContext.HttpContext.User.Identity.Name;
    
            return dc.Table<Participant>().Where( p => p.UserName == userName && p.ParticipantID == id ).Any();
        }
    }
    
    
    protected void SetCachePolicy( AuthorizationContext filterContext )
    {
        // ** 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 */);
    }
    
    0 讨论(0)
  • 2020-12-22 19:24

    If the authorization is really that dynamic, I would handle it in the controller. I have one action where I do this - you can return a HttpUnauthorizedResult to redirect to the login page or you can show a custom error in your view.

    I don't the default redirect to the login page when somebody is already logged in, but not in the correct role. That's very confusing for the user.

    0 讨论(0)
提交回复
热议问题