ASP.NET MVC5 Forms登陆+权限控制(控制到Action)

一、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>&copy; @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 数据库的连接字符串为绝对路径注意修改!

如有错误欢迎指正。

原文地址:https://www.cnblogs.com/GYY2046/p/8763412.html