zoukankan      html  css  js  c++  java
  • AOP实践--利用MVC5 Filter实现登录状态判断

    AOP有的翻译“面向切面编程”,有的是“面向方面编程”。其实名字不重要,思想才是核心,mvc的Filter让我们很方便达到这种面向方面编程,就是在现有代码的基础上注入外部代码,也就是所谓的面向方面编程,比如身份验证。下面通过一个具体的例子来体验一下MVC的AOP。

    1、定义一AuthenAdminAttribute特性类

    1. public class AuthenAdminAttribute : FilterAttribute, IAuthenticationFilter
    2. {
    3. public void OnAuthentication(AuthenticationContext filterContext)
    4. {
    5. //这个方法是在Action执行之前调用
    6. var user = filterContext.HttpContext.Session["AdminUser"];
    7. if (user == null)
    8. {
    9. //filterContext.HttpContext.Response.Redirect("/Account/Logon");
    10. var Url = new UrlHelper(filterContext.RequestContext);
    11. var url = Url.Action("Logon", "Account", new { area=""});
    12. filterContext.Result = new RedirectResult(url);
    13. }
    14. }
    15. public void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext)
    16. {
    17. //这个方法是在Action执行之后调用
    18. }
    19. }

    是否登录是通过Session键值为AdminUser的值是否为null判断,如果为null也就是还没有登录或者过期了,就跳转到登录页面,即"/Account/Logon"。

    注意:上面OnAuthentication是在最开始被调用的,也在ActionFilter方法之前。而OnAuthenticationChallenge方法是在Action执行之后,返回视图之前被调用。所以要把登录验证写在方法OnAuthentication中。而且在里面我们用到了设置filterContext.Result = new RedirectResult(url);而不是跳转的形式,很关键的。MVC在执行Filter时,如果我们手动用一个ActionResult对象指定了其Context对象的Result属性的值,那么这个这个ActionResult将作为这个请求的结果输出,并且在这次请求管道中剩下的步骤将不再继续执行。反之如果没有设置filterContext.Result的值,它会继续执行接下来的步骤,甚至是Action方法,就算我们设置了跳转。

    2、定义登录Controller

    1. public class ManageController : Controller
    2. {
    3. public ActionResult Logon()
    4. {
    5. return View();
    6. }
    7. [HttpPost]
    8. public ActionResult Logon(string username,string password)
    9. {
    10. if (username == "admin" && password == "admin")
    11. {
    12. Session["AdminUser"] = username;
    13. return RedirectToAction("Index",
    14. "Order", new { area = "Admin" });
    15. }
    16. else
    17. ViewBag.Error = "用户名或密码不正确!";
    18. return View();
    19. }
    20. public ActionResult LogOff()
    21. {
    22. if (Session["AdminUser"] != null)
    23. {
    24. Session["AdminUser"] = null;
    25. }
    26. return RedirectToAction("Logon");
    27. }
    28. }

    Action名为Logon的方法就是里面就是登录相关逻辑,这里的逻辑我为了简单化,就直接把用户名和密码固定写死了。当然实际过程中你可以根据你自己的需要,比如结合数据库表记录来判断用户名密码是否合法,如果合法就相应的信息存在Session里面,当然你也可以存在Cookie里。

    注意:这里登录成功之后的存Session的key一定要和上面第一步的AuthenAdminAttribute用到的key一致。

    3、设置需要登录判断的Controller或者Action

    最后就是根据你的需要,看哪些Controller或者Action需要登录才能访问,只需要在前面加上我们在上面定义好的特性类就可以了。   
    1. [AuthenAdmin]
    2. public class CategoryController : Controller
    3. {
    4. public ActionResult Index()
    5. {
    6. //此处省略具体逻辑代码
    7. return View();
    8. }
    9. }

    上面是对整个Controller都要登录验证,就是这个Controller的所有Action必须要登录才能访问。那如果要针对单独的一个Action控制,其它不做要求呢?这也很好办。代码这样写就可以了。

    1. public class CategoryController : Controller
    2. {
    3. public ActionResult Index()
    4. {
    5. //此处省略具体逻辑代码
    6. return View();
    7. }
    8. [AuthenAdmin]
    9. public ActinResult List()
    10. {
    11. //此处省略具体逻辑代码
    12. return View();
    13. }
    14. }
    这样就是只有List这个Action需要登录,Index就不用登录就能访问。
    最后,说一下第一步为什么我要自己实现IAuthenticationFilter接口,而不直接继承AuthorizeAttribute,比如这样写
    1. public class CustomAuthAttribute : AuthorizeAttribute {
    2. private bool localAllowed;
    3. public CustomAuthAttribute(bool allowedParam) {
    4. localAllowed = allowedParam;
    5. }
    6. protected override bool AuthorizeCore(HttpContextBase httpContext) {
    7. var user = httpContext.Session["AdminUser"];
    8. return user != null
    9. }
    10. }

    可以看到AuthorizeAttribute核心方法是AuthorizeCore返回值是一个bool类型,也就是只能判断是否登录过了,这种情况如果你的系统采用Form验证这个,确实是一个简单可行的方案。如果要涉及到更加细微的权限控制或者要把登录信息存储到Session或者其实地方就不太好办了,因为ASP.NET的Form验证是基于Cookie的。所以我一般建议自己实现接口IAuthenticationFilter,这样让我们的系统更加灵活,更加容易扩展和控制。

    这样最后来看我们的业务逻辑代码不会有身份验证相关的代码,登录验证和业务逻辑代码完全隔离开了,业务逻辑代码变得简洁了许多,这就是我理解的:你只需要针对一方面编程,也就是AOP提倡的面向方面编程。AOP技术让我们的软件模块之间的耦合性降低,大大的提高的我们软件的可维护性和可复用性,AOP你值得拥有。

  • 相关阅读:
    this指向详解
    领域驱动设计-1-概述
    算法 表达式求值
    进制转换
    IDEA Junit FileNotFoundException: class path resource [spring/spring.xml] cannot be opened because it does not exist
    aes加密示例
    create an oauth app
    搭建docusaurus博客
    Vue项目整体架构记要
    vue+element 获取验证码
  • 原文地址:https://www.cnblogs.com/waw/p/8229046.html
Copyright © 2011-2022 走看看