一、Forms认证流程
请先参考如下网址:
http://www.cnblogs.com/fish-li/archive/2012/04/15/2450571.html
本文主要介绍使用自定义的身份认证表示来实现认证
二、自定义的身份认证主要流程
主要代码如下:
1..登录验证完用户名和密码后写入Cookie信息
1 public static HttpCookie SingIn(string loginName,TUserData userData,int expiration) 2 { 3 if (string.IsNullOrEmpty(loginName)) 4 throw new ArgumentNullException("loginName"); 5 if (userData == null) 6 throw new ArgumentNullException("userData"); 7 // 1. 把需要保存的用户数据转成一个字符串。 8 string data = null; 9 if (userData != null) 10 data = JsonConvert.SerializeObject(userData); 11 //(new JavaScriptSerializer()).Serialize(userData); 12 // 2. 创建一个FormsAuthenticationTicket,它包含登录名以及额外的用户数据。 13 FormsAuthenticationTicket ticket = new FormsAuthenticationTicket( 14 2, loginName, DateTime.Now, DateTime.Now.AddDays(1), true, data); 15 // 3. 加密Ticket,变成一个加密的字符串。 16 string cookieValue = FormsAuthentication.Encrypt(ticket); 17 // 4. 根据加密结果创建登录Cookie 18 HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, cookieValue); 19 cookie.HttpOnly = true; 20 cookie.Secure = FormsAuthentication.RequireSSL; 21 cookie.Domain = FormsAuthentication.CookieDomain; 22 cookie.Path = FormsAuthentication.FormsCookiePath; 23 if (expiration > 0) 24 cookie.Expires = DateTime.Now.AddMinutes(expiration); 25 26 HttpContext context = HttpContext.Current; 27 if (context == null) 28 throw new InvalidOperationException(); 29 30 // 5. 写登录Cookie 31 context.Response.Cookies.Remove(cookie.Name); 32 context.Response.Cookies.Add(cookie); 33 return cookie; 34 }
2.在Global.asax 中解析Cookie携带的自定义信息
1 protected void Application_AuthenticateRequest(object sender, EventArgs e) 2 { 3 HttpApplication app = (HttpApplication)sender; 4 UserFormsPrincipal<UserInfo>.TrySetUserInfo(app.Context); 5 }
相关的解析方法
1 public static void TrySetUserInfo(HttpContext context) 2 { 3 if (context == null) 4 throw new ArgumentNullException("context"); 5 // 1. 读登录Cookie 6 HttpCookie cookie = context.Request.Cookies[FormsAuthentication.FormsCookieName]; 7 if (cookie == null || string.IsNullOrEmpty(cookie.Value)) 8 return; 9 try 10 { 11 TUserData userData = null; 12 // 2. 解密Cookie值,获取FormsAuthenticationTicket对象 13 FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookie.Value); 14 if (ticket != null && string.IsNullOrEmpty(ticket.UserData) == false) 15 { 16 // 3. 还原用户数据 17 userData = JsonConvert.DeserializeObject<TUserData>(ticket.UserData); 18 } 19 if (ticket != null && userData != null) 20 { 21 // 4. 构造我们的UserFormsPrincipal实例,重新给context.User赋值。 22 context.User = new UserFormsPrincipal<TUserData>(ticket, userData); 23 } 24 } 25 catch { /* 有异常也不要抛出,防止攻击者试探。 */ } 26 }
3.自定义授权Attribute
1 public class RoleAuthorizeAttribute : AuthorizeAttribute 2 { 3 public override void OnAuthorization(AuthorizationContext filterContext) 4 { 5 var isAuth = false; 6 if (!filterContext.RequestContext.HttpContext.Request.IsAuthenticated) 7 { 8 isAuth = false; 9 } 10 else 11 { 12 if (filterContext.RequestContext.HttpContext.User.Identity != null) 13 { 14 IList<Permission> pList = null; 15 var roleService = new UserServer("DefaultConnection"); 16 var actionDescriptor = filterContext.ActionDescriptor; 17 var controllerDescriptor = actionDescriptor.ControllerDescriptor; 18 var controller = controllerDescriptor.ControllerName; 19 var action = actionDescriptor.ActionName; 20 var ticket = (filterContext.RequestContext.HttpContext.User.Identity as FormsIdentity).Ticket; 21 var userData = (filterContext.RequestContext.HttpContext.User as UserFormsPrincipal<UserInfo>).UserData; 22 string perListKey = string.Format("userPermission_{0}", userData.RoleId); 23 var cache = HttpRuntime.Cache.Get(perListKey) as List<Permission>; 24 if (cache != null) 25 { 26 pList = cache; 27 } 28 29 if (pList != null) 30 { 31 isAuth = pList.Any(x => x.CName.ToLower() == controller.ToLower() && x.AName.ToLower() == action.ToLower()); 32 } 33 } 34 } 35 if (!isAuth) 36 { 37 filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(new { controller = "Home", action = "Index", returnUrl = filterContext.HttpContext.Request.Url, returnMessage = "您无权查看." })); 38 return; 39 } 40 else 41 { 42 base.OnAuthorization(filterContext); 43 } 44 } 45 }
4.Web.Config 在System.Web下新增配节
1 <authentication mode="Forms"> 2 <forms name="LoginCookieName" loginUrl="~/Home/Index"></forms> 3 </authentication>
三、实现细粒度权限控制
1.构造BaseController 所有需要权限认证的Controller 都需要从此进行继承
1 public class BaseController : Controller 2 { 3 public BaseController() 4 { 5 var pList = new List<Permission>(); 6 if (System.Web.HttpContext.Current != null && System.Web.HttpContext.Current.User.Identity.IsAuthenticated) 7 { 8 var ticket = (System.Web.HttpContext.Current.User.Identity as FormsIdentity).Ticket; 9 var userData = (System.Web.HttpContext.Current.User as UserFormsPrincipal<UserInfo>).UserData; 10 string perListKey = string.Format("userPermission_{0}", userData.RoleId); 11 pList = HttpRuntime.Cache.Get(perListKey) as List<Permission>; 12 } 13 ViewBag.PerList = pList; 14 15 } 16 }
2._Layout.cshtml中获取权限信息并对主菜单进行权限控制
1 @using FormAuth.Models; 2 @using FormAuth.Utils; 3 @{ 4 var pList = ViewBag.PerList as List<Permission>; 5 } 6 <!DOCTYPE html> 7 <html> 8 <head> 9 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 10 <meta charset="utf-8" /> 11 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 12 <title>@ViewBag.Title - 我的 ASP.NET 应用程序</title> 13 @Styles.Render("~/Content/css") 14 @Scripts.Render("~/bundles/modernizr") 15 </head> 16 <body> 17 <div class="navbar navbar-inverse navbar-fixed-top"> 18 <div class="container"> 19 <div class="navbar-header"> 20 <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse"> 21 <span class="icon-bar"></span> 22 <span class="icon-bar"></span> 23 <span class="icon-bar"></span> 24 </button> 25 @Html.ActionLink("大思无疆", "Index", "Home", new { area = "" }, new { @class = "navbar-brand" }) 26 </div> 27 <div class="navbar-collapse collapse"> 28 <ul class="nav navbar-nav"> 29 @if (pList != null) 30 { 31 if (pList.FirstOrDefault(m => m.CName.ToLower() == "hello") != null) 32 { 33 <li>@Html.ActionLink("你好", "Index", "Hello")</li> 34 } 35 if (pList.FirstOrDefault(m => m.CName.ToLower() == "world") != null) 36 { 37 <li>@Html.ActionLink("世界", "Index", "world")</li> 38 } 39 if (pList.FirstOrDefault(m => m.CName.ToLower() == "good") != null) 40 { 41 <li>@Html.ActionLink("棒棒哒", "Index", "good")</li> 42 } 43 } 44 45 </ul> 46 </div> 47 </div> 48 </div> 49 <div class="container body-content"> 50 @RenderBody() 51 <hr /> 52 <footer> 53 <p>© @DateTime.Now.Year - 我的 ASP.NET 应用程序</p> 54 </footer> 55 </div> 56 57 @Scripts.Render("~/bundles/jquery") 58 @Scripts.Render("~/bundles/bootstrap") 59 @RenderSection("scripts", required: false) 60 </body> 61 </html>
3.对Action根据权限信息进行显示
1 @using FormAuth.Models; 2 @{ 3 ViewBag.Title = "Index"; 4 var perList = ViewBag.PerList as List<Permission>; 5 } 6 7 8 <h2>Hello->Index</h2> 9 <div> 10 <ul > 11 @if (perList != null) 12 { 13 var helloList = perList.Where(m => m.CName.ToLower() == "hello"); 14 foreach (var item in helloList) 15 { 16 @Html.ActionLink(item.ActCnName,item.AName) 17 } 18 } 19 </ul> 20 </div>
Action的权限已经在 2.3节已进行验证
项目github地址:https://github.com/GYY2046/FormAuth
注意事项:项目使用VS2017 数据库为Local DB 数据库的连接字符串为绝对路径注意修改!
如有错误欢迎指正。