热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

.netMVC使用IPrincipal进行Form登录即权限验证(3)

这篇文章主要为大家详细介绍了.netMVC使用IPrincipal进行Form登录即权限验证,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

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

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

public class UserData
 {
 /// 
 /// ID
 /// 
 public int UserId { get; set; }

 /// 
 /// 用户名
 /// 
 public string UserName { get; set; }

 /// 
 /// 角色ID列表
 /// 
 public List Roles { get; set; }
 }

2.添加类Principal实现IPrincipal接口

public class Principal : IPrincipal
 {
 public IIdentity Identity { get; private set;}

 public UserData Account { get; set; }

 /// 
 /// 构造函数
 /// 
 /// 
 /// 
 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的类

/// 
 /// 写入COOKIE和读取COOKIE
 /// 
 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(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
 {
 /// 
 /// 先进入此方法,此方法中会调用 AuthorizeCore 验证逻辑,验证不通过会调用 HandleUnauthorizedRequest 方法
 /// 
 /// 
 public override void OnAuthorization(AuthorizationContext filterContext)
 {
  base.OnAuthorization(filterContext);
 }

 /// 
 /// 权限验证
 /// 
 /// 
 /// 
 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() { 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());
 }
 }

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


推荐阅读
  • 本文介绍了Hyperledger Fabric外部链码构建与运行的相关知识,包括在Hyperledger Fabric 2.0版本之前链码构建和运行的困难性,外部构建模式的实现原理以及外部构建和运行API的使用方法。通过本文的介绍,读者可以了解到如何利用外部构建和运行的方式来实现链码的构建和运行,并且不再受限于特定的语言和部署环境。 ... [详细]
  • t-io 2.0.0发布-法网天眼第一版的回顾和更新说明
    本文回顾了t-io 1.x版本的工程结构和性能数据,并介绍了t-io在码云上的成绩和用户反馈。同时,还提到了@openSeLi同学发布的t-io 30W长连接并发压力测试报告。最后,详细介绍了t-io 2.0.0版本的更新内容,包括更简洁的使用方式和内置的httpsession功能。 ... [详细]
  • SpringMVC接收请求参数的方式总结
    本文总结了在SpringMVC开发中处理控制器参数的各种方式,包括处理使用@RequestParam注解的参数、MultipartFile类型参数和Simple类型参数的RequestParamMethodArgumentResolver,处理@RequestBody注解的参数的RequestResponseBodyMethodProcessor,以及PathVariableMapMethodArgumentResol等子类。 ... [详细]
  • 在Docker中,将主机目录挂载到容器中作为volume使用时,常常会遇到文件权限问题。这是因为容器内外的UID不同所导致的。本文介绍了解决这个问题的方法,包括使用gosu和suexec工具以及在Dockerfile中配置volume的权限。通过这些方法,可以避免在使用Docker时出现无写权限的情况。 ... [详细]
  • 学习SLAM的女生,很酷
    本文介绍了学习SLAM的女生的故事,她们选择SLAM作为研究方向,面临各种学习挑战,但坚持不懈,最终获得成功。文章鼓励未来想走科研道路的女生勇敢追求自己的梦想,同时提到了一位正在英国攻读硕士学位的女生与SLAM结缘的经历。 ... [详细]
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 本文介绍了brain的意思、读音、翻译、用法、发音、词组、同反义词等内容,以及脑新东方在线英语词典的相关信息。还包括了brain的词汇搭配、形容词和名词的用法,以及与brain相关的短语和词组。此外,还介绍了与brain相关的医学术语和智囊团等相关内容。 ... [详细]
  • 云原生边缘计算之KubeEdge简介及功能特点
    本文介绍了云原生边缘计算中的KubeEdge系统,该系统是一个开源系统,用于将容器化应用程序编排功能扩展到Edge的主机。它基于Kubernetes构建,并为网络应用程序提供基础架构支持。同时,KubeEdge具有离线模式、基于Kubernetes的节点、群集、应用程序和设备管理、资源优化等特点。此外,KubeEdge还支持跨平台工作,在私有、公共和混合云中都可以运行。同时,KubeEdge还提供数据管理和数据分析管道引擎的支持。最后,本文还介绍了KubeEdge系统生成证书的方法。 ... [详细]
  • 本文介绍了设计师伊振华受邀参与沈阳市智慧城市运行管理中心项目的整体设计,并以数字赋能和创新驱动高质量发展的理念,建设了集成、智慧、高效的一体化城市综合管理平台,促进了城市的数字化转型。该中心被称为当代城市的智能心脏,为沈阳市的智慧城市建设做出了重要贡献。 ... [详细]
  • uniapp开发H5解决跨域问题的两种代理方法
    本文介绍了uniapp开发H5解决跨域问题的两种代理方法,分别是在manifest.json文件和vue.config.js文件中设置代理。通过设置代理根域名和配置路径别名,可以实现H5页面的跨域访问。同时还介绍了如何开启内网穿透,让外网的人可以访问到本地调试的H5页面。 ... [详细]
  • python限制递归次数(python最大公约数递归)
    本文目录一览:1、python为什么要进行递归限制 ... [详细]
  • 本文介绍了如何使用JSONObiect和Gson相关方法实现json数据与kotlin对象的相互转换。首先解释了JSON的概念和数据格式,然后详细介绍了相关API,包括JSONObject和Gson的使用方法。接着讲解了如何将json格式的字符串转换为kotlin对象或List,以及如何将kotlin对象转换为json字符串。最后提到了使用Map封装json对象的特殊情况。文章还对JSON和XML进行了比较,指出了JSON的优势和缺点。 ... [详细]
  • 图像因存在错误而无法显示 ... [详细]
  • 本文介绍了一个React Native新手在尝试将数据发布到服务器时遇到的问题,以及他的React Native代码和服务器端代码。他使用fetch方法将数据发送到服务器,但无法在服务器端读取/获取发布的数据。 ... [详细]
author-avatar
手机用户2602925995
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有