.NET 雲原生架構師訓練營(許可權系統 程式碼實現 Store.EntityFramework)--學習筆記

MingsonZheng發表於2022-02-17

目錄

  • 開發任務
  • 程式碼實現

開發任務

  • DotNetNB.Security.Core:定義 core,models,Istore;實現 default memory store
  • DotNetNB.Security.Store.EntityFramework:基於 mysql 建立 PermissionStore 和 ResourceStore

程式碼實現

我們需要在 ResourceProviderHostedService 中讀取所有的 Resource,將 Resource 轉換為 Permission,再將 Permission 分配給 Role

建立 Permission 的 model

namespace DotNetNB.Security.Core.Models
{
    public class Permission
    {
        public string Key { get; set; }

        public string DisplayName { get; set; }

        public string Description { get; set; }

        public IEnumerable<Resource> Resources { get; set; }
    }
}

在 IPermissionManager 介面中定義 CreateAsync 方法

namespace DotNetNB.Security.Core
{
    public interface IPermissionManager
    {
        public Task CreateAsync(string key, string displayName, string description, IEnumerable<string> resources);
    }
}

IResourceManager 介面新增通過 key 獲取 resource 的方法 GetByKeysAsync

public Task<IEnumerable<Resource>> GetByKeysAsync(IEnumerable<string> resources);

PermissionManager 裡面需要用到 Store,先定義介面 IPermissionStore

using DotNetNB.Security.Core.Models;

namespace DotNetNB.Security.Core.Store
{
    public interface IPermissionStore
    {
        public Task CreateAsync(Permission permission);
    }
}

在 PermissionManager 裡面建立一個 permission,通過 ResourceManager 獲取到所有 resources 賦值給 permission,再將 permission 儲存到 PermissionStore

using DotNetNB.Security.Core.Models;
using DotNetNB.Security.Core.Store;

namespace DotNetNB.Security.Core;

public class PermissionManager: IPermissionManager
{
    private readonly IResourceManager _resourceManager;
    private readonly IPermissionStore _permissionStore;

    public PermissionManager(IResourceManager resourceManager, IPermissionStore permissionStore)
    {
        _resourceManager = resourceManager;
        _permissionStore = permissionStore;
    }

    public async Task CreateAsync(string key, string displayName, string description, IEnumerable<string> resourceKeys)
    {
        if (string.IsNullOrEmpty(key))
            throw new ArgumentNullException(nameof(key));

        var permission = new Permission { Key = key, DisplayName = displayName, Description = description };
        var resources = await _resourceManager.GetByKeysAsync(resourceKeys);
        permission.Resources = resources;

        await _permissionStore.CreateAsync(permission);
    }
}

建立 DefaultPermissionStore 實現 IPermissionStore

using DotNetNB.Security.Core.Models;

namespace DotNetNB.Security.Core.Store
{
    public class DefaultPermissionStore : IPermissionStore
    {
        private List<Permission> _list;

        public DefaultPermissionStore()
        {
            _list = new List<Permission>();
        }

        public async Task CreateAsync(Permission permission)
        {
            _list.Add(permission);
        }
    }
}

IPermissionStore 介面新增獲取 permission 列表的方法

public Task<IEnumerable<Permission>> GetAllAsync();

在 DefaultPermissionStore 中直接將列表返回即可

public async Task<IEnumerable<Permission>> GetAllAsync()
{
    return _list;
}

在 PermissionManager 中通過 PermissionStore 獲取 Permission 列表返回

public async Task<IEnumerable<Permission>> GetAllAsync()
{
    return await _permissionStore.GetAllAsync();
}

在 IPermissionStore 中新增 GetByKeyAsync 方法,在 PermissionManager 中用於校驗 key 是否存在對應的 Permission

public Task<Permission> GetByKeyAsync(string key);

在 DefaultPermissionStore 中實現 GetByKeyAsync 方法

public async Task<Permission> GetByKeyAsync(string key)
{
    return _list.SingleOrDefault(r => r.Key == key);
}

在 PermissionManager 中校驗 key 是否存在對應的 Permission

var origin = await _permissionStore.GetByKeyAsync(key);
if (origin != null)
    throw new InvalidOperationException("Duplicated permission key found");

IResourceManager 介面新增獲取所有 resource 方法 GetAllAsync

public Task<IEnumerable<Resource>> GetAllAsync();

ResourceManager 裡面需要用到 Store,先定義介面 IResourceStore

using DotNetNB.Security.Core.Models;

namespace DotNetNB.Security.Core.Store
{
    public interface IResourceStore
    {
        public Task CreateAsync(Resource resource);

        public Task CreateAsync(IEnumerable<Resource> resources);

        public Task<IEnumerable<Resource>> GetAllAsync();
        
        public Task<Resource> GetByKeyAsync(string key);

        public Task<IEnumerable<Resource>> GetByKeysAsync(IEnumerable<string> resources);
    }
}

建立 DefaultResourceStore 實現 IResourceStore

using DotNetNB.Security.Core.Models;

namespace DotNetNB.Security.Core.Store
{
    public class DefaultResourceStore : IResourceStore
    {
        private readonly List<Resource> _list;

        public DefaultResourceStore()
        {
            _list = new List<Resource>();
        }

        public async Task CreateAsync(Resource resource)
        {
            _list.Add(resource);
        }

        public async Task CreateAsync(IEnumerable<Resource> resources)
        {
            _list.AddRange(resources);
        }

        public async Task<IEnumerable<Resource>> GetAllAsync()
        {
            return _list;
        }

        public async Task<Resource> GetByKeyAsync(string key)
        {
            return _list.SingleOrDefault(r => r.Key == key);
        }

        public async Task<IEnumerable<Resource>> GetByKeysAsync(IEnumerable<string> resources)
        {
            return _list.Where(r => resources.Contains(r.Key));
        }
    }
}

在 ResourceManager 中通過 ResourceStore 建立儲存獲取 Resource,建立的時候判斷是否已經存在 Resource

using DotNetNB.Security.Core.Models;
using DotNetNB.Security.Core.Store;

namespace DotNetNB.Security.Core
{
    public class ResourceManager :  IResourceManager
    {
        private readonly IResourceStore _resourceStore;
        public ResourceManager(IResourceStore resourceStore)
        {
            _resourceStore = resourceStore;
        }

        public async Task CreateAsync(Resource resource)
        {
            var origin = await _resourceStore.GetByKeyAsync(resource.Key);
            if (origin != null)
                throw new InvalidOperationException("Duplicated resource key found");

            await _resourceStore.CreateAsync(resource);
        }

        public async Task CreateAsync(IEnumerable<Resource> resources)
        {
            var origins = await _resourceStore.GetByKeysAsync(resources.Select(r => r.Key));
            if (origins.Any())
                throw new InvalidOperationException($"Duplicated resource key found:{string.Concat(origins.Select(o => o.Key), ",")}");

            await _resourceStore.CreateAsync(resources);
        }

        public async Task<IEnumerable<Resource>> GetAllAsync()
        {
            return await _resourceStore.GetAllAsync();
        }

        public async Task<IEnumerable<Resource>> GetByKeysAsync(IEnumerable<string> resources)
        {
            return await _resourceStore.GetByKeysAsync(resources);
        }
    }
}

GitHub原始碼連結:

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

課程連結

https://appsqsyiqlk5791.h5.xiaoeknow.com/v1/course/video/v_5f39bdb8e4b01187873136cf?type=2

知識共享許可協議

本作品採用知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議進行許可。

歡迎轉載、使用、重新發布,但務必保留文章署名 鄭子銘 (包含連結: http://www.cnblogs.com/MingsonZheng/ ),不得用於商業目的,基於本文修改後的作品務必以相同的許可釋出。

如有任何疑問,請與我聯絡 (MingsonZheng@outlook.com) 。

相關文章