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 }
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 }
由于我们的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 }
都完成后,我们来开始写我们自己的过滤器了,类名为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 }
三个子类代码:
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 }
写好之后,才到我们最重要的类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 }
这里我们默认是登录用户权限才可以访问。
增加一个用于登录的控制器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 }
登录所用到的视图部分的代码各位看官自己添加咯!
新建一个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 }
如代码所示,Index需要需要把Rank的值设置为Anyone才能让每个人都可以访问。而About则不设置。默认需要登录的用户才可以访问。而Admin方法设置为Admin才能达到让管理权限的用户才能访问的功能。
首先,我们注册一个账号001,用户权限。
请注意RoleId那个表单,在实际使用中。我们提供给别人注册的表单里面是不能包含这个属性的,需要我们在后台的Action里面手动设置RoleId的值,这里我设置成2表示注册一个普通用户。
访问个人中心正常(个人中心对应的Action是About),但是我们点击管理后台的时候会自动跳转到登录页面
注册一个管理员权限的用户
访问管理页面正常
以上
如有需要demo的童鞋 点我下载
第一次写笔记 好紧张好害怕会不会鄙视
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。