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

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

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

目录

  • 开发任务
  • 代码实现

开发任务

  • DotNetNB.Security.Core:定义 core,models,Istore;实现 default memory store
  • DotNetNB.Security.Identity:将权限赋予角色或用户;在用户登录时将 Permissions 写入用户身份 claims
image.png
image.png

代码实现

添加一个 Identity 的扩展,将 role 和 Permission 结合到一起

定义 IRolePermissionManager 接口,提供一个 AddRolePermission 的方法

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

namespace DotNetNB.Security.Identity
{
    public interface IRolePermissionManager<TRole>
    {
        public Task AddRolePermission(TRole role, Permission permission);
    }
}

新增 RolePermissionManager 继承 IRolePermissionManager,将 resource 的 key 存到 role 的 Claim 中

因为这样只在 role 里面记录了 key,不知道来自哪个 permission,所以还需要持久化 permission 和 role 的关系

代码语言:txt
复制
using DotNetNB.Security.Core;
using DotNetNB.Security.Core.Models;
using Microsoft.AspNetCore.Identity;
using System.Security.Claims;

namespace DotNetNB.Security.Identity
{
    public class RolePermissionManager<TRole> : IRolePermissionManager<TRole> where TRole : class
    {
        private readonly RoleManager<TRole> _roleManager;

        public RolePermissionManager(RoleManager<TRole> roleManager)
        {
            _roleManager = roleManager;
        }

        public async Task AddRolePermission(TRole role, Permission permission)
        {
            foreach (var resource in permission.Resources)
            {
                await _roleManager.AddClaimAsync(role, new Claim(ClaimsTypes.Permission, resource.Key));
            }

            //TBD 持久化 permission 和 role 的关系
        }
    }
}

由于无法直接获取到 Permission,只能获取到 Permission 的 key,所以需要在 IPermissionManager 接口中添加一个 GetAsync 方法

代码语言:txt
复制
public Task<Permission> GetAsync(string key);

在 PermissionManager 中实现 GetAsync 方法

代码语言:txt
复制
public async Task<Permission> GetAsync(string key)
{
    return await _permissionStore.GetByKeyAsync(key);
}

这样在 RolePermissionManager 中就可以通过这个方法获取到 Permission

代码语言:txt
复制
using DotNetNB.Security.Core;
using Microsoft.AspNetCore.Identity;
using System.Security.Claims;

namespace DotNetNB.Security.Identity
{
    public class RolePermissionManager<TRole> : IRolePermissionManager<TRole> where TRole : class
    {
        private readonly IPermissionManager _permissionManager;
        private readonly RoleManager<TRole> _roleManager;

        public RolePermissionManager(IPermissionManager permissionManager, RoleManager<TRole> roleManager)
        {
            _permissionManager = permissionManager;
            _roleManager = roleManager;
        }

        public async Task AddRolePermission(TRole role, string permissionKey)
        {
            var permission = await _permissionManager.GetAsync(permissionKey);
            if (permission == null)
            {
                throw new InvalidOperationException($"Permission not found:{permissionKey}");
            }
            foreach (var resource in permission.Resources)
            {
                await _roleManager.AddClaimAsync(role, new Claim(ClaimsTypes.Permission, resource.Key));
            }

            //TBD 持久化 permission 和 role 的关系
        }
    }
}

实际上用户可能也获取不到 TRole,需要通过 roleId 查询

代码语言:txt
复制
public async Task AddRolePermission(string roleId, string permissionKey) 
{
    var role = await _roleManager.FindByIdAsync(roleId);
    if (role == null)
    {
        throw new InvalidOperationException($"Role not found:{roleId}");
    }

    var permission = await _permissionManager.GetAsync(permissionKey);
    if (permission == null)
    {
        throw new InvalidOperationException($"Permission not found:{permissionKey}");
    }
    foreach (var resource in permission.Resources)
    {
        await _roleManager.AddClaimAsync(role, new Claim(ClaimsTypes.Permission, resource.Key));
    }

    //TBD 持久化 permission 和 role 的关系
}

用户也是一样的做法,定义一个 IUserPermissionManager 接口,提供一个 AddUserPermission 方法

代码语言:txt
复制
namespace DotNetNB.Security.Identity
{
    public interface IUserPermissionManager<TUser>
    {
        public Task AddUserPermission(string userId, string permissionKey);
    }
}

新增 UserPermissionManager 继承 IUserPermissionManager,将 Permission 中所有 Resource 的 key 作为 User 的 Claim

代码语言:txt
复制
using System.Security.Claims;
using DotNetNB.Security.Core;
using Microsoft.AspNetCore.Identity;

namespace DotNetNB.Security.Identity
{
    public class UserPermissionManager<TUser> : IUserPermissionManager<TUser> where TUser : class
    {
        private readonly UserManager<TUser> _userManager;
        private readonly IPermissionManager _permissionManager;

        public UserPermissionManager(UserManager<TUser> userManager, IPermissionManager permissionManager)
        {
            _userManager = userManager;
            _permissionManager = permissionManager;
        }

        public async Task AddUserPermission(string userId, string permissionKey)
        {
            var user = await _userManager.FindByIdAsync(userId);
            if (user == null)
            {
                throw new InvalidOperationException($"User not found:{userId}");
            }

            var permission = await _permissionManager.GetAsync(permissionKey);
            if (permission == null)
            {
                throw new InvalidOperationException($"Permission not found:{permissionKey}");
            }

            var claims = permission.Resources.Select(p => new Claim(ClaimsTypes.Permission, p.Key)).ToList();
            await _userManager.AddClaimsAsync(user, claims);
        }
    }
}

提供一个扩展方法将 RolePermissionManager 和 UserPermissionManager 添加到程序中

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

namespace DotNetNB.Security.Identity.Extensions
{
    public static class IdentityBuilderExtensions
    {
        public static IdentityBuilder WithPermissions<TUser, TRole>(this IdentityBuilder identityBuilder)
            where TRole : class where TUser : class
        {
            identityBuilder.Services.AddScoped<IRolePermissionManager<TRole>, RolePermissionManager<TRole>>()
                .AddScoped<IUserPermissionManager<TUser>, UserPermissionManager<TUser>>();
            return identityBuilder;
        }
    }
}

GitHub源码链接:

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

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

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

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

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

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