侯体宗的博客
  • 首页
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

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

框架(架构)  /  管理员 发布于 7年前   170

.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()); } }

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


  • 上一条:
    Yii实现简单分页的方法
    下一条:
    Yii查询生成器(Query Builder)用法实例教程
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • Filament v3.1版本发布(0个评论)
    • docker + gitea搭建一个git服务器流程步骤(0个评论)
    • websocket的三种架构方式使用优缺点浅析(0个评论)
    • ubuntu20.4系统中宿主机安装nginx服务,docker容器中安装php8.2实现运行laravel10框架网站(0个评论)
    • phpstudy_pro(小皮面板)中安装最新php8.2.9版本流程步骤(0个评论)
    • 近期文章
    • 在go语言中实现字符串可逆性压缩及解压缩功能(0个评论)
    • 使用go + gin + jwt + qrcode实现网站生成登录二维码在app中扫码登录功能(0个评论)
    • 在windows10中升级go版本至1.24后LiteIDE的Ctrl+左击无法跳转问题解决方案(0个评论)
    • 智能合约Solidity学习CryptoZombie第四课:僵尸作战系统(0个评论)
    • 智能合约Solidity学习CryptoZombie第三课:组建僵尸军队(高级Solidity理论)(0个评论)
    • 智能合约Solidity学习CryptoZombie第二课:让你的僵尸猎食(0个评论)
    • 智能合约Solidity学习CryptoZombie第一课:生成一只你的僵尸(0个评论)
    • 在go中实现一个常用的先进先出的缓存淘汰算法示例代码(0个评论)
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2018-05
    • 2020-02
    • 2020-03
    • 2020-05
    • 2020-06
    • 2020-07
    • 2020-08
    • 2020-11
    • 2021-03
    • 2021-09
    • 2021-10
    • 2021-11
    • 2022-01
    • 2022-02
    • 2022-03
    • 2022-08
    • 2023-08
    • 2023-10
    • 2023-12
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客