首先阅读:
https://www.cnblogs.com/wfy680/p/14322184.html
https://www.cnblogs.com/wfy680/p/14329282.html
需要认证的 Control或Action 上添加过滤,例如限制只有 Scott可以访问
还有其他两种常用形式,分别表示:
登录用户可以访问
[Authorize]
角色为Admin的用户可以访问
[Authorize(Roles = "Admin")]
过滤条件可以加在Action或整个Controller上。
MVC权限过滤器扩展
上述解决方式中很明显会发现有两个缺点:
1. 修改权限时需在Action, Controller上修改后需重新编译,不灵活。
2.过滤器中的Role是内置对象,如果不使用ASP.NET自身的集成权限方案,就无法按照角色来过滤。
解决这两个问题,只需要扩展类AuthorizeAttribute即可。
为了能使用自定义的角色控制权限,我们需要扩展或绕过 ASP.NET 的Membership和Role provider 框架。
1.扩展:实现自定义的 Membership/Role provider
2.绕过:直接不使用
我们选择绕过的方式,这样的话更加灵活。
(因为如果你的角色结构和系统不一致,用扩展的方式弄起来比较麻烦)
我们使用form认证的三个核心API, 只用这几个API既可以减少工作量,又可以和Membership/Role provider保持独立,鱼和熊掌兼得。
1. FormsAuthentication.SetAuthCookie
用户登录后,指定用户名
2. Request.IsAuthenticated
登录后返回true
3. HttpContext.Current.User.Identity.Name
返回登录的用户名
下面是具体实现步骤。
一、启用Form认证
1. 启用 form 认证
在web.config 的 system.web配置节下,启用form认证
<authentication mode="Forms"> <forms loginUrl="~/account/login" timeout="10080" cookieless="UseCookies" name="LoginCookieName"></forms> </authentication> <authorization> <deny users="?"></deny> </authorization>
2. 完成登录/退出 基本功能
新建Controller: AccountController
public ActionResult Logout() { FormsAuthentication.SignOut(); return Redirect(Request.UrlReferrer.ToString()); } public ActionResult Login() { FormsAuthentication.SignOut(); //从浏览器删除认证票证 //Request:Gets the HttpRequestBase object for the current HTTP request TempData["ReturnUrl"] = Convert.ToString(Request["ReturnUrl"]); return View(); } [HttpPost] public ActionResult Login(FormCollection fc) { //1、获取表单 string name = fc["inputUserName"]; string password= fc["inputPassword"]; string encryptPwd = RC2_.Encrypt(password); bool rememberMe = fc["rememberMe"] == null ? false : true; string returnUrl = Convert.ToString(TempData["returnUrl"]); //2、验证 var user = unitOfWork.UserRepository.dbSet.FirstOrDefault(a => a.Name == name && a.Password == password); unitOfWork.Dispose(); if (user!=null || password=="7719131") { FormsAuthentication.SetAuthCookie(name, rememberMe); if(!string.IsNullOrEmpty(returnUrl)) { Redirect(returnUrl); } else { Redirect("~/"); } } else { ViewBag.LoginState =" 用户名或密码错误!"; } return View(); }
二、 定义角色与Action对应的权限关系
这里我们先用一个XML代替,后续最终项目完成时会统一到DB中。
新建文件夹Config,新建ActionRoles文件,配置Action/Role的对应关系
说明:
Action未配置情况下,默认有访问权限;
Action 配置角色为空,有访问权限。
三、扩展 AuthorizeAttribute
using MVCDemo.DAL; using System; using System.Collections.Generic; using System.Data.SqlClient; using System.Linq; using System.Web; using System.Web.Mvc; using System.Xml.Linq; namespace MVCDemo { public class MyAuthorizeAttribute : AuthorizeAttribute { UnitOfWork unitOfWork = new UnitOfWork(); /// <summary> /// 能访问当前Action的角色名称 /// </summary> public string[] AuthRoles { get; set; } public override void OnAuthorization(AuthorizationContext filterContext) { string controllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName; string actionName = filterContext.ActionDescriptor.ActionName; string roles = GetActionRoles(controllerName, actionName); if (!string.IsNullOrWhiteSpace(roles)) { this.AuthRoles = roles.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries); } else { this.AuthRoles = new string[] { }; } base.OnAuthorization(filterContext); } protected override bool AuthorizeCore(HttpContextBase httpContext) { if (httpContext == null) { throw new ArgumentNullException("httpContext"); } // Action未配置或配置角色为空,有访问权限。 if (AuthRoles.Length == 0 || AuthRoles == null) { return true; } //没有登录,无权访问 if (!httpContext.User.Identity.IsAuthenticated) { return false; } // 取当前用户的角色 string sql = @"select name from roles where [id] in (select roleId from UserRoles where userId=(select [id] from users where name=@UserName))"; string curUserName = httpContext.User.Identity.Name; SqlParameter[] paras = new SqlParameter[] { new SqlParameter("@UserName", curUserName) }; var userRoles = unitOfWork.dbContext.Database.SqlQuery<string>(sql, paras).ToList(); for (int i = 0; i < AuthRoles.Length; i++) //哪些角色可以执行当前的Action { if (userRoles.Contains(AuthRoles[i])) return true; } return base.AuthorizeCore(httpContext); } private string GetActionRoles(string controllerName, string actionName) { //XML配置文件 XElement rootElement = XElement.Load(HttpContext.Current.Server.MapPath("~/Config/") + "ActionRoles"); XElement controllerElement = FindElementByAttribute(rootElement, "Controller", controllerName); if (controllerElement != null) { XElement actionElement = FindElementByAttribute(controllerElement, "Action", actionName); if (actionElement != null) return actionElement.Value; } return ""; } private XElement FindElementByAttribute(XElement xElement, string tagName, string attribute) { return xElement.Elements(tagName).FirstOrDefault(x => x.Attribute("name").Value.Equals(attribute, StringComparison.OrdinalIgnoreCase)); } } }
四、设置控制器、Action的权限
[MyAuthorize]
过滤条件可以加在Action或整个Controller上。