.net MVC使用IPrincipal进行Form登录即权限验证

网络转载  2018-04-10   作者:清幽火焰   [简洁网络]

本文作者主要为大家详细介绍了.net MVC使用IPrincipal进行Form登录即权限验证,具有一定的参考价值,感兴趣的码友们可以参考一下

.net MVC使用IPrincipal进行Form登录即权限验证,供大家参考,具体内容如下

1.在MVC项目中添加用户类,可以根据实际项目需求添加必要属性

public class UserData
 {
  /// <summary>
  /// ID
  /// </summary>
  public int UserId { get; set; }
  /// <summary>
  /// 用户名
  /// </summary>
  public string UserName { get; set; }
  /// <summary>
  /// 角色ID列表
  /// </summary>
  public List<int> Roles { get; set; }
 }

2.添加类Principal实现IPrincipal接口

public class Principal : IPrincipal
 {
  public IIdentity Identity { get; private set;}
  public UserData Account { get; set; }
  /// <summary>
  /// 构造函数
  /// </summary>
  /// <param name="ticket"></param>
  /// <param name="account"></param>
  public Principal(FormsAuthenticationTicket ticket, UserData account)
  {
   if (ticket == null)
    throw new ArgumentNullException("ticket");
   if (account == null)
    throw new ArgumentNullException("UserData");
   this.Identity = new FormsIdentity(ticket);
   this.Account = account;
  }
  public bool IsInRole(string role)
  {
   if (string.IsNullOrEmpty(role))
    return true;
   if (this.Account == null || this.Account.Roles == null)
    return false;
   return role.Split(',').Any(q => Account.Roles.Contains(int.Parse(q)));
  }
 }

IPrincipal接口有对象Identity已经需要实现验证角色方法IsInRole()。在我们的实现类中添加了"用户信息(UserData)"属性Account。

构造函数中进行了初始化,第一个对象为Form验证的票据对象,下面ticket会携带用户信息一起保存进cookie中。

3.创建存储cookie和读取cookie的类

/// <summary>
 /// 写入cookie和读取cookie
 /// </summary>
 public class HttpFormsAuthentication
 {
  //将用户信息通过ticket加密保存到cookie
  public static void SetAuthenticationCoolie(UserData account, int rememberDay = 0)
  {
   if (account == null)
    throw new ArgumentNullException("account");
   //序列化account对象
   string accountJson = JsonConvert.SerializeObject(account);
   //创建用户票据
   var ticket = new FormsAuthenticationTicket(1, account.UserName, DateTime.Now, DateTime.Now.AddDays(rememberDay), false, accountJson);
   //加密
   string encryptAccount = FormsAuthentication.Encrypt(ticket);
   //创建cookie
   var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptAccount)
   {
    HttpOnly = true,
    Secure = FormsAuthentication.RequireSSL,
    Domain = FormsAuthentication.CookieDomain,
    Path = FormsAuthentication.FormsCookiePath
   };
   if (rememberDay > 0)
    cookie.Expires = DateTime.Now.AddDays(rememberDay);
   //写入Cookie
   HttpContext.Current.Response.Cookies.Remove(cookie.Name);
   HttpContext.Current.Response.Cookies.Add(cookie);
  }
  //获取cookie并解析出用户信息
  public static Principal TryParsePrincipal(HttpContext context)
  {
   if (context == null)
    throw new ArgumentNullException("context");
   HttpRequest request = context.Request;
   HttpCookie cookie = request.Cookies[FormsAuthentication.FormsCookieName];
   if (cookie == null || string.IsNullOrEmpty(cookie.Value))
   {
    return null;
   }
   //解密coolie值
   FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookie.Value);
   UserData account = JsonConvert.DeserializeObject<UserData>(ticket.UserData);
   return new Principal(ticket, account);
  }
 }

存储cookie时将用户信息序列化后的字符串accountJson由ticket其携带加密后保存入cookie中,具体的accountJson被赋值给FormsAuthenticationTicket的UserData属性。

可看到解析时将ticket.UserData反序列化后得到了原始的用户信息对象,然后生成Principal对象。

解析cookie得到Principal对象的方法TryParsePrincipal,下面会在发起请求时用到,而返回的Principal对象被赋值给HttpContext.User。

4.在Global.asax中注册Application_PostAuthenticateRequest事件,保证权限验证前将cookie中的用户信息取出赋值给User

protected void Application_PostAuthenticateRequest(object sender, System.EventArgs e)
  {
   HttpContext.Current.User =
    HttpFormsAuthentication.TryParsePrincipal(HttpContext.Current);
  }

 5.集成AuthorizeAttribute特性类并重写AuthorizeCore,HandleUnauthorizedRequest方法

public class FormAuthorizeAttribute : AuthorizeAttribute
 {
  /// <summary>
  /// 先进入此方法,此方法中会调用 AuthorizeCore 验证逻辑,验证不通过会调用 HandleUnauthorizedRequest 方法
  /// </summary>
  /// <param name="filterContext"></param>
  public override void OnAuthorization(AuthorizationContext filterContext)
  {
   base.OnAuthorization(filterContext);
  }
  /// <summary>
  /// 权限验证
  /// </summary>
  /// <param name="httpContext"></param>
  /// <returns></returns>
  protected override bool AuthorizeCore(HttpContextBase httpContext)
  {
   var user = httpContext.User as Principal;
   if (user != null)
    return user.IsInRole(base.Roles);
   return false;
  }
  protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
  {
   //验证不通过,直接跳转到相应页面,注意:如果不是哟娜那个以下跳转,则会继续执行Action方法
   filterContext.Result = new RedirectResult("~/Login/Index");
  }
 }

AuthorizeCore与HandleUnauthorizedRequest方法均是在方法OnAuthorization中调用,AuthorizeCore验证不通过才会调用HandleUnauthorizedRequest方法。

将验证代码在AuthorizeCore中实现,验证不通过的逻辑在HandleUnauthorizedRequest方法中实现。

6.添加LoginController实现登录逻辑

namespace MVCAuthorizeTest.Controllers
{
 public class LoginController : Controller
 {
  [AllowAnonymous]
  // GET: Login
  public ActionResult Index(string returnUrl)
  {
   ViewBag.ReturnUrl = returnUrl;
   return View();
  }
  [HttpPost]
  [AllowAnonymous]
  public ActionResult Index(string name, string password, bool rememberMe, string returnUrl)
  {
   var account = new UserData()
   {
    UserName = name,
    UserId = 110,
    Roles = new List<int>() { 1, 2, 3 }
   };
   HttpFormsAuthentication.SetAuthenticationCoolie(account, rememberMe ? 7 : 0);
   if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/") && !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\"))
   {
    return Redirect(returnUrl);
   }
   else
   {
    return RedirectToAction("Index", "Home");
   }
  }
  // POST: /Account/LogOff
  [HttpPost]
  public ActionResult LogOff()
  {
   System.Web.Security.FormsAuthentication.SignOut();
   return RedirectToAction("Index", "Home");
  }
 }
}

7.对需要验证的controller或action添加特性标签

 [FormAuthorize(Roles = "1,2")]
 public class HomeController : Controller
 {
  [FormAuthorize]
  public ActionResult Index()
  {
   return View();
  }
 }

如图

8.在添加FilterConfig中添加全局注册filter,减少每个action分别设置。如果有不需要验证的页面,添加[AllowAnonymous]特性即可

public class FilterConfig
 {
 public static void RegisterGlobalFilters(GlobalFilterCollection filters)
 {
  filters.Add(new HandleErrorAttribute());
  //全局注册filter
  filters.Add(new FormAuthorizeAttribute());
 }
 }

以上内容便是本文的全部内容,希望对广大码友们的学习有所帮助,也希望广大码友多多支持我们的简洁网络。

相关文章