MVC 基于 AuthorizeAttribute 实现的登陆权限控制
2016-12-16 16:54
211 查看
本篇主要讲述在MVC中使用AuthorizeAttribute实现登陆和权限控制,通俗的讲就是,判定用户是否登陆,若没登陆就跳转到登陆页,是否有权限访问页面,若没有则跳转到特定提示页。
网上有很多类似的,我也借鉴了部分,如有雷同请见谅。
关于AuthorizeAttribute的详解 请查看 https://msdn.microsoft.com/en-us/library/system.web.mvc.authorizeattribute(v=vs.118).aspx
代码的执行顺序是 OnAuthorization–>AuthorizeCore–>HandleUnauthorizedRequest 不过我去掉了OnAuthorization部分。这部分也可以做很多验证的。如果AuthorizeCore返回false时,才会走HandleUnauthorizedRequest 方法,并且Request.StausCode会返回401。
首先创建一个MCV的项目,在App_Start目录下创建一个类UserAuthAttribute,此类要继承AuthorizeAttribute类,这里继承的时候注意using System.Web.Mvc;
还是在App_Start目录下找到 FilterConfig类,添加注册。
现在已经完成了基本的架构。
系统要有用户,角色,根据登陆的用户获取角色,再根据角色获取可访问的页面。 我这里用简单的表结构描述各表之间的关系。
在Models文件下创建各实体。(可以用edmx直接生成的,然而我没有)
然后我们要创建一些模拟数据
其中GetMenuByUserID(int UserID) 方法是根据UserID获取可访问的Menu.
这些部分完成后,接下来我们要创建登陆页面和登陆后显示的主页,以及子页面,还有无权访问提示页。
LogIn页前台,
LogIn后台
注意:这里加了标识 [AllowAnonymous] ,表示允许任何用户访问,NoPremission 也要加。
登陆完成后,session记录用户信息和可访问的Menu信息,跳转到主页或者先前页。
现在已经完成大部分了。but 最主要的还没做,就是之前创建的UserAuthAttribute这个类。
在类里先定义个变量
开始最主要部分。验证是否已经登陆,判定是否有权限
返回false的处理, 进行跳转, 若没登陆,跳转到登陆页并带有参数,当登陆完成后可以跳转的先前页。这URL可以使用加密,防止客户修改或传递的参数发生编码错误。
判定是否有权限, URL可能带有参数,我这里使用了GUID模拟的,
如果参数很多,可以写个类特殊处理下,
现在已经完成了。
现在我有些疑问。
1我发现这个只是在访问页面的时候能起作用, 如果是ajax请求根本就不跳转, 我用bootstrap+dataTable 做个列表, 如果登陆超时,点搜索按钮时 就报错,不跳转到登陆页。 我好多页面都是这么做的,每个页面都加js判定会累死的, 有人说去改dataTable源码, 有人说去改ajax源码, 我感觉能不动组件代码就别动, 如果版本更新,换个人维护谁知道你改了组件。
有没有更好的方法,通用的,一看就知道在哪的办法呢?
希望大家给些建议。
实例代码在百度网盘 http://pan.baidu.com/s/1o8O19ZO
我才不去赚CSDN积分呢。
网上有很多类似的,我也借鉴了部分,如有雷同请见谅。
关于AuthorizeAttribute的详解 请查看 https://msdn.microsoft.com/en-us/library/system.web.mvc.authorizeattribute(v=vs.118).aspx
代码的执行顺序是 OnAuthorization–>AuthorizeCore–>HandleUnauthorizedRequest 不过我去掉了OnAuthorization部分。这部分也可以做很多验证的。如果AuthorizeCore返回false时,才会走HandleUnauthorizedRequest 方法,并且Request.StausCode会返回401。
首先创建一个MCV的项目,在App_Start目录下创建一个类UserAuthAttribute,此类要继承AuthorizeAttribute类,这里继承的时候注意using System.Web.Mvc;
还是在App_Start目录下找到 FilterConfig类,添加注册。
public class FilterConfig { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new HandleErrorAttribute()); filters.Add(new UserAuthAttribute());//注册 } }
现在已经完成了基本的架构。
系统要有用户,角色,根据登陆的用户获取角色,再根据角色获取可访问的页面。 我这里用简单的表结构描述各表之间的关系。
在Models文件下创建各实体。(可以用edmx直接生成的,然而我没有)
public class User { public int UserID { get; set; } public string UserName { get; set; } public string PassWord { get; set; } }
public class Role { public int RoleID { get; set; } public string RoleName { get; set; } }
public class UserRole { public int UserRoleID { get; set; } public int UserID { get; set; } public int RoleID { get; set; } }
public class SysMenu { public int MenuID { get; set; } public string MenuURL { get; set; } public string MenuName { get; set; } }
public class RoleMenu { public int RoleMenuID { get; set; } public int RoleID { get; set; } public int MenuID { get; set; } }
然后我们要创建一些模拟数据
public class TestData { public static List<User> Users { get { //模拟用户 List<User> lists = new List<User>(); lists.Add(new User { UserID = 1, UserName = "test1", PassWord = "1" }); lists.Add(new User { UserID = 2, UserName = "test2", PassWord = "2" }); lists.Add(new User { UserID = 3, UserName = "test3", PassWord = "3" }); lists.Add(new User { UserID = 4, UserName = "test4", PassWord = "4" }); return lists; } } /// <summary> /// 页面 /// </summary> public static List<SysMenu> SysMenuList { get { List<SysMenu> lists = new List<SysMenu>(); lists.Add(new SysMenu { MenuID = 0, MenuName = "Home", MenuURL = "/Account/Home" }); lists.Add(new SysMenu { MenuID = 1, MenuName = "Index", MenuURL = "/Admin/Index" }); lists.Add(new SysMenu { MenuID = 2, MenuName = "TestPageOne", MenuURL = "/Admin/TestPageOne" }); lists.Add(new SysMenu { MenuID = 3, MenuName = "TestPageTwo", MenuURL = "/Admin/TestPageTwo" }); lists.Add(new SysMenu { MenuID = 4, MenuName = "TestPageThree", MenuURL = "/Admin/TestPageThree" }); lists.Add(new SysMenu { MenuID = 5, MenuName = "Index", MenuURL = "/Test/Index" }); lists.Add(new SysMenu { MenuID = 6, MenuName = "TestPageOne", MenuURL = "/Test/TestPageOne" }); lists.Add(new SysMenu { MenuID = 7, MenuName = "TestPageTwo", MenuURL = "/Test/TestPageTwo" }); lists.Add(new SysMenu { MenuID = 8, MenuName = "TestPageThree", MenuURL = "/Test/TestPageThree" }); return lists; } } /// <summary> /// 角色 /// </summary> public static List<Role> RoleList { get { List<Role> roles = new List<Role> { new Role { RoleID = 1, RoleName = "Admin" }, new Role { RoleID = 2, RoleName = "User" } }; return roles; } } /// <summary> /// 角色可访问的页面 /// </summary> public static List<RoleMenu> RoleMenuList { get { List<RoleMenu> roles = new List<RoleMenu> { new RoleMenu { RoleMenuID=1, RoleID = 1,MenuID = 1 }, new RoleMenu { RoleMenuID=2, RoleID = 1,MenuID = 2 }, new RoleMenu { RoleMenuID=3, RoleID = 1,MenuID = 3 }, new RoleMenu { RoleMenuID=4, RoleID = 1,MenuID = 4 }, new RoleMenu { RoleMenuID=5, RoleID = 2,MenuID = 5 }, new RoleMenu { RoleMenuID=6, RoleID = 2,MenuID = 6 }, new RoleMenu { RoleMenuID=7, RoleID = 2,MenuID = 7 }, new RoleMenu { RoleMenuID=8, RoleID = 2,MenuID = 8 }, new RoleMenu { RoleMenuID=9, RoleID = 1,MenuID = 0 }, new RoleMenu { RoleMenuID=10, RoleID = 2,MenuID =0 }, }; return roles; } } public static List<UserRole> UserRoleList { get { return new List<UserRole>() { new UserRole{ UserRoleID=1,UserID=1,RoleID=1}, new UserRole{ UserRoleID=2,UserID=1,RoleID=2}, new UserRole{ UserRoleID=3,UserID=2,RoleID=1}, new UserRole{ UserRoleID=4,UserID=3,RoleID=2}, new UserRole{ UserRoleID=5,UserID=4,RoleID=2} }; } } public static List<SysMenu> GetMenuByUserID(int UserID) { //var usermenu = from u in Users // where u.UserID == UserID // join ur in UserRoleList on u.UserID equals ur.UserID // join r in RoleList on ur.RoleID equals r.RoleID // join rm in RoleMenuList on r.RoleID equals rm.RoleID // join m in SysMenuList on rm.MenuID equals m.MenuID // select new // { // u.UserID, // u.UserName, // r.RoleID, // r.RoleName, // m.MenuID, // m.MenuURL // }; var usermenu = from u in Users where u.UserID == UserID join ur in UserRoleList on u.UserID equals ur.UserID join r in RoleList on ur.RoleID equals r.RoleID join rm in RoleMenuList on r.RoleID equals rm.RoleID join m in SysMenuList on rm.MenuID equals m.MenuID select m; return usermenu.Distinct().ToList(); } }
其中GetMenuByUserID(int UserID) 方法是根据UserID获取可访问的Menu.
这些部分完成后,接下来我们要创建登陆页面和登陆后显示的主页,以及子页面,还有无权访问提示页。
LogIn页前台,
<!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>LogIn</title> </head> <body> <div style=" width:600px; margin:50px auto;"> <form action="/Account/LogIn" method="post"> <table> <tr><td>User Name</td><td><input type="text" id="username" name="username" /></td></tr> <tr><td>Pass word</td><td><input type="password" id="password" name="password" /></td></tr> <tr><td></td><td><input type="submit" value="LogIn" /></td></tr> </table> </form> </div> </body> </html>
LogIn后台
[AllowAnonymous] public ActionResult LogIn() { string User_Name = this.Request.Form["username"]; string User_Pw = this.Request.Form["password"]; if (!string.IsNullOrEmpty(User_Name) && !string.IsNullOrEmpty(User_Pw)) { List<User> Ulist = TestData.Users; var userinfos = Ulist.Where(e => e.UserName.Equals(User_Name) && e.PassWord.Equals(User_Pw)); if (userinfos != null && userinfos.Count() == 1) { User _user = userinfos.FirstOrDefault(); Session[WebConstants.UserSession] = _user; Session[WebConstants.UserRoleMenu] = TestData.GetMenuByUserID(_user.UserID); string fromurl = Request.UrlReferrer.Query; if (fromurl.IndexOf("?fromurl=") > -1) { fromurl = fromurl.Substring(9); return this.Redirect(fromurl); } else { return this.RedirectToAction("Home", "Account"); } } } return View(); }
注意:这里加了标识 [AllowAnonymous] ,表示允许任何用户访问,NoPremission 也要加。
[AllowAnonymous] public ActionResult NoPremission() { return View(); }
登陆完成后,session记录用户信息和可访问的Menu信息,跳转到主页或者先前页。
现在已经完成大部分了。but 最主要的还没做,就是之前创建的UserAuthAttribute这个类。
在类里先定义个变量
public bool IsLogin = false;
开始最主要部分。验证是否已经登陆,判定是否有权限
protected override bool AuthorizeCore(HttpContextBase httpContext) { bool Pass = false; try { var websession = httpContext.Session[WebConstants.UserSession]; if (websession == null) { httpContext.Response.StatusCode = 401;//无权限状态码 Pass = false; IsLogin = false; } else { User user = httpContext.Session[WebConstants.UserSession] as User; if (user == null) { httpContext.Response.StatusCode = 401;//无权限状态码 Pass = false; IsLogin = false; } else if (!IsMenuRole(httpContext)) { httpContext.Response.StatusCode = 401;//无权限状态码 Pass = false; IsLogin = true; } else { Pass = true; } } } catch (Exception) { return Pass; } return Pass; }
返回false的处理, 进行跳转, 若没登陆,跳转到登陆页并带有参数,当登陆完成后可以跳转的先前页。这URL可以使用加密,防止客户修改或传递的参数发生编码错误。
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) { if (filterContext == null) { throw new ArgumentNullException("filterContext"); } else { if (!IsLogin) { string fromUrl = filterContext.HttpContext.Request.Url.PathAndQuery; // string strUrl = new UrlHelper(filterContext.RequestContext).Action("Login", "Account","") + "?fromurl={0}"; string strUrl = "~/Account/Login/?fromurl={0}"; filterContext.HttpContext.Response.Redirect(string.Format(strUrl, fromUrl), true); } else { filterContext.Result = new RedirectResult("~/Account/NoPremission"); } } }
判定是否有权限, URL可能带有参数,我这里使用了GUID模拟的,
如果参数很多,可以写个类特殊处理下,
public bool IsMenuRole(HttpContextBase httpContext) { string rawurll = httpContext.Request.RawUrl.ToLower(); List<SysMenu> MenuList = httpContext.Session[WebConstants.UserRoleMenu] as List<SysMenu>; Guid guid; //这里是过滤掉 url后的GUID参数 int rindex = rawurll.LastIndexOf("/"); if (rindex > 0 && Guid.TryParse(rawurll.Substring(rindex + 1), out guid)) { rawurll = rawurll.Substring(0, rindex); } if (MenuList.Where(e => e.MenuURL.ToLower().Contains(rawurll)).Count() == 0) { return false; } return true; }
现在已经完成了。
现在我有些疑问。
1我发现这个只是在访问页面的时候能起作用, 如果是ajax请求根本就不跳转, 我用bootstrap+dataTable 做个列表, 如果登陆超时,点搜索按钮时 就报错,不跳转到登陆页。 我好多页面都是这么做的,每个页面都加js判定会累死的, 有人说去改dataTable源码, 有人说去改ajax源码, 我感觉能不动组件代码就别动, 如果版本更新,换个人维护谁知道你改了组件。
有没有更好的方法,通用的,一看就知道在哪的办法呢?
希望大家给些建议。
实例代码在百度网盘 http://pan.baidu.com/s/1o8O19ZO
我才不去赚CSDN积分呢。
相关文章推荐
- ASP.NET MVC 中实现基于角色的权限控制的处理方法
- ASP.NET MVC 中实现基于角色的权限控制的处理方法
- 在ASP.NET MVC中实现基于URL的权限控制
- 在ASP.NET MVC中实现基于URL的权限控制
- ASP.NET MVC 中如何实现基于角色的权限控制
- ASP.NET MVC 中如何实现基于角色的权限控制
- 在ASP.NET MVC中实现基于URL的权限控制
- 在ASP.NET MVC中实现基于URL的权限控制
- ASP.NET MVC 中如何实现基于角色的权限控制
- ASP.NET MVC 中如何实现基于角色的权限控制
- 基于角色-功能-资源的权限控制模型的设计与实现-引子
- ASP.NET MVC中权限控制的简单实现
- 一种基于annotation的Spring-mvc权限控制方法
- ASP.NET MVC(模型(Model),视图(View)和控制Controller)实践:实现身份验证权限管理
- 在struts2.3.4.1中使用注解、反射、拦截器实现基于方法的权限控制
- 基于.net mvc的校友录(五、web.config对的配置以及filter实现的权限控制)
- 基于URL实现权限控制
- 如何设计数据库表实现完整的RBAC(基于角色权限控制)
- 基于struts的权限控制——简单实现
- 如何设计数据库表实现完整的RBAC(基于角色权限控制)