在ASP.NET Identity 2.0中使用声明(Claims)实现用户组
目录
介绍
背景
使用代码
步骤1:数据库修改
步骤2:动作(Actions)储存
步骤3:分组控制动作
步骤4:授权验证“ClaimsAuthorizeAttribute”
第5步:声明分配
- 从Github下载源代码
介绍
ASP.NET Identity是通过建立ASP.NET应用程序来对用户进行身份验证和授权的membershi系统。
服务器使用身份验证来确定谁正在访问其信息或网站。在身份验证中,用户或客户必须通过使用电子邮件和文字或使用各种社交提供程序登录来在Web服务器上证明其身份。
授权是一个过程,服务器通过该过程可以确定客户端在成功进行身份验证之后是否具有使用资源或访问文件的权限。
有关更多详细信息,请阅读原始文章。
ASP.NET身份仅使用角色和声明来实现授权,在某些应用程序中,如果您的业务逻辑需要额外的授权管理层(例如用户组),则您总是尝试从ASP.NET Identity上实现这一点,因为它们本身并不提供表格或方法来实现这一层。
背景
ASP.NET Identity本机提供了一个默认架构,您可以在其中添加任何扩展表作为以下架构:
使用代码
此实现包括以下步骤:
步骤1:数据库修改
当然,要引入用户组功能,您需要添加一些表来存储此信息。
在此实现中,我们只需要添加以下表格:
- tblGroups {PK_Id, Name}
- tblGroupActions {PK_Id, FK_Group, ActionName}
- tblUserGroups {PK_Id, FK_Group, FK_User}
但是tblActions呢在哪里?这就是技巧,将在下一节中说明。
步骤2:动作(Actions)储存
我的动作将存储在哪里?实际上,动作是在应用程序层中定义的,因此每次创建动作时,在某些表中添加动作条目都是多余的。
因此,如果我们创建了一个函数来检索应用程序中的所有动作,那么我们的工作就完成了。这可以通过以下功能实现:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;namespace UserManagmentSystem.Controllers
{public class ImplementedMethods{public List ActiveMethods;public ImplementedMethods(){var asm = Assembly.GetExecutingAssembly();ActiveMethods = asm.GetTypes().Where(type => typeof(Controller).IsAssignableFrom(type)).SelectMany(type => type.GetMethods()).Where(method => method.IsPublic&& !method.IsDefined(typeof(NonActionAttribute))&& (method.CustomAttributes.Any(s => s.AttributeType == typeof(HttpPostAttribute)) ||method.CustomAttributes.Any(s => s.AttributeType == typeof(HttpGetAttribute)))&& (!method.CustomAttributes.Any(s => s.AttributeType == typeof(AllowAnonymousAttribute)))&& method.CustomAttributes.Any(s => s.AttributeType == typeof(ClaimsAuthorizeAttribute))&& (method.ReturnType == typeof(ActionResult) ||method.ReturnType == typeof(Task) ||method.ReturnType == typeof(String) )).Select(m => m.CustomAttributes.FirstOrDefault(s => s.AttributeType == typeof(HttpPostAttribute) || s.AttributeType == typeof(HttpGetAttribute)).AttributeType.Name.Replace("Attribute", "") + " : " + m.DeclaringType.ToString().Split('.')[2].Replace("Controller", "") + "/" + m.Name).ToList();}}
}
先前功能的主要目标是检索所有控制器方法,这些方法是:
是由GET或POST装饰,而不是AllowAnonymousAttribute,并有一个自定义装饰“ClaimsAuthorizeAttribute”,以确保行动将被添加到池中,并且确保操作将检查登录用户的声明
步骤3:分组控制动作
现在,它很容易创建组到控制器{ Add,Edit,Delete,Details,AddAction,RevokeAction}:
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;
using AccountingSystem.Models;
using Audit.Mvc;namespace UserManagmentSystem.Controllers
{[Authorize]public class GroupsController : Controller{private AccountingdbEntities db = new AccountingdbEntities();// GET: Groupspublic ActionResult Index(){return View(db.tblGroups.ToList());}// GET: Groups/Details/5public ActionResult Details(int? id){if (id == null){return new HttpStatusCodeResult(HttpStatusCode.BadRequest);}tblGroups tblGroups = db.tblGroups.Find(id);if (tblGroups == null){return HttpNotFound();}GroupsViewModel groupsViewModel = new GroupsViewModel();ImplementedMethods implementedMethods = new ImplementedMethods();groupsViewModel.Name = tblGroups.Name;groupsViewModel.PK_Id = tblGroups.PK_Id;groupsViewModel.Actions = tblGroups.tblGroupActions.Select(s => new ActionsViewModel{PK_Id = s.PK_Id,Name = s.ActionName}).ToList();groupsViewModel.Users = tblGroups.tblUserGroups.Select(s => new UsersViewModel{Id = s.AspNetUsers.Id,Name = s.AspNetUsers.UserName,OrdersConut = db.tblOrderStatusHistory.Where(k => k.FK_User == s.AspNetUsers.Id && k.tblOrderStatus.IsFirst && k.tblOrderStatus.IsDefault).Count()}).ToList();ViewBag.AvailableActions = implementedMethods.ActiveMethods.Where(t => !db.tblGroupActions.Any(k => k.FK_Group == id && k.ActionName == t)).Select(s => new SelectListItem { Value = s, Text = s }).ToList();return View(groupsViewModel);}[HttpPost][ValidateAntiForgeryToken]public ActionResult RevokeAction(int GroupId, string ActionName){tblGroupActions tblGroupActions = db.tblGroupActions.FirstOrDefault(s=> s.FK_Group == GroupId && s.ActionName == ActionName);if (tblGroupActions!= null){db.tblGroupActions.Remove(tblGroupActions);db.SaveChanges();} return RedirectToAction("Details", new { id = GroupId });}[HttpPost][ValidateAntiForgeryToken]public ActionResult AddAction(int GroupId, string ActionName){tblGroupActions tblGroupActions = new tblGroupActions() { ActionName = ActionName, FK_Group = GroupId };if (tblGroupActions != null){db.tblGroupActions.Add(tblGroupActions);db.SaveChanges();}return RedirectToAction("Details", new { id = GroupId });}[HttpPost][ValidateAntiForgeryToken]public ActionResult RevokeUser(int GroupId, string UserId){tblUserGroups tblUserGroups = db.tblUserGroups.FirstOrDefault(s => s.FK_Group == GroupId && s.FK_User == UserId);if (tblUserGroups != null){db.tblUserGroups.Remove(tblUserGroups);db.SaveChanges();}return RedirectToAction("Details", new { id = GroupId });}protected override void Dispose(bool disposing){if (disposing){db.Dispose();}base.Dispose(disposing);}}
}
步骤4:授权验证“ClaimsAuthorizeAttribute”
通过应用此自定义AuthorizeAttribute,我们可以确保应用程序将检查CurrentUser声明是否具有此操作的声明。
关于身份声明和角色的妙处在于,在当前登录会话中,UserManager将用户声明和角色存储在内存中,因此无需每次都访问数据库来检查声明:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Web;
using System.Web.Mvc;namespace UserManagmentSystem.Controllers
{public class ClaimsAuthorizeAttribute : AuthorizeAttribute{private string claimType;public ClaimsAuthorizeAttribute(string type){this.claimType = type;}public override void OnAuthorization(AuthorizationContext filterContext){var user = filterContext.HttpContext.User as ClaimsPrincipal;if (user != null && user.HasClaim(claimType, claimType)){base.OnAuthorization(filterContext);}else{base.HandleUnauthorizedRequest(filterContext);}}}
}
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;namespace UserManagmentSystem.Controllers
{[Authorize]public class CarriersController : Controller{[ClaimsAuthorize("HttpGet : Carriers/Index")][HttpGet]public ActionResult Index(){//}[ClaimsAuthorize("HttpGet : Carriers/Details")][HttpGet]public ActionResult Details(int? id){//}[ClaimsAuthorize("HttpGet : Carriers/Create")][HttpGet]public ActionResult Create(){//}[HttpPost][ValidateAntiForgeryToken][ClaimsAuthorize("HttpPost : Carriers/Create")]public ActionResult Create(Model){//} }
}
第5步:声明分配
在此实现中,我们发现最好通过登录分配用户声明,因为tblGroupActions 表中的任何更改仅在登录后才会生效。
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{if (!ModelState.IsValid){return View(model);}var user = UserManager.Find(model.Email, model.Password);if (user != null){var UserClaim = user.Claims.AsEnumerable().ToList();foreach (IdentityUserClaim claim in UserClaim){await UserManager.RemoveClaimAsync(user.Id, new Claim(claim.ClaimType, claim.ClaimValue));}var UserClaims = db.tblGroupActions.AsEnumerable().Where(s => s.tblGroups.tblUserGroups.Any(l => l.FK_User == user.Id)).Select(k => new Claim(k.ActionName, k.ActionName)).ToList();foreach (Claim cliam in UserClaims){await UserManager.AddClaimAsync(user.Id, cliam);}}// This doesn't count login failures towards account lockout// To enable password failures to trigger account lockout,// change to shouldLockout: truevar result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: true);switch (result){case SignInStatus.Success:return RedirectToLocal(returnUrl);case SignInStatus.LockedOut:return View("Lockout");case SignInStatus.RequiresVerification:return RedirectToAction("SendCode",new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });case SignInStatus.Failure:default:ModelState.AddModelError("", "Invalid login attempt.");return View(model);}
}
为特定组添加操作:
在ASP.NET Identity 2.0中使用声明(Claims)实现用户组相关推荐
- 避免在 ASP.NET Core 3.0 中为启动类注入服务
本篇是如何升级到ASP.NET Core 3.0系列文章的第二篇. Part 1 - 将.NET Standard 2.0 类库转换为.NET Core 3.0 类库 Part 2 - IHostin ...
- ASP.NET Core 3.0中使用动态控制器路由
原文:Dynamic controller routing in ASP.NET Core 3.0 作者:Filip W 译文:https://www.cnblogs.com/lwqlun/p/114 ...
- asp.net core 3.0 中使用 swagger
asp.net core 3.0 中使用 swagger Intro 上次更新了 asp.net core 3.0 简单的记录了一下 swagger 的使用,那个项目的 api 比较简单,都是匿名接口 ...
- ASP.Net Core 2.0中的Razor Page不是WebForm
随着.net core2.0的发布,我们可以创建2.0的web应用了.2.0中新东西的出现,会让我们忘记老的东西,他就是Razor Page.下面的这篇博客将会介绍ASP.Net Core 2.0中的 ...
- 在ASP.NET Core 2.0中使用CookieAuthentication
在ASP.NET Core中关于Security有两个容易混淆的概念一个是Authentication(认证),一个是Authorization(授权).而前者是确定用户是谁的过程,后者是围绕着他们允 ...
- 在ASP.NET Core 2.0中创建Web API
目录 介绍 先决条件 软件 技能 使用代码 第01步 - 创建项目 第02步 - 安装Nuget包 步骤03 - 添加模型 步骤04 - 添加控制器 步骤05 - 设置依赖注入 步骤06 - 运行We ...
- asp.net ajax 1.0中detailview与updatepanel混合使用的例子
asp.net ajax 1.0中detailview与updatepanel混合使用的例子 在asp.net ajax 1.0中,如果有一个detailview控件,想做到每点detailview中 ...
- ASP.NET AJAX 4.0 中的数据绑定
代码下载: 围绕该 bush 击退停止:AJAX 是可能仅使用一个强的 JavaScript 引擎,可以在客户端浏览器中运行,并提供更高级和异步功能基础的. JavaScript 库当前包含在 ASP ...
- ASP.NET Core 3.0中支持AI的生物识别安全
本文共两个部分,这是第一部分,其中介绍了 ASP.NET Core 3 中旨在将授权逻辑与基本的用户角色相分离的基于策略的授权模型. 此部分提供了此授权进程的基于生物识别信息(如人脸识别或语音识别)的 ...
最新文章
- 面试小结之Elasticsearch篇
- centos5.8 安装配置vsftp虚拟用户
- 视频编辑SDK---我们只提供API,任你自由设计炫酷的功能
- Learn About Salesforce Flow for Service
- html5长按保存,iOS UIWebView仿微信H5页面实现长按保存图片功能
- 甲骨文严查Java授权,企业连夜删除JDK
- Fedora/CentOS7/RedHat7关闭图形桌面开启文本界面
- zookeeper 日志查看_不懂 Zookeeper?看完不懂你打我
- php ci controller,Codeigniter – CI_Controller与控制器
- 什么是Adam/ReLU/YOLO?这里有一份深度学习(.ai)词典
- 苹果Mac轻量级网页代码编辑器:​​​​​​​​​​​​Espresso
- SPSS说明附学习方法
- PMP-8. 项目经理的能力
- 【智能无线小车系列九】在树莓派上使用USB摄像头
- python求学生成绩平均值_python 计算student_grade.txt 中 语文成绩的平均值, 找出数学成绩最高的学生是谁...
- 小白:关于处理“can't find '__main__' module in ”这个问题的详细处理方式!
- 华维单片机编程-无线红外探测器03-环境搭建及程序详解
- 域控中同一计算机名字,更改域控的计算机名
- 【Day_09】走方格的方案数
- OCJP(1Z0-851) 模拟题分析(三)