MVC4学习笔记之--身份认证过滤器

  过滤器作为MVC模式中面向切面编程应用很广泛,例如身份验证,日志,异常,行为截取等。博客园里面的大神对应过滤器的介绍以及很多,MVC4中不同的过滤器也介绍得很清楚。FlyDragon  辉太 禁止吸烟 如果对过滤器还没有概念的童鞋,不妨先看看前面各位前辈的介绍(前面的文章说得已经很好了,而我是想写一个较为完整的例子)。

  此文仅作为个人学习笔记整理,如果有幸对你有所帮助,不胜荣幸。如果文中有错误的地方,感谢指正。

  如果在个人前期学习阶段,使用MVC自带的身份验证,给人的感觉就是无法自己达到自己想要的控制效果,掌握起来比较麻烦。往往在一个小的作为学习MVC的项目里面,反而自己写一个过滤器来实现相关的功能,反而觉得整个学习思路比较清晰。该实例的身份验证过滤器支持三种验证方式:

1.游客(每个人都可以访问)

2.用户(注册的用户)

3.管理员(后台管理)

一、先来看看数据库

技术分享

定义了一个基础的用户表,右侧是一个权限表。右侧的权限表是固定的,一开始就把我们的权限规则数据填充在里面。设置RoleId这个字段是为了待会方便我们判断权限。

技术分享
 1 using System;
 2 using System.Collections.Generic;
 3 using System.ComponentModel;
 4 using System.ComponentModel.DataAnnotations;
 5 using System.ComponentModel.DataAnnotations.Schema;
 6 using System.Linq;
 7 using System.Web;
 8 
 9 namespace MyAuthorizen.Models
10 {
11     [Table("User")]
12     public class User
13     {
14         [Key]
15         public int UserId { get; set; }
16 
17         [DisplayName("用户名")]
18         [Required(ErrorMessage="用户名是必填字段")]
19         public string Name { get; set; }
20 
21         [DisplayName("密码")]
22         [DataType(DataType.Password)]
23         [Required(ErrorMessage="密码是必填字段")]
24         public string Password { get; set; }
25 
26         [DisplayName("昵称")]
27         public string AuthName { get; set; }
28 
29         public int RoleId { get; set; }
30 
31         public virtual Roles Role { get; set; }
32     }
33 
34     public class LoginModel
35     {
36         [DisplayName("用户名")]
37         [Required(ErrorMessage = "用户名是必填字段")]
38         public string Name { get; set; }
39 
40         [DisplayName("密码")]
41         [DataType(DataType.Password)]
42         [Required(ErrorMessage = "密码是必填字段")]
43         public string Password { get; set; }
44     }
45 
46     public class RegisterModel
47     {
48         [DisplayName("用户名")]
49         [Required(ErrorMessage = "用户名是必填字段")]
50         public string Name { get; set; }
51 
52         [DisplayName("密码")]
53         [DataType(DataType.Password)]
54         [Required(ErrorMessage = "密码是必填字段")]
55         public string Password { get; set; }
56 
57         [DisplayName("确认密码")]
58         [DataType(DataType.Password)]
59         [Required(ErrorMessage = "密码是必填字段")]
60         [Compare("Password", ErrorMessage = "密码和确认密码不匹配。")]
61         public string ConfirmPassword { get; set; }
62 
63         public int RoleId { get; set; }
64 
65         public virtual Roles Role { get; set; }
66     }
67 }
View Code
技术分享
 1 using System;
 2 using System.Collections.Generic;
 3 using System.ComponentModel;
 4 using System.ComponentModel.DataAnnotations;
 5 using System.ComponentModel.DataAnnotations.Schema;
 6 using System.Linq;
 7 using System.Web;
 8 
 9 namespace MyAuthorizen.Models
10 {
11     [Table("Roles")]
12     public class Roles
13     {
14         [Key]
15         public int RoleId { get; set; }
16 
17         [Required]
18         public string RoleName { get; set; }
19 
20         public virtual List<User> Users { get; set; }
21     }
22 }
View Code

由于我们的Roles表需要预先存数据在数据库中,在EF中我们这样添加种子数据

技术分享
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Data.Entity;
 4 using System.Linq;
 5 using System.Web;
 6 
 7 namespace MyAuthorizen.Models
 8 {
 9     public class dbContext : DbContext
10     {
11         public dbContext()
12             : base("name=DefaultConnection")
13         {
14             Database.SetInitializer<dbContext>(new RankDBInitializer());
15         }
16 
17         public DbSet<User> Users { get; set; }
18         public DbSet<Roles> Roles { get; set; }
19     
20     }
21 
22     public class RankDBInitializer : DropCreateDatabaseAlways<dbContext>
23     {
24         protected override void Seed(dbContext context)
25         {
26             List<Roles> Roles = new List<Roles>();
27             Roles.Add(new Roles { RoleId = 1, RoleName = "Admin" });
28             Roles.Add(new Roles { RoleId = 2, RoleName = "User" });
29             Roles.Add(new Roles { RoleId = 3, RoleName = "Anyone" });
30 
31             foreach(var item in Roles)
32             {
33                 context.Roles.Add(item);
34             }
35             base.Seed(context);
36         }
37     }
38 }
View Code

都完成后,我们来开始写我们自己的过滤器了,类名为MyAuthFilter。要实现标签的功能我们需要继承至ActionFilterAttribute类和实现IAuthorizationFilter接口。

在验证的过程中,我们使用了不同的类来返回验证结果,这里我们定义一个父类AuthResult。由于分别要验证三种用户身份,我们又从父类AuthResult写了三个子类。

父类代码:

技术分享
 1     public class AuthResult
 2     {
 3         protected AuthorizationContext filterContext;
 4 
 5         protected int RankId = 100;
 6 
 7 
 8         public AuthResult(AuthorizationContext filterContext)
 9         {
10             this.filterContext = filterContext;
11             this.GetRankId();
12             this.Process();
13         }
14         public virtual void Process()
15         {
16 
17         }
18 
19         private void GetRankId()
20         {
21             using (var db = new dbContext())
22             {
23                 var session = filterContext.RequestContext.HttpContext.Session["Name"];
24                 
25                 if(session != null)
26                 {
27                     this.RankId = db.Users
28                         .Where(w => w.Name == session)
29                         .Select(s => s.RoleId)
30                         .FirstOrDefault();
31                 }
32             }
33         }
34     }
View Code

三个子类代码:

技术分享
 1     public class AnyOneAuthResult : AuthResult
 2     {
 3         public AnyOneAuthResult(AuthorizationContext filterContext)
 4             : base(filterContext)
 5         {
 6 
 7         }
 8         public override void Process()
 9         {
10 
11         }
12     }
13 
14     public class UserAuthResult : AuthResult
15     {
16         public UserAuthResult(AuthorizationContext filterContext)
17             : base(filterContext)
18         {
19 
20         }
21         public override void Process()
22         {
23             if (this.RankId <= 2)
24                 return;
25             filterContext.Result = new RedirectResult("/Login/Login");
26 
27         }
28     }
29 
30     public class AdminAuthResult : AuthResult
31     {
32         public AdminAuthResult(AuthorizationContext filterContext)
33             : base(filterContext)
34         {
35 
36         }
37         public override void Process()
38         {
39             if (this.RankId == 1)
40                 return;
41             filterContext.Result = new RedirectResult("/Login/Login");
42         }
43     }
View Code

写好之后,才到我们最重要的类MyAuthFilter 前面都是扯淡的。

技术分享
 1     public class MyAuthFilter : ActionFilterAttribute, IAuthorizationFilter
 2     {
 3 
 4         public string Rank;
 5 
 6         public MyAuthFilter(string Rank = "User")
 7         {
 8             this.Rank = Rank;
 9         }
10 
11         void IAuthorizationFilter.OnAuthorization(AuthorizationContext filterContext)
12         {
13             AuthResult Auth;
14             switch (Rank)
15             {
16                 case "Anyone":
17                     Auth = new AnyOneAuthResult(filterContext);
18                     break;
19                 case "User":
20                     Auth = new UserAuthResult(filterContext);
21                     break;
22                 case "Admin":
23                     Auth = new AdminAuthResult(filterContext);
24                     break;
25             }
26 
27         }
28     }
View Code

这里我们默认是登录用户权限才可以访问。

增加一个用于登录的控制器Login

技术分享
 1 using MyAuthorizen.Models;
 2 using System;
 3 using System.Collections.Generic;
 4 using System.Linq;
 5 using System.Web;
 6 using System.Web.Mvc;
 7 
 8 namespace MyAuthorizen.Controllers
 9 {
10     public class LoginController : Controller
11     {
12 
13         private dbContext db = new dbContext();
14 
15         [HttpGet]
16         public ActionResult Login()
17         {
18             return View();
19         }
20 
21         [HttpPost]
22         public ActionResult Login(LoginModel login)
23         {
24             var Name = db.Users
25                 .Where(w => w.Name == login.Name)
26                 .Where(w => w.Password == login.Password)
27                 .Select(s => s.Name).FirstOrDefault();
28             if(Name != null )
29             {
30                 Session["Name"] = Name;
31                 return Redirect("/Home/Index");
32             }
33             return RedirectToAction("Login");
34         }
35 
36         [HttpGet]
37         public ActionResult Register()
38         {
39             //ViewBag.model = db.Users.Include("Role").ToList();
40             return View();
41         }
42 
43         [HttpPost]
44         public ActionResult Register(RegisterModel regis)
45         {
46             db.Users.Add(new User { Name=regis.Name,Password=regis.Password,RoleId = regis.RoleId});
47             db.SaveChanges();
48             return RedirectToAction("Login");
49         }
50 
51         public ActionResult LoginOut()
52         {
53             Session.RemoveAll();
54             Session.Clear();
55             return RedirectToAction("Login","Login");
56         }
57 
58     }
59 }
View Code

 登录所用到的视图部分的代码各位看官自己添加咯!

新建一个Home控制器来看看效果吧,Home控制器里面有三个方法,分别是Index、About、Admin三个方法分别需要不同的权限。Index每个人都可以访问,About需要登录的用户才能访问,而Admin需要管理员权限的用户才能访问。

技术分享
 1 using MyAuthorizen.Class;
 2 using System;
 3 using System.Collections.Generic;
 4 using System.Linq;
 5 using System.Web;
 6 using System.Web.Mvc;
 7 
 8 namespace MyAuthorizen.Controllers
 9 {
10     [MyAuthFilter]
11     public class HomeController : Controller
12     {
13         //
14         // GET: /Home/
15         [MyAuthFilter(Rank="Anyone")]
16         public ActionResult Index()
17         {
18             return View();
19         }
20 
21         public ActionResult About()
22         {
23             return View();
24         }
25 
26         [MyAuthFilter(Rank="Admin")]
27         public ActionResult Admin()
28         {
29             return View();
30         }
31 
32     }
33 }
View Code

如代码所示,Index需要需要把Rank的值设置为Anyone才能让每个人都可以访问。而About则不设置。默认需要登录的用户才可以访问。而Admin方法设置为Admin才能达到让管理权限的用户才能访问的功能。

首先,我们注册一个账号001,用户权限。

技术分享请注意RoleId那个表单,在实际使用中。我们提供给别人注册的表单里面是不能包含这个属性的,需要我们在后台的Action里面手动设置RoleId的值,这里我设置成2表示注册一个普通用户。

技术分享访问个人中心正常(个人中心对应的Action是About),但是我们点击管理后台的时候会自动跳转到登录页面

 

 

注册一个管理员权限的用户

技术分享

技术分享访问管理页面正常

 

以上

如有需要demo的童鞋 点我下载

第一次写笔记 好紧张好害怕会不会鄙视 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。