2023年6月20日发(作者:)
webapi框架搭建-安全机制(四)-可配置的基于⾓⾊的权限控制 在上⼀篇的,某个⾓⾊拥有哪些接⼝的权限是⽤硬编码的⽅式写在接⼝上的,如RBAuthorize(Roles = "user,member"),在⼩的项⽬⾥,其实也够⽤了,但如果项⽬的需求就是要可在后台管理界⾯⾥动态配置某某⾓⾊有某某接⼝的权限怎么办?这编我们⼀起来实现。 ⾸先,我们要在数据库⾥存储这些需要权限控制的接⼝,其次,要在上编的RBAuthorizeAttribute的IsAuthorized⽅法⾥重写⾃⼰逻辑。实体设计(数据库表设计) 共4张表:⽤户表、⾓⾊表、资源表、权限表 ⽤户表:只记录⽤户的基本信息,如id,⽤户名,姓名,性别,密码等 ⾓⾊表:只记录⾓⾊的基本信息,如⾓⾊名,id 资源表:只记录“需要做权限控制的资源”,这些“资源”可以是菜单,接⼝等。 权限表:记录“哪些⾓⾊对哪些资源有访问权限” ⽤户⾓⾊关系表:记录⽤户和⾓⾊的关系四个表的实体对应如下⽤户表using System;using notations;using ;namespace es{ /// /// ⽤户表 /// [Table("User")] public partial class User:BaseEntity { /// /// 主键 /// [Key, Column(TypeName = "varchar"), MaxLength(50)] public string Id { get; set; } /// /// 登录名 /// [Column(TypeName = "varchar"), MaxLength(50)] public string LoginName { get; set; } /// /// 真实姓名 /// [Column(TypeName = "varchar"), MaxLength(50)] public string Name { get; set; } /// /// 密码,⽤于存储密码的md5加密 /// [Column(TypeName = "varchar"), MaxLength(50)] public string Pwd { get; set; } /// /// 性别,1男2⼥,对应Gender枚举 /// [Column(TypeName = "int")] public int? Gender { get; set; } /// /// ⾝份证 /// [Column(TypeName = "varchar"), MaxLength(50)] public string IdentityCard { get; set; } /// /// 电话 /// [Column(TypeName = "varchar"), MaxLength(50)] public string Tel { get; set; } /// /// 出⽣⽇期 /// [Column(TypeName = "datetime")] public DateTime? Birthdate { get; set; } /// /// 头像 /// [Column(TypeName = "varchar"), MaxLength(500)] public string UserPic { get; set; } }} ⾓⾊表using notations;using ;namespace es{ /// /// ⾓⾊表 /// [Table("Role")] public partial class Role:BaseEntity { /// /// ⾓⾊ID /// [Key, Column(TypeName = "varchar"), MaxLength(50)] public string Id { get; set; } /// /// ⾓⾊名 /// [Column(TypeName = "varchar"), MaxLength(20)] public string Name { get; set; }
}} ⽤户⾓⾊关系表using notations;using ;namespace es{ /// /// ⽤户⾓⾊关系对应表,user role map /// [Table("URM")] public partial class URM:BaseEntity { /// /// ID主键 /// [Key, Column(TypeName = "varchar"), MaxLength(50)] public string Id { get; set; } /// /// ⽤户ID /// [Column(TypeName = "varchar"), MaxLength(50)] public string UserId { get; set; } /// /// ⾓⾊ID /// [Column(TypeName = "varchar"), MaxLength(50)] public string RoleId { get; set; }
}} 资源表using notations;using ;namespace es{ /// /// 需要做权限控制的资源 /// [Table("Resource")] public class Resource:BaseEntity { /// /// 主键 /// [Key,Column(TypeName = "varchar"),MaxLength(50)] public string Id { set; get; } /// /// 资源类型,如webapi接⼝,菜单等 /// [Column(TypeName = "varchar"), MaxLength(20)] public string Category { set; get; } /// /// 资源名,如“Name”,或是“url地址” /// [Column(TypeName = "varchar"), MaxLength(100)] public string Name { set; get; } /// /// 资源描述 /// [Column(TypeName = "varchar"), MaxLength(200)] public string Description { set; get; } }} 权限表using notations;using ;namespace es{ /// /// 权限表,记录⾓⾊和资源的对应关系 /// [Table("Permission")] public class Permission:BaseEntity { /// /// 主键 /// [Key, Column(TypeName = "varchar"), MaxLength(50)] public string Id { set; get; } /// /// 资源类型,如webapi接⼝,菜单等 /// [Column(TypeName = "varchar"), MaxLength(50)] public string RoleId { set; get; } /// /// 资源名,如“Name”,或是“url地址” /// [Column(TypeName = "varchar"), MaxLength(50)] public string ResourceId { set; get; } }} RBAuthorizeAttribute代码修改核⼼代码:using System;using c;using ;using ;using ;using pal;using ;using llers;using es;using es;namespace ty{ /// /// Role Basic AuthorizeAttribute(基于⾓⾊的授权) /// public class RBAuthorizeAttribute : AuthorizeAttribute { public string Description { set; get; } protected override bool IsAuthorized(HttpActionContext actionContext) {
// 下在可替换成⾃⼰的授权逻辑代码 AuthorizeService authorizeService =new AuthorizeService(new DB()); var resourceName = tomAttributes().Any() Name : llerName; var roleNames = ourceRoleNames(resourceName); IPrincipal principal = pal; return principal != null && ty != null && enticated && ( (((IEnumerable)roleNames).Any(new Func(le))) ); } protected override void HandleUnauthorizedRequest(HttpActionContext actionContext) { se = ErrorResponse(orized, "未授权"); } }} 说明:在IsAuthorized⽅法⾥判断⽤户是否有某个资源的权限。下⾯是我的思路 1)获取⽤户的⾓⾊ 在前⾯的博客⾥,IdentityBasicAuthentication已经从http请求头⾥将token解密并知道了⽤户的⾓⾊,并将⾓⾊写⼊到了IPrincipal对象,所以RBAuthorizeAttribute只要从IPrincipal⾥取出来就⾏,即如下的代码:IPrincipal principal =pal; 2)获取该请求资源的所有⾓⾊数组 我创建了authorizeService类,⽤于处理这⼀个逻辑,博友们可以下载我的框架,只要改⼀下authorizeService类⾥的GetResourceRoleNames⽅法就⾏。 3)判断是否有权限
⾸先principal不能为空,且ty是已经通过⾝份验证的(即enticated==true),并且⽤户的⾓⾊在资源权限⾓⾊数组⾥。 return principal != null && ty != null && enticated && ( (((IEnumerable)roleNames).Any(new Func(le))) );各辅助代码也附上AuthorizeService代码using System;using c;using ;using ;using es;namespace es{ public class AuthorizeService:BaseService { public AuthorizeService(DB db) : base(db) { } /// /// 获取资源的⾓⾊名数组 /// /// /// public string[] GetResourceRoleNames(string resourceName) { var resource=_rDefault(a => == resourceName); var roleIds = _(a => ceId == ).Select(a => ).ToArray(); var roleNames = _(a => ns()).Select(a => ).ToArray(); return roleNames; }
}}
2023年6月20日发(作者:)
webapi框架搭建-安全机制(四)-可配置的基于⾓⾊的权限控制 在上⼀篇的,某个⾓⾊拥有哪些接⼝的权限是⽤硬编码的⽅式写在接⼝上的,如RBAuthorize(Roles = "user,member"),在⼩的项⽬⾥,其实也够⽤了,但如果项⽬的需求就是要可在后台管理界⾯⾥动态配置某某⾓⾊有某某接⼝的权限怎么办?这编我们⼀起来实现。 ⾸先,我们要在数据库⾥存储这些需要权限控制的接⼝,其次,要在上编的RBAuthorizeAttribute的IsAuthorized⽅法⾥重写⾃⼰逻辑。实体设计(数据库表设计) 共4张表:⽤户表、⾓⾊表、资源表、权限表 ⽤户表:只记录⽤户的基本信息,如id,⽤户名,姓名,性别,密码等 ⾓⾊表:只记录⾓⾊的基本信息,如⾓⾊名,id 资源表:只记录“需要做权限控制的资源”,这些“资源”可以是菜单,接⼝等。 权限表:记录“哪些⾓⾊对哪些资源有访问权限” ⽤户⾓⾊关系表:记录⽤户和⾓⾊的关系四个表的实体对应如下⽤户表using System;using notations;using ;namespace es{ /// /// ⽤户表 /// [Table("User")] public partial class User:BaseEntity { /// /// 主键 /// [Key, Column(TypeName = "varchar"), MaxLength(50)] public string Id { get; set; } /// /// 登录名 /// [Column(TypeName = "varchar"), MaxLength(50)] public string LoginName { get; set; } /// /// 真实姓名 /// [Column(TypeName = "varchar"), MaxLength(50)] public string Name { get; set; } /// /// 密码,⽤于存储密码的md5加密 /// [Column(TypeName = "varchar"), MaxLength(50)] public string Pwd { get; set; } /// /// 性别,1男2⼥,对应Gender枚举 /// [Column(TypeName = "int")] public int? Gender { get; set; } /// /// ⾝份证 /// [Column(TypeName = "varchar"), MaxLength(50)] public string IdentityCard { get; set; } /// /// 电话 /// [Column(TypeName = "varchar"), MaxLength(50)] public string Tel { get; set; } /// /// 出⽣⽇期 /// [Column(TypeName = "datetime")] public DateTime? Birthdate { get; set; } /// /// 头像 /// [Column(TypeName = "varchar"), MaxLength(500)] public string UserPic { get; set; } }} ⾓⾊表using notations;using ;namespace es{ /// /// ⾓⾊表 /// [Table("Role")] public partial class Role:BaseEntity { /// /// ⾓⾊ID /// [Key, Column(TypeName = "varchar"), MaxLength(50)] public string Id { get; set; } /// /// ⾓⾊名 /// [Column(TypeName = "varchar"), MaxLength(20)] public string Name { get; set; }
}} ⽤户⾓⾊关系表using notations;using ;namespace es{ /// /// ⽤户⾓⾊关系对应表,user role map /// [Table("URM")] public partial class URM:BaseEntity { /// /// ID主键 /// [Key, Column(TypeName = "varchar"), MaxLength(50)] public string Id { get; set; } /// /// ⽤户ID /// [Column(TypeName = "varchar"), MaxLength(50)] public string UserId { get; set; } /// /// ⾓⾊ID /// [Column(TypeName = "varchar"), MaxLength(50)] public string RoleId { get; set; }
}} 资源表using notations;using ;namespace es{ /// /// 需要做权限控制的资源 /// [Table("Resource")] public class Resource:BaseEntity { /// /// 主键 /// [Key,Column(TypeName = "varchar"),MaxLength(50)] public string Id { set; get; } /// /// 资源类型,如webapi接⼝,菜单等 /// [Column(TypeName = "varchar"), MaxLength(20)] public string Category { set; get; } /// /// 资源名,如“Name”,或是“url地址” /// [Column(TypeName = "varchar"), MaxLength(100)] public string Name { set; get; } /// /// 资源描述 /// [Column(TypeName = "varchar"), MaxLength(200)] public string Description { set; get; } }} 权限表using notations;using ;namespace es{ /// /// 权限表,记录⾓⾊和资源的对应关系 /// [Table("Permission")] public class Permission:BaseEntity { /// /// 主键 /// [Key, Column(TypeName = "varchar"), MaxLength(50)] public string Id { set; get; } /// /// 资源类型,如webapi接⼝,菜单等 /// [Column(TypeName = "varchar"), MaxLength(50)] public string RoleId { set; get; } /// /// 资源名,如“Name”,或是“url地址” /// [Column(TypeName = "varchar"), MaxLength(50)] public string ResourceId { set; get; } }} RBAuthorizeAttribute代码修改核⼼代码:using System;using c;using ;using ;using ;using pal;using ;using llers;using es;using es;namespace ty{ /// /// Role Basic AuthorizeAttribute(基于⾓⾊的授权) /// public class RBAuthorizeAttribute : AuthorizeAttribute { public string Description { set; get; } protected override bool IsAuthorized(HttpActionContext actionContext) {
// 下在可替换成⾃⼰的授权逻辑代码 AuthorizeService authorizeService =new AuthorizeService(new DB()); var resourceName = tomAttributes().Any() Name : llerName; var roleNames = ourceRoleNames(resourceName); IPrincipal principal = pal; return principal != null && ty != null && enticated && ( (((IEnumerable)roleNames).Any(new Func(le))) ); } protected override void HandleUnauthorizedRequest(HttpActionContext actionContext) { se = ErrorResponse(orized, "未授权"); } }} 说明:在IsAuthorized⽅法⾥判断⽤户是否有某个资源的权限。下⾯是我的思路 1)获取⽤户的⾓⾊ 在前⾯的博客⾥,IdentityBasicAuthentication已经从http请求头⾥将token解密并知道了⽤户的⾓⾊,并将⾓⾊写⼊到了IPrincipal对象,所以RBAuthorizeAttribute只要从IPrincipal⾥取出来就⾏,即如下的代码:IPrincipal principal =pal; 2)获取该请求资源的所有⾓⾊数组 我创建了authorizeService类,⽤于处理这⼀个逻辑,博友们可以下载我的框架,只要改⼀下authorizeService类⾥的GetResourceRoleNames⽅法就⾏。 3)判断是否有权限
⾸先principal不能为空,且ty是已经通过⾝份验证的(即enticated==true),并且⽤户的⾓⾊在资源权限⾓⾊数组⾥。 return principal != null && ty != null && enticated && ( (((IEnumerable)roleNames).Any(new Func(le))) );各辅助代码也附上AuthorizeService代码using System;using c;using ;using ;using es;namespace es{ public class AuthorizeService:BaseService { public AuthorizeService(DB db) : base(db) { } /// /// 获取资源的⾓⾊名数组 /// /// /// public string[] GetResourceRoleNames(string resourceName) { var resource=_rDefault(a => == resourceName); var roleIds = _(a => ceId == ).Select(a => ).ToArray(); var roleNames = _(a => ns()).Select(a => ).ToArray(); return roleNames; }
}}
发布评论