NET MVC5 Brief Introduction to Filter and AuthorizeAttribute Authentication

Keywords: ASP.NET Session Attribute IIS encoding

In webform, the process of validation is roughly as follows:

 

 

In AOP:

 

 

In Filter:

 

 

AuthorizeAttribute permission validation

After login, you have the right to control. Some pages need user login to access. You need to add a validation to the visiting pages, and you can't use every action once.

1. Write a Custom Authorization Attribute, inherit from Authorization Attribute, rewrite the OnAuthorization method, and write the logic as its own.

2. Method registration and controller registration.

3. With global registration, all action s of the controllers are in effect.

But in this, first of all, to verify the login home page, the home page does not have Deng Li, ran to the login page, but the login page also has to follow the logic in the features, and redirect to Deng Li... The cycle...

Here's an AlloAnonymous tag. This tag can solve the problem of this loop. Anonymous support does not require login, but it's useless to add features alone. In fact, it's also possible to support verification, even to customize a feature. This feature is empty, just for use. Make a mark.

The scope of use of features, we hope that the characteristics are universal, in different systems, different address login, =="add a parameter constructor on the features.

 public class CustomAllowAnonymousAttribute : Attribute
 {
 }

CustomAuthorAttribute class

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
    private Logger logger = new Logger(typeof(CustomAuthorizeAttribute));
    private string _LoginUrl = null;
    public CustomAuthorizeAttribute(string loginUrl = "~/Home/Login")
    {
        this._LoginUrl = loginUrl;
    }
    //public CustomAuthorizeAttribute(ICompanyUserService service)
    //{
    //}
    //No way


    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        var httpContext = filterContext.HttpContext;//Can get httpcontext You can do whatever you want.

        if (filterContext.ActionDescriptor.IsDefined(typeof(CustomAllowAnonymousAttribute), true))
        {
            return;
        }
        else if (filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(CustomAllowAnonymousAttribute), true))
        {
            return;
        }
        else if (httpContext.Session["CurrentUser"] == null
            || !(httpContext.Session["CurrentUser"] is CurrentUser))//It's empty.
        {
            //Here's the user. With the address, you can actually check the permissions.
            if (httpContext.Request.IsAjaxRequest())
                //httpContext.Request.Headers["xxx"].Equals("XMLHttpRequst")
            {
                filterContext.Result = new NewtonJsonResult(
                    new AjaxResult()
                    {
                        Result = DoResult.OverTime,
                        DebugMessage = "Landing overdue",
                        RetValue = ""
                    });
            }
            else
            {
                httpContext.Session["CurrentUrl"] = httpContext.Request.Url.AbsoluteUri;
                filterContext.Result = new RedirectResult(this._LoginUrl);
                //Shorter: specified Result,Then the request is closed and will not be executed. action
            }
        }
        else
        {
            CurrentUser user = (CurrentUser)httpContext.Session["CurrentUser"];
            //this.logger.Info($"{user.Name}Logged on to the system");
            return;//Continue
        }
        //base.OnAuthorization(filterContext);
    }
}

Filter Effective Mechanism

Why add a tag, inherit AuthorizeAttribute, and rewrite the OnAuthorization method? Controller has been instantiated, call ExecuteCore method, find method name, Controller Action Invokee. InvokeAction, find all Filter features, InvokeAuthorize - result is not empty, direct InvokeAction Result, empty normal execution of action.

There is an instance type and a method name that you want to reflect on.

After finding the method, before executing the method, the characteristics can be detected, from the global, from the controller, from the method. Spread characteristics, characteristics are predefined by themselves, according to class implementation, set a logo, as empty as normal, not empty jump, normal continue to implement.

Filter Principle and AOP Face-Oriented Programming

Filter is an implementation of AOP. In fact, there is an InvokeAction method in the ControllerActionInvoke class. After controller instantiation, before and after ActionInvoke, AOP is achieved by detecting predefined filter and executing it.

Here is the source code for InvokeAction:

public virtual bool InvokeAction(ControllerContext controllerContext, string actionName)
        {
            if (controllerContext == null)
            {
                throw new ArgumentNullException("controllerContext");
            }
            if (string.IsNullOrEmpty(actionName) && !controllerContext.RouteData.HasDirectRouteMatch())
            {
                throw new ArgumentException(MvcResources.Common_NullOrEmpty, "actionName");
            }
            ControllerDescriptor controllerDescriptor = this.GetControllerDescriptor(controllerContext);
            ActionDescriptor actionDescriptor = this.FindAction(controllerContext, controllerDescriptor, actionName);
            if (actionDescriptor != null)
            {
                FilterInfo filters = this.GetFilters(controllerContext, actionDescriptor);
                try
                {
                    AuthenticationContext authenticationContext = this.InvokeAuthenticationFilters(controllerContext, filters.AuthenticationFilters, actionDescriptor);
                    if (authenticationContext.Result != null)
                    {
                        AuthenticationChallengeContext authenticationChallengeContext = this.InvokeAuthenticationFiltersChallenge(controllerContext, filters.AuthenticationFilters, actionDescriptor, authenticationContext.Result);
                        this.InvokeActionResult(controllerContext, authenticationChallengeContext.Result ?? authenticationContext.Result);
                    }
                    else
                    {
                        AuthorizationContext authorizationContext = this.InvokeAuthorizationFilters(controllerContext, filters.AuthorizationFilters, actionDescriptor);
                        if (authorizationContext.Result != null)
                        {
                            AuthenticationChallengeContext authenticationChallengeContext2 = this.InvokeAuthenticationFiltersChallenge(controllerContext, filters.AuthenticationFilters, actionDescriptor, authorizationContext.Result);
                            this.InvokeActionResult(controllerContext, authenticationChallengeContext2.Result ?? authorizationContext.Result);
                        }
                        else
                        {
                            if (controllerContext.Controller.ValidateRequest)
                            {
                                ControllerActionInvoker.ValidateRequest(controllerContext);
                            }
                            IDictionary<string, object> parameterValues = this.GetParameterValues(controllerContext, actionDescriptor);
                            ActionExecutedContext actionExecutedContext = this.InvokeActionMethodWithFilters(controllerContext, filters.ActionFilters, actionDescriptor, parameterValues);
                            AuthenticationChallengeContext authenticationChallengeContext3 = this.InvokeAuthenticationFiltersChallenge(controllerContext, filters.AuthenticationFilters, actionDescriptor, actionExecutedContext.Result);
                            this.InvokeActionResultWithFilters(controllerContext, filters.ResultFilters, authenticationChallengeContext3.Result ?? actionExecutedContext.Result);
                        }
                    }
                }
                catch (ThreadAbortException)
                {
                    throw;
                }
                catch (Exception exception)
                {
                    ExceptionContext exceptionContext = this.InvokeExceptionFilters(controllerContext, filters.ExceptionFilters, exception);
                    if (!exceptionContext.ExceptionHandled)
                    {
                        throw;
                    }
                    this.InvokeActionResult(controllerContext, exceptionContext.Result);
                }
                return true;
            }
            return false;
        }

HandleErrorAttribute for Global Exception Handling

Suggestions on exception handling:

1. Avoid the UI layer seeing exceptions directly, try-catch in each controller? Isn't it too much trouble?

2. At this time, AOP comes on the scene. HandleErrorAttribute writes its own feature, inherits HandleErrorAttribute, rewrites OnException, and jumps to this method after an exception occurs.

On this side, we must

 public class CustomHandleErrorAttribute : HandleErrorAttribute
 {
     private Logger logger = new Logger(typeof(CustomHandleErrorAttribute));

     /// <summary>
     /// After the exception occurs, jump to this method
     /// </summary>
     /// <param name="filterContext"></param>
     public override void OnException(ExceptionContext filterContext)
     {
         var httpContext = filterContext.HttpContext;//"Do as one pleases"
         if (!filterContext.ExceptionHandled)//No other HandleErrorAttribute Handle
         {
             this.logger.Error($"In response {httpContext.Request.Url.AbsoluteUri} When an exception occurs, information:{filterContext.Exception.Message}");//
             if (httpContext.Request.IsAjaxRequest())
             {
                 filterContext.Result = new NewtonJsonResult(
                 new AjaxResult()
                 {
                     Result = DoResult.Failed,
                     DebugMessage = filterContext.Exception.Message,
                     RetValue = "",
                     PromptMsg = "An error occurred. Please contact the administrator."
                 });
             }
             else
             {
                 filterContext.Result = new ViewResult()//Short circuiting device
                 {
                     ViewName = "~/Views/Shared/Error.cshtml",
                     ViewData = new ViewDataDictionary<string>(filterContext.Exception.Message)
                 };
             }
             filterContext.ExceptionHandled = true;//It's been dealt with by me.
         }
     }
 }

This is the address to be redirected:

 

 

Be sure to consider whether Ajax requests

 

 

 

 

 

Can you enter custom exceptions in a variety of exceptions?

1. Action exception, not Catch

2. Action exception, Catch

3. Action calls Service exceptions

4. Action Normal View Abnormal

5. Controller construction is abnormal

6. Action name error

7. Arbitrary Address Error

8. Permission Filter exception

Answer:

1.

2. No

3. Yes, abnormal bubbling

4. Yes, why? Because Execute Result is wrapped in try

5. No. Filter is done before the method executes after the control is constructed.

6. No, because requests do not enter the MVC process.

7. No, because requests are not entered into MVC

8. Yes, the permission Filter is also in try.

What about these uncovered anomalies? There's another way.

Add an event to Global

 public class MvcApplication : System.Web.HttpApplication
 {
     private Logger logger = new Logger(typeof(MvcApplication));
     protected void Application_Start()
     {
         AreaRegistration.RegisterAllAreas();//Registering area
         FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);//Registered Global Filter
         RouteConfig.RegisterRoutes(RouteTable.Routes);//Registration routing
         BundleConfig.RegisterBundles(BundleTable.Bundles);//Merge Compression, Packaging Tool Combres
         ControllerBuilder.Current.SetControllerFactory(new ElevenControllerFactory());

         this.logger.Info("The website is launched...");
     }
     /// <summary>
     /// Global exception handling can catch the fish out of the net
     /// </summary>
     /// <param name="sender"></param>
     /// <param name="e"></param>
     protected void Application_Error(object sender, EventArgs e)
     {
         Exception excetion = Server.GetLastError();
         this.logger.Error($"{base.Context.Request.Url.AbsoluteUri}Abnormal");
         Response.Write("System is Error....");
         Server.ClearError();

         //Response.Redirect
         //base.Context.RewritePath("/Home/Error?msg=")
     }

Handle ErrorAttribute + Application_Error, with different granularity, can get different things

IActionFilter Extended Customization

IActionFilter

1. Before the OnAction Executing method is executed

2. After the OnActionExecuted method is executed

3. Before the OnResultExecuting result is executed

4. After the OnResultExecuted result is executed

Execute the permission Filter first, then the ActionFilter.

Order of execution:

  Global OnActionExecuting

  Controller OnActionExecuting

  Action OnActionExecuting

Action True Execution

  Action OnActionExecuted

  Controller OnActionExecuted

  Global OnActionExecuted

 

 

Effective Order of Registration at Different Locations: Global -"Controller -" Action

It's like a Russian doll, or onion model.

 

 

In the order of registration in the same location, the same location will take effect in the order in which it is registered. There is also a parameter of Order, which does not set the default of Order 1. After setting, it will be executed from small to large.

 

 

 

What can ActionFilter do?

Logging, parameter detection, caching, rewriting view, compression, anti-theft chain, statistical access, different clients jump different pages, current limit...

When the browser requests, it will declare the supported format. The default IIS is not compressed. It detects the supported format, compresses the data in response (completed by the IIS server), adds Content-Encoding to the response header. The browser looks at the data format and decompresses it according to the browser format (whatever you are, all of them are decompressed according to the browser format). Compression can be decompressed), compression is IIS, decompression is browser.

 public class CompressActionFilterAttribute : ActionFilterAttribute
 {
     public override void OnActionExecuting(ActionExecutingContext filterContext)
     {
         //foreach (var item in filterContext.ActionParameters)
         //{
         //    //Sensitive Word Filtering for Parameter Detection
         //}  
         var request = filterContext.HttpContext.Request;
         var respose = filterContext.HttpContext.Response;
         string acceptEncoding = request.Headers["Accept-Encoding"];//Detection Support Format
         if (!string.IsNullOrWhiteSpace(acceptEncoding) && acceptEncoding.ToUpper().Contains("GZIP"))
         {
             respose.AddHeader("Content-Encoding", "gzip");//Response header specifies type
             respose.Filter = new GZipStream(respose.Filter, CompressionMode.Compress);//Compression type specification
         }
     }
 }

 public class LimitActionFilterAttribute : ActionFilterAttribute
 {
     private int _Max = 0;
     public LimitActionFilterAttribute(int max = 1000)
     {
         this._Max = max;
     }
     public override void OnActionExecuting(ActionExecutingContext filterContext)
     {
         string key = $"{filterContext.RouteData.Values["Controller"]}_{filterContext.RouteData.Values["Action"]}";
         //CacheManager.Add(key,) Cache to cache key Collection time  
         filterContext.Result = new JsonResult()
         {
             Data = new { Msg = "Out of frequency" }
         };
     }
 }

 

 

 

 

 

 

What are the limitations of Filter?

Although it is rich, it can only use Action as a unit. Action calls other class libraries internally, and adding operations can not do it! This depends on IOC+AOP extensions.

This article only introduces the Filter filter (permission feature, action, Result, Exception) in. NET Framework MVC. Actually, in. NET Core MVC, ResourceFilter has been added, adding this feature, resource feature, and the three features of Action/Result/Exception have not changed. This will be described in detail later when it is recorded in. NET Core MVC.

 

 

 

 

 

Posted by matthewst on Mon, 23 Sep 2019 08:41:34 -0700