一、自定义权限认证特性 CheckLoginAttribute
基于.net core mvc的验证Session登陆状态
1.新建一个.net core mvc项目
2.在Models文件夹下面添加一个类MyAttribute,专门用来保存我们定义的特性
在这里我只写了CheckLoginAttribute用来验证登陆情况
using Microsoft.AspNetCore.Http;using Microsoft.AspNetCore.Mvc;using Microsoft.AspNetCore.Mvc.Filters;using System;namespace AttributeStudy.Models{ public class MyAttribute { } public class CheckLoginAttribute : Attribute,IActionFilter { public void OnActionExecuted(ActionExecutedContext context)//方法执行后执行 { } public void OnActionExecuting(ActionExecutingContext context)//方法执行前执行 { if(context.HttpContext.Session.GetString("LoginName")==null) { context.Result = new RedirectResult("Contact");//如果不存在这个Session则表示登陆不成功,跳到Contact页面 } else { //否则,不做操作。 } } }}
因为这里不是controller,所以,我们要得使用session得用注入的context来调用
而且,在.Net core使用Sesion还得在Startup添加配置
ConfigureServices下面添加 services.AddSession();Configure下面添加 app.UseSession();
HomeController如下:
using AttributeStudy.Models;using Microsoft.AspNetCore.Http;using Microsoft.AspNetCore.Mvc;using System.Diagnostics;namespace AttributeStudy.Controllers{ public class HomeController : Controller { public IActionResult Index() { return View(); } public void SetSession(int i)//做测试用,添加LogonName这个Session { HttpContext.Session.SetString("LoginName", "123456"); } public void RemoveSession(int i,int j)//做测试用,删除LogonName这个Session { HttpContext.Session.Remove("LoginName"); } [CheckLogin] public IActionResult About() { ViewData["Message"] = "Your application description page."; return View(); } public IActionResult Contact() { ViewData["Message"] = "Your contact page."; return View(); } public IActionResult Error() { return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier }); } }}
这样我们检测登陆特性已经可以演示了,启动后,在网页点击About,会先检执行CheckLoginAttribute的OnActionExecuting做登陆验证。
二、自定义权限认证特性 CustomAuthorizeAttribute
基于.net mvc 的验证Session登陆状态
1.新建一个.net mvc项目
添加控制器Login、并在控制器index右键添加index视图
public class LoginController : Controller { // GET: Login public ActionResult Index() { return View(); } public string Login() { HttpContext.Session["StudyAOPSession"] = "kxy&123"; return "登录成功"; } public string Out() { HttpContext.Session["StudyAOPSession"] = null; return "已退出"; } }
index视图
@{ ViewBag.Title = "Index";}请登录!
@Html.ActionLink("登录", "Login", "Login")@Html.ActionLink("退出", "Out", "Login")
2.新建文件夹CustomAttribute,并添加类 CustomAuthorizeAttribute
public class CustomAuthorizeAttribute: AuthorizeAttribute { // 加上这个特性 会先执行这个函数 public override void OnAuthorization(AuthorizationContext filterContext) { var StudyAOPSession = filterContext.HttpContext.Session["StudyAOPSession"]; // 判断登录Session是否存在、账号密码是否正确(这里只是模拟一下) if (StudyAOPSession == null || !StudyAOPSession.ToString().Equals("kxy&123")) { filterContext.Result = new ViewResult() { ViewName = "~/Views/Login/index.cshtml" }; } } }
这样我们就新建好了一个用来验证登陆的特性
加特性的三个地方
1、Action:方法注册、指定某个方法
2、Controller:控制器注册、指定控制器下面的所有方法
3、FilterConfig:全局注册,在App_Start 里面的 FilterConfig
public class FilterConfig { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new HandleErrorAttribute()); filters.Add(new CustomAuthorizeAttribute());// 我们加的特性 } }
3.允许匿名访问 AllowAnonymous
AllowAnonymous不是添加了就有效,需要在自定义特性判断是否有添加AllowAnonymous,已经添加了就是允许匿名,直接return,不做筛选操作
修改类:CustomAuthorizeAttribute
public class CustomAuthorizeAttribute : AuthorizeAttribute { public override void OnAuthorization(AuthorizationContext filterContext) { if (filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true)) return;//判断控制器是否允许匿名 if (filterContext.ActionDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true)) return;//判断Action是否允许匿名 var StudyAOPSession = filterContext.HttpContext.Session["StudyAOPSession"]; // 判断登录Session是否存在、账号密码是否正确(这里只是模拟一下) if (StudyAOPSession == null || !StudyAOPSession.ToString().Equals("kxy&123")) { filterContext.Result = new ViewResult() { ViewName = "~/Views/Login/index.cshtml" }; } } }
AllowAnonymous特性可以注册在Controller或者Action上面
三、自定义捕捉异常特性 CustomHandleErrorAttribute
public class CustomHandleErrorAttribute : HandleErrorAttribute { public override void OnException(ExceptionContext filterContext) { if (filterContext.ExceptionHandled) return;//异常已被处理,这里不再处理 filterContext.Result = new ViewResult() { //捕捉到未被处理的异常(也就是没有catch掉的异常),转到错误页,显示错误信息 ViewName = "~/Views/Shared/Error.cshtml", ViewData = new ViewDataDictionary(filterContext.Exception.Message) }; filterContext.ExceptionHandled = true;//标记已处理 } }
Error页如下
错误 错误。
处理你的请求时出错。
@Model
CustomHandleErrorAttribute 可以进行方法、控制器、全局注册
一般而言,捕捉异常会用全局注册
public class FilterConfig { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { //filters.Add(new HandleErrorAttribute());//这是自带的异常捕捉特性,现在换成我们自己的 filters.Add(new CustomHandleErrorAttribute()); } }
软谋教育举例的七大异常:
可以看出5、6、7 这三个场景并不能被捕捉到,还是会出现异常黄页
可以通过在Global.asax.cs 添加如下函数进行异常捕捉
////// 保底全局异常处理,任何最终没有被处理的异常都会来这里 /// 但是获取的信息比较粗略,所以是作为补充 /// /// /// protected void Application_Error(object sender,EventArgs e) { var error = Server.GetLastError(); Server.ClearError();// 将错误清除掉 Response.Write(error.Message); }
注意,函数名和参数必须是这样 不能改
PS:异常捕捉特性可以捕捉 权限认证特性和方法过滤特性里面发送的异常
四、自定义方法过滤特性 CustomActionFilterAttribute
可用于页面压缩
1.特性代码演示
////// 自定义Action过滤特性 /// public class CustomActionFilterAttribute : ActionFilterAttribute { ////// 动作执行前 /// /// public override void OnActionExecuting(ActionExecutingContext filterContext) { filterContext.HttpContext.Response.Write("动作执行前"); } ////// 动作执行后 /// /// public override void OnActionExecuted(ActionExecutedContext filterContext) { filterContext.HttpContext.Response.Write("动作执行后"); } ////// 视图加载前 /// /// public override void OnResultExecuting(ResultExecutingContext filterContext) { filterContext.HttpContext.Response.Write("视图加载前"); } ////// 视图加载后 /// /// public override void OnResultExecuted(ResultExecutedContext filterContext) { filterContext.HttpContext.Response.Write("视图加载后"); } }
这个特性分别是网页面添加一句话,在Home的About方法注册一下这个特性
[CustomActionFilter] public ActionResult About() { ViewBag.Message = "Your application description page."; return View(); }
页面如下:
从这里我们可以看出,在Action执行前后四个特性函数的执行顺序
2.使用函数 OnActionExecuting 进行页面压缩
我们先看一下没有压缩的About网页的 请求头 和 响应头
请求头中,页面支持的压缩类型有 gzip,所以,我们可以对这个页面进行 gzip压缩
响应头中,页面传输数据长度为1830
接下来看一下特性代码中 OnActionExecuting 函数
public override void OnActionExecuting(ActionExecutingContext filterContext) { string acceptEncoding = filterContext.HttpContext.Request.Headers["accept-encoding"]; if (string.IsNullOrEmpty(acceptEncoding)) return; else { if (acceptEncoding.ToLower().Contains("gzip")) { // 页面支持 gzip压缩 var response = filterContext.HttpContext.Response; response.Filter = new GZipStream(response.Filter,CompressionMode.Compress);//对响应流进行gzip压缩 response.AddHeader("content-encoding", "gzip");//告诉浏览器要解压 } } }
给About添加特性后
回复的页面传输数据长度为 716 ,比之前少了很多,内容编码为gzip,浏览器会自动对页面进行解压