化妆培训学校网站开发,住房公积金服务,中立建设集团有限公司网站,网站兼容浏览器▲ 点击上方“DotNet NB”关注公众号回复“1”获取开发者路线图学习分享 丨作者 / 郑 子 铭 这是DotNet NB 公众号的第188篇原创文章目录开发任务代码实现开发任务DotNetNB.Security.Core#xff1a;定义 core#xff0c;models#xff0c;Istore#xff1b;实现 defaul… ▲ 点击上方“DotNet NB”关注公众号回复“1”获取开发者路线图学习分享 丨作者 / 郑 子 铭 这是DotNet NB 公众号的第188篇原创文章目录开发任务代码实现开发任务DotNetNB.Security.Core定义 coremodelsIstore实现 default memory storeDotNetNB.Security.ActionAccess扫描 action添加 action authorize filter添加集成方式代码实现对于一个 web 项目Filter 是在构建构建 builder 的时候添加的builder.Services.AddControllers(options
{options.Filters.Add()
})这里不可能让用户手动添加所以需要有一个扩展方法给用户调用using Microsoft.AspNetCore.Mvc;namespace DotNetNB.Security.ActionAccess
{public static class MvcOptionsExtensions{public static MvcOptions AddActionAccessControl(this MvcOptions options){options.Filters.AddDynamicAuthorizeFilter();return options;}}
}创建 Resource包含 Key 和 Data 两个属性namespace DotNetNB.Security.Core.Models
{public class Resource{public string Key { get; set; }public object Data { get; set; }}
}创建 ActionResource继承 Resource包含 ControllerNameActionNameRouteTemplate 和 HttpVerb 几个属性using DotNetNB.Security.Core.Models;namespace DotNetNB.Security.ActionAccess
{public class ActionResource : Resource{}public class ActionResourceData{public string? ControllerName { get; set; }public string? ActionName { get; set; }public string DisplayName { get; set; }public string? RouteTemplate { get; set; }public string? HttpVerb { get; set; }}
}定义一个 IResourceManager 接口提供创建资源的方法using DotNetNB.Security.Core.Models;namespace DotNetNB.Security.Core
{public interface IResourceManager{public Task CreateAsync(Resource resource);public Task CreateAsync(IEnumerableResource resources);}
}参考 ASP .NET Core 源码中的 ActionEndpointDataSourceBasehttps://github.com/dotnet/aspnetcore/blob/main/src/Mvc/Mvc.Core/src/Routing/ActionEndpointDataSourceBase.cs创建 endpoint 的时候有一个 action 的列表 ActionDescriptorsvar endpoints CreateEndpoints(_actions.ActionDescriptors.Items, Conventions);它的类型是一个 IActionDescriptorCollectionProvider专门用于扫描获取所有的 actionprivate readonly IActionDescriptorCollectionProvider _actions;在 ActionAccess 模块的 ActionResourceProvider 中把它加进来using Microsoft.AspNetCore.Mvc.Infrastructure;namespace DotNetNB.Security.ActionAccess
{public class ActionResourceProvider{private readonly IActionDescriptorCollectionProvider _actionDescriptorCollectionProvider;public ActionResourceProvider(IActionDescriptorCollectionProvider actionDescriptorCollectionProvider){_actionDescriptorCollectionProvider actionDescriptorCollectionProvider;}}
}在 host 启动的时候扫描获取所有的 action 信息定义一个 IResourceProvider 接口namespace DotNetNB.Security.Core
{public interface IResourceProvider{public TaskIEnumerableResource ExecuteAsync();}
}ActionResourceProvider 实现这个接口从 ActionDescriptors 获取 action 信息构建 ActionResourceDatapublic async TaskIEnumerableResource ExecuteAsync()
{var actions _actionDescriptorCollectionProvider.ActionDescriptors.Items;var actionResources new ListActionResource();foreach (var action in actions){if (action is ControllerActionDescriptor){var actionDescriptor action as ControllerActionDescriptor;var httpMethod action.EndpointMetadata.Where(m m is HttpMethodMetadata).FirstOrDefault() as HttpMethodMetadata;var routeAttribute actionDescriptor?.EndpointMetadata.FirstOrDefault(m m is RouteAttribute) as RouteAttribute;var resourceData new ActionResourceData();resourceData.HttpVerb httpMethod?.HttpMethods.First();resourceData.ActionName actionDescriptor?.ActionName;resourceData.ControllerName actionDescriptor?.ControllerName;resourceData.RouteTemplate routeAttribute?.Template;resourceData.DisplayName action.DisplayName;actionResources.Add(new ActionResource(){Data resourceData,Key actionDescriptor.GetSecurityKey()});}}return await Task.FromResult(actionResources);
}参考 ASP .NET Core 源码中的 AuthorizeFilterhttps://github.com/dotnet/aspnetcore/blob/main/src/Mvc/Mvc.Core/src/Authorization/AuthorizeFilter.csAuthorizeFilter 中有一个 OnAuthorizationAsync 的方法首先获取 policy 执行器然后执行了认证接着执行授权根据授权结果修改 AuthorizationFilterContext我们权限主要是 Forbidden 的结果返回 403 即可public virtual async Task OnAuthorizationAsync(AuthorizationFilterContext context)
{if (context null){throw new ArgumentNullException(nameof(context));}if (!context.IsEffectivePolicy(this)){return;}// IMPORTANT: Changes to authorization logic should be mirrored in securitys AuthorizationMiddlewarevar effectivePolicy await GetEffectivePolicyAsync(context);if (effectivePolicy null){return;}var policyEvaluator context.HttpContext.RequestServices.GetRequiredServiceIPolicyEvaluator();var authenticateResult await policyEvaluator.AuthenticateAsync(effectivePolicy, context.HttpContext);// Allow Anonymous skips all authorizationif (HasAllowAnonymous(context)){return;}var authorizeResult await policyEvaluator.AuthorizeAsync(effectivePolicy, authenticateResult, context.HttpContext, context);if (authorizeResult.Challenged){context.Result new ChallengeResult(effectivePolicy.AuthenticationSchemes.ToArray());}else if (authorizeResult.Forbidden){context.Result new ForbidResult(effectivePolicy.AuthenticationSchemes.ToArray());}
}DynamicAuthorizeFilter 继承自 AuthorizeFilter只获取 ControllerActionDescriptor 类型的 action如果 permissions 中不包含 actionKey 则返回 403using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;namespace DotNetNB.Security.ActionAccess
{public class DynamicAuthorizeFilter : AuthorizeFilter{public override async Task OnAuthorizationAsync(AuthorizationFilterContext context){var actionDescriptor context.ActionDescriptor as ControllerActionDescriptor;if (actionDescriptor null){return;}base.OnAuthorizationAsync(context);if (context.Result ! null){return;}var permissions context.HttpContext.User.Claims.Where(c c.Type Core.ClaimsTypes.Permission);var actionKey actionDescriptor.GetSecurityKey();var values permissions.Select(p p.Value);if (!values.Contains(actionKey)){context.Result new ForbidResult();}}}
}在 ClaimsTypes 中增加一个 Permission 类型的 ClaimsTypenamespace DotNetNB.Security.Core
{public static class ClaimsTypes{public const string Permission Permission;}
}为了避免重复代码添加一个 GetSecurityKey 的扩展方法using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Internal;namespace DotNetNB.Security.ActionAccess;public static string GetSecurityKey(this ControllerActionDescriptor descriptor)
{var httpMethod descriptor.EndpointMetadata.FirstOrDefault(m m is HttpMethodMetadata) as HttpMethodMetadata;return string.Format(${descriptor?.ControllerName}-{descriptor?.ActionName}-{httpMethod.HttpMethods.First()});
}这样就完成了 DotNetNB.Security.ActionAccess 模块的 ActionResourceProvider 和 DynamicAuthorizeFilterGitHub源码链接https://github.com/MingsonZheng/dotnetnb.security课程链接.NET云原生架构师训练营讲什么怎么讲讲多久推荐阅读《Kubernetes全栈架构师Kubeadm高可用安装k8s集群--学习笔记》《.NET 云原生架构师训练营模块一 架构师与云原生--学习笔记》《.NET Core开发实战第1课课程介绍--学习笔记》点击下方卡片关注DotNet NB一起交流学习