前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >.NET 云原生架构师训练营(权限系统 代码实现 EntityAccess)--学习笔记

.NET 云原生架构师训练营(权限系统 代码实现 EntityAccess)--学习笔记

原创
作者头像
郑子铭
修改2022-02-24 10:08:39
2130
修改2022-02-24 10:08:39
举报

目录

  • 开发任务
  • 代码实现

开发任务

  • DotNetNB.Security.Core:定义 core,models,Istore;实现 default memory store
  • DotNetNB.Security.EntityAccess:扫描 entities;添加 ef savechanges interceptor
image.png
image.png

代码实现

我们现在已经通过 ActionResourceProvider 完成了 action 的扫描,生成了 ResourceModel,需要持久化到 IResourceStore,持久化之后才可以将它们绑定到用户,角色

由于 ActionAccess 是一个类库,提供了一些比较零散的功能,所以需要添加一个扩展方法把功能组装起来,在 host 启动的时候执行 action 的扫描

代码语言:txt
复制
using Microsoft.Extensions.DependencyInjection;

namespace DotNetNB.Security.Core.Extensions
{
    public static class ServiceCollectionExtensions
    {
        public static IServiceCollection AddSecurity(this IServiceCollection services)
        {
            services.AddHostedService<ResourceProviderHostedService>();
            return services;
        }
    }
}

ResourceProviderHostedService 继承自 IHostedService,有一个 StartAsync 和一个 StopAsync 方法

代码语言:txt
复制
using Microsoft.Extensions.Hosting;

namespace DotNetNB.Security.Core
{
    public class ResourceProviderHostedService : IHostedService
    {
        public async Task StartAsync(CancellationToken cancellationToken)
        {

        }

        public async Task StopAsync(CancellationToken cancellationToken)
        {

        }
    }
}

新建一个示例的 api 项目 DotNetNB.WebApplication,在这个 api 项目里面使用我们的 dll 要足够简单,就像使用 asp .net core 的 api 一样

添加 DotNetNB.Security.Core 的项目引用之后,可以直接在 Program.cs 中调用扩展方法

代码语言:txt
复制
using DotNetNB.Security.Core.Extensions;

...

builder.Services.AddSecurity();

在启动扫描的时候,Security.Core 并不知道外部的 host 里面有哪些 action provider,所以需要注册进来,需要构建一个 builder

同时需要一个配置 options 告诉我们它是来自哪个包,是 ActionAccess,还是 EntityAccess

参照 MvcOptions

代码语言:txt
复制
builder.Services.AddControllers(options => {});

它是一个 Action 的委托

代码语言:txt
复制
public static IMvcBuilder AddControllers(
  this IServiceCollection services,
  Action<MvcOptions>? configure)
{
  IMvcCoreBuilder builder = services != null ? MvcServiceCollectionExtensions.AddControllersCore(services) : throw new ArgumentNullException(nameof (services));
  if (configure != null)
    builder.AddMvcOptions(configure);
  return (IMvcBuilder) new MvcBuilder(builder.Services, builder.PartManager);
}

于是乎我们在 AddSecurity 添加一个入参

代码语言:txt
复制
public static IServiceCollection AddSecurity(this IServiceCollection services, Action<SecurityOption>? configure)

SecurityOption

代码语言:txt
复制
using Microsoft.Extensions.DependencyInjection;

namespace DotNetNB.Security.Core.Extensions
{
    public class SecurityOption
    {
        public IServiceCollection Services { get; set; }
    }
}

在调用 AddSecurity 扩展方法的时候通过 SecurityOption 进行配置,这样所有对外的 api 只需要做这一个配置就可以把两个包的所有功能引用进去

代码语言:txt
复制
builder.Services.AddSecurity(options =>
{
    options.AddActionAccess();
    options.AddEntityAccess<DBContext>();
});

参考 MvcCoreServiceCollectionExtensions 的 AddMvcCoreServices 方法

代码语言:txt
复制
internal static void AddMvcCoreServices(IServiceCollection services)
{
    //
    // Options
    //
    services.TryAddEnumerable(
        ServiceDescriptor.Transient<IConfigureOptions<MvcOptions>, MvcCoreMvcOptionsSetup>());
    
    ...
}

在 ActionAccess 中添加一个扩展方法 AddActionAccessControl,将 IResourceProvider 添加进去,这样就可以在 ResourceProviderHostedService 中读取到

代码语言:txt
复制
using DotNetNB.Security.Core;
using DotNetNB.Security.Core.Extensions;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;

namespace DotNetNB.Security.ActionAccess
{
    public static class SecurityOptionExtensions
    {
        public static SecurityOption AddActionAccessControl(this SecurityOption option)
        {
            option.Services.TryAddEnumerable(ServiceDescriptor.Transient<IResourceProvider, ActionResourceProvider>());
            return option;
        }
    }
}

在 ResourceProviderHostedService 的构造函数中读取 IServiceProvider

代码语言:txt
复制
using Microsoft.Extensions.Hosting;

namespace DotNetNB.Security.Core
{
    public class ResourceProviderHostedService : IHostedService
    {
        private readonly IServiceProvider[] _serviceProviders;

        public ResourceProviderHostedService(IServiceProvider[] serviceProviders)
        {
            _serviceProviders = serviceProviders;
        }

        public async Task StartAsync(CancellationToken cancellationToken)
        {

        }

        public async Task StopAsync(CancellationToken cancellationToken)
        {

        }
    }
}

在 EntityAccess 中同样添加一个扩展方法 AddEntityAccessControl

代码语言:txt
复制
using DotNetNB.Security.Core;
using DotNetNB.Security.Core.Extensions;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;

namespace DotNetNB.Security.EntityAccess
{
    public static class SecurityOptionExtensions
    {
        public static SecurityOption AddEntityAccessControl(this SecurityOption option)
        {
            option.Services.TryAddEnumerable(ServiceDescriptor.Transient<IResourceProvider, EntityResourceProvider>());
            return option;
        }
    }
}

EntityResourceProvider 继承 IResourceProvider

代码语言:txt
复制
using DotNetNB.Security.Core;
using DotNetNB.Security.Core.Models;

namespace DotNetNB.Security.EntityAccess
{
    public class EntityResourceProvider : IResourceProvider
    {
        public async Task<IEnumerable<Resource>> ExecuteAsync()
        {
            return new List<Resource>();
        }
    }
}

完成之后在 DotNetNB.WebApplication 中添加项目引用,就可以进行配置

代码语言:txt
复制
builder.Services.AddSecurity(options =>
{
    options.AddActionAccessControl()
        .AddEntityAccessControl();
});

后面再完善 AddEntityAccessControl 加入 DBContext

GitHub源码链接:

https://github.com/MingsonZheng/dotnetnb.security

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 目录
    • 开发任务
      • 代码实现
        • GitHub源码链接:
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
        http://www.vxiaotou.com