MVC过滤器之添加LoginAttribute,浏览器提示:重定向次数太多
以前在写登录Action过滤时,都在每个Controller前写上CheckLoginAttribute;这次决定偷懒试一下能否将所有Action和Controller统一过滤;
开始代码是这样式儿的:
1.新建一个特性类,继承ActionFilterAttribute,在Action执行前判断是否有登录记录Session,则在OnActionExecuting(ActionExecutingContext filterContext)中判断未登录,则返回登录界面;
1 public class LoginAttribute:ActionFilterAttribute 2 { 3 4 public override void OnActionExecuting(ActionExecutingContext filterContext) 5 { 6 base.OnActionExecuting(filterContext); 7 8 if (filterContext.HttpContext.Session["useruid"] == null) 9 { 10 filterContext.Result = new RedirectResult("/Home/Login"); 11 return; 12 } 13 14 } 15 }
2.在App_Start文件夹里的FilterConfig.cs,添加LoginAttribute
1 public class FilterConfig 2 { 3 public static void RegisterGlobalFilters(GlobalFilterCollection filters) 4 { 5 filters.Add(new HandleErrorAttribute()); 6 filters.Add(new LoginAttribute());//新增登录特性 7 } 8 }
运行后,网页如下图,清除cookie完全无效。
查找问题原因:单步调试后,发现RegisterGlobalFilters中的filters.Add(new LoginAttribute()) 和 LoginAttribute中的RedirectResult,都会执行多次,次数和什么有关呢?
在运行到LoginAttribute前,曾经在定义Controller的依赖注入UnityContainer里晃了一圈,重复执行RedirectResult的次数和容器注入的类数有关,先执行到依赖注入再执行到OnActionExecuting,应该是在Action操作之前,先对所有Controller依赖构造器接口进行初始化操作,初始化操作涉及到各个Controller。
再看RegisterGlobalFilters初始化是属于Global.asax.cs,用于对全局文件配置的,在每执行一次Controller中的Action,都会执行一次LoginAttribute。于是初始化所有Controller依赖注入接口期间,有触发LoginAttribute。RouteConfig配置Home\Login为默认启动Action。所以,在启动Home\Login后,在初始化Controller的依赖注入后会连续多次执行RedirectResult(“/Home/Login“”),导致程序并没报错,而浏览器崩溃。
于是这样改了试试:
1 public override void OnActionExecuting(ActionExecutingContext filterContext) 2 { 3 base.OnActionExecuting(filterContext); 4 5 //增加对初始化/Home/Login判定,直接跳出,避免多次执行RedirectResult 6 string url = filterContext.HttpContext.Request.Url.ToString(); 7 if (url.IndexOf("Home") > 0&&url.IndexOf("Login")>0) 8 { 9 return; 10 } 11 //增加部分到此结束 12 13 if (filterContext.HttpContext.Session["useruid"] == null) 14 { 15 filterContext.Result = new RedirectResult("/Home/Login"); 16 return; 17 } 18 }
然后暂时解决了。在各位大神帮忙指正下,添加标签的方式然后根据标签判断,比判断关键字符串,更便于扩展维护。
最后代码如下:
1 public class LoginAttribute:ActionFilterAttribute 2 { 3 4 public override void OnActionExecuting(ActionExecutingContext filterContext) 5 { 6 //判断Action描述标签中是否有AllowAnonymous特性 7 if(filterContext.ActionDescriptor.IsDefined(typeof(AllowAnonymousAttribute), inherit: true)) 8 { 9 return; 10 } 11 12 if (filterContext.HttpContext.Session["useruid"] == null) 13 { 14 filterContext.Result = new RedirectResult("/Home/Login"); 15 return; 16 } 17 base.OnActionExecuting(filterContext); 18 19 } 20 }