新文章 网摘 文章 随笔 日记

Abp VNext微服务-从身份认证及授权开始(一)(干货,强烈推荐)

Abp-VNext是基于aspnetboilerplate的先行版本,在我看来,具有下面三个特点:

1,一个全面的技术框架:基本上囊括了.Net 技术栈上各种流行的技术应用,并且在集成度上也做得很好。

2,基于领域驱动的分层设计模型:提供了DDD分层设计的最佳实践,明确了各层的工作职责

3,模块化的开发模式

参考:aspnetboilerplateABP-VNext

Abp-VNext的特点决定了他在.Net 微服上能大展拳脚,下面从微服务的身份认证及授权开始,看看Abp-Vnext能帮我们做些什么。

 

一,基于Abp-Vnext的微服务架构目录

参考Abp-Vnext的微服务Demo,先把工作目录建立起来

 

 

 先建立一个服务,用于用户身份认证及授权管理

1,建立解决方案:dotnet new sln --name Kingsun.Liujb

2,建立用于用户身份认证及授权管理的模块:

  切换目录到modules,执行Abp命令:abp new Kingsun.Liujb.IDServer --ui-none -t module -csf。创建一个没有ui的模块。

3,创建模块后认识一下Abp-vnext的DDD分层架构

 

 

 4,按需将模块添加到根解决方案

 

二,IdentityServer宿主配置

切换到microsoftservices目录,

将Modules目录中的宿主示例中的IdentityServer直接拷过来。切换到shared目录,新建一个类库:Kingusn.Liujb.Shared

 

注意,这里Kingusn.Liujb.Shared使用netstandard2.0

 

 

将Kingsun.Liujb.Shared添加到Kingsun.Liujb.IDServer.IdentityServer项目引用,替换原来的shared项目。

 MultiTenancyConsts.cs

1
2
3
4
public class MultiTenancyConsts
  {
      public const bool IsEnabled = true;
  }

 更改数据库链接地址为实际地址:Kingsun.Liujb.IDServer.IdentityServer项目的appsettings.json。

 由于目前没有使用reids缓存,先行在IDServerIdentityServerModule中将redis相关模块注释掉。

 

此处要注释的地方包括:
1、IdentityServerModule的依赖注入项DependsOn中的typeof(AbpCachingStackExchangeRedisModule)
2、下面这一段

if (!hostingEnvironment.IsDevelopment())
{
  var redis = ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]);
    context.Services
    .AddDataProtection()
    .PersistKeysToStackExchangeRedis(redis, "IdServer-Protection-Keys");
}

 

使用”update-database“命令更新数据到数据库,运行IdentityServer项目后使用默认的用户名:admin。密码:1q2w3E* 登录

 

 

 

三,添加用户身份管理、租户管理模块

前面我们见识到了使用ABP-Vnext创建项目的实用性,下面将用使用ABP-VNext的模块化特性快速添加部份管理模块

先添加身份认证相关的管理模块,安装Nuget包:Volo.Abp.Identity.Web 后在IDServerIdentityServerModule.cs中添加依赖:typeof(Volo.Abp.Identity.Web.AbpIdentityWebModule)。

运行程序:

 

 

 

 同样添加租户管理:Volo.Abp.TenantManagement.Web.AbpTenantManagementWebModule

 

 

四,添加日志查看模块

查看Abp-vnex的日志管理模块,可以看出社区版本只提供了领域层及基础设施层,没有应用服务层和表示层,也就意味着没有包含日志管理相关接口及页面:

 以上依赖要在Kingsun.Liujb.IDServer.Application中使用nuget中添加

然后在IdentityServerModule的依赖注入项DependsOn中加入:

typeof(Volo.Abp.Identity.Web.AbpIdentityWebModule),
typeof(Volo.Abp.TenantManagement.Web.AbpTenantManagementWebModule),
typeof(Kingsun.Liujb.Web.IDServerWebModule)

 

1,新增查询日志服务

1),先建立服务约束,包括接口,数据传输对象。我这里建立了一个名为IAuditServices的接口,约束服务的使用。AuditDto以及GetAuditlogInput这两个类用于服务数据的传输。

 

 声明如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
   public interface IAuditServices : IApplicationService
    {
        System.Threading.Tasks.Task<PagedResultDto<AuditDto>> GetAuditsByUsernameAsync(GetAuditlogInput input);
        System.Threading.Tasks.Task<PagedResultDto<AuditDto>> GetListAsync();
    }
 
public class AuditDto: EntityDto<Guid>
    {
        public string ApplicationName { getset; }
        public string UserId { getset; }
        public string UserName { getset; }
        public string TenantName { getset; }
        public DateTime ExecutionTime { getset; }
        public int ExecutionDuration { getset; }
        public string ClientIpAddress { getset; }
        public string ClientName { getset; }
        public string BrowserInfo { getset; }
        public string HttpMethod { getset; }
        public string Url { getset; }
        public string Exceptions { getset; }
        public int HttpStatusCode { getset; }
    }
 
 public class GetAuditlogInput: PagedAndSortedResultRequestDto
    {
        public string Filter { getset; }
    }

2),实现服务

在Kingsun.Liujb.IDServer.Application包中实现具体的服务

 

 


    [Authorize(IDServerPermissions.Audits.AuditMannage)]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class AuditServices : IDServerAppService, IAuditServices
    {
        private readonly IAuditLogRepository _auditLogRepository;
        public AuditServices(IAuditLogRepository auditLogRepository)
        {
            this._auditLogRepository = auditLogRepository;
        }
        public async System.Threading.Tasks.Task<PagedResultDto<AuditDto>> GetAuditsByUsernameAsync(GetAuditlogInput input)
        {
            long count = await _auditLogRepository.GetCountAsync(userName: input.Filter);
            var list = await _auditLogRepository.GetListAsync(
                skipCount: input.SkipCount,
                maxResultCount: input.MaxResultCount,
                userName: input.Filter,
                sorting: input.Sorting
                );
            return new PagedResultDto<AuditDto>()
            {
                TotalCount = count,
                Items = ObjectMapper.Map<List<AuditLog>, List<AuditDto>>(list)
            };
        }
 
        public async Task<PagedResultDto<AuditDto>> GetListAsync()
        {
            long count = await _auditLogRepository.GetCountAsync();
            var list = await _auditLogRepository.GetListAsync();
            return new PagedResultDto<AuditDto>()
            {
                TotalCount = count,
                Items = ObjectMapper.Map<List<AuditLog>, List<AuditDto>>(list)
            };
        }
    }

 暴露API

Kingsun.Liujb.IDServer.HttpApi

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[RemoteService]
   [Route("api/IDServer/Audit")]
   [Authorize(IDServerPermissions.Audits.AuditMannage)]
   public class AuditController : IDServerController, IAuditServices
   {
       private readonly IAuditServices _iDServerAuditService;
       public AuditController(IAuditServices _iDServerAuditService)
       {
           this._iDServerAuditService = _iDServerAuditService;
       }
       [HttpGet]
       [Route("GetAuditsByUsername")]
       public async Task<PagedResultDto<AuditDto>> GetAuditsByUsernameAsync(GetAuditlogInput input)
       {
           return await _iDServerAuditService.GetAuditsByUsernameAsync(input);
       }
 
       [HttpGet]
       [Route("GetList")]
       public async Task<PagedResultDto<AuditDto>> GetListAsync()
       {
           return await _iDServerAuditService.GetListAsync();
       }
   }

2,新增访问权限  

 对服务访问进行授权管理。

在Kingsun.Liujb.IDServer.Application.Contracts包的PermissionDefinitionProvider中新建权限,并设置本地化显示名称。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class IDServerPermissionDefinitionProvider : PermissionDefinitionProvider
{
    public override void Define(IPermissionDefinitionContext context)
    {
        var auditGroup = context.AddGroup(IDServerPermissions.GroupName, L("Permission:AuditManagement"));
        auditGroup.AddPermission(IDServerPermissions.Audits.AuditMannage, L("Permission:AuditManagement"), Volo.Abp.MultiTenancy.MultiTenancySides.Host);
    }
 
    private static LocalizableString L(string name)
    {
        return LocalizableString.Create<IDServerResource>(name);
    }
}
 
public class IDServerPermissions
{
    public const string GroupName = "IDServer";
    public static class Audits
    {
        public const string AuditMannage = GroupName + ".Audits";
    }
    public static string[] GetAll()
    {
        return ReflectionHelper.GetPublicConstantsRecursively(typeof(IDServerPermissions));
    }
}

 权限名称本地化:Kingsun.Liujb.IDServer.Domain.Shared中的Localization目录中修改本地化Json文件

1
2
3
4
5
6
7
"texts": {
  "ManageYourProfile""管理个人资料",
  "SamplePageMessage""IDServer模块的示例页面",
  "Menu:AuditManagement""审核日志",
  "Audits""日志",
  "Permission:AuditManagement""审核日志"
}

打开管理页面,可以看到新增的权限已经可以被管理

 

 3,新增菜单

Kingsun.Liujb.IDServer.Web的Menu目录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class IDServerMenuContributor : IMenuContributor
   {
       public async Task ConfigureMenuAsync(MenuConfigurationContext context)
       {
           if (context.Menu.Name == StandardMenus.Main)
           {
               await ConfigureMainMenu(context);
           }
       }
       private async Task ConfigureMainMenu(MenuConfigurationContext context)
       {
           //Add main menu items.
           var administrationMenu = context.Menu.GetAdministration();
           var l = context.GetLocalizer<IDServerResource>();
           var AuditlogsMenuItem = new ApplicationMenuItem(IDServerMenus.AuditManagementGroup, l["Menu:AuditManagement"], icon: "fa fa-file-text-o");
           administrationMenu.AddItem(AuditlogsMenuItem);
           if (await context.IsGrantedAsync(IDServerPermissions.Audits.AuditMannage))
           {
               AuditlogsMenuItem.AddItem(new ApplicationMenuItem(IDServerMenus.AuditManagementSelect,
                   l["Audits"], url: "~/Audit"));
           }
       }
   }
 
  private const string Prefix = "IDServer";
       public const string AuditManagementGroup = "AuditManagement";
       public const string AuditManagementSelect = AuditManagementGroup + ".AuditLogs";

菜单名称本地化参考权限名称本地化,修改本地化json文件即可。

打开管理页面,看到管理菜单已经添加了日志目录

 

 

4,新增日志查看页面

 

 

 

 Index.cshtml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@page
@using Microsoft.Extensions.Localization
@using Kingsun.Liujb.IDServer.Localization
@model Kingsun.Liujb.IDServer.Web.Pages.IDServer.IndexModel
@inject IStringLocalizer<IDServerResource> L
@section scripts{
    <abp-script src="/Pages/Audit/Index.js" />
}
<abp-card>
    <abp-card-header>
        <abp-row>
            <abp-column size-md="_6">
                <abp-card-title>@L["Audits"]</abp-card-title>
            </abp-column>
        </abp-row>
    </abp-card-header>
    <abp-card-body>
        <abp-table striped-rows="true" id="AuditsTable"></abp-table>
    </abp-card-body>
</abp-card>

Index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
(function ($) {
    var l = abp.localization.getResource('IDServer');
    var dataTable = $('#AuditsTable').DataTable(
        abp.libs.datatables.normalizeConfiguration({
            serverSide: true,
            paging: true,
            searching: true,
            scrollX: true,
            order: [[1, "asc"]],
            ajax: abp.libs.datatables.createAjax(kingsun.liujb.iDServer.audits.audit.getAuditsByUsername),
            columnDefs: [
                {
                    title:l("UserName"),
                    data:"userName"
                },
                {
                    title: l( "ExecutionTime"),
                    data: "executionTime"
                },
                {
                    title: l("Url"),
                    data: "url"
                },
                {
                    title: l("HttpMethod"),
                    data: "httpMethod"
                },
                {
                    title: l("HttpStatusCode"),
                    data: "httpStatusCode"
                }
            ]
        })
    )
})(jQuery);

  此处有一个谬误,javascript调用createAjax方法时是按照AuditController中的路由[Route("api/IDServer/Audit")]应该是“ajax: abp.libs.datatables.createAjax(kingsun.liujb.iDServer.audit.getAuditsByUsername)”而非“ajax: abp.libs.datatables.createAjax(kingsun.liujb.iDServer.audits.audit.getAuditsByUsername)”,否则程序会报错。

        此处另一个错误,需要在IdServerHttpApiModule上面依赖注入IdServerApplicationModule(请先引用它)

       此处有另一个错误,没有配置AuditLog和AuditDto的AutoMap,需在Kingsun.Liujb.IDServer.Application的IDServerApplicationAutoMapperProfile文件中添加以下配置:

 

            CreateMap<AuditLog, AuditDto>();

 

 本地化:参考权限名称本地化,修改本地化json文件即可 

 打开页面

 

 

 这只是一个比较简单的管理功能,下一篇将使用模块化的方式添加一个较为复杂的管理模块:IdentityServer管理模块。

 

 
分类: abp
 

此处有另一个错误,没有配置AuditLog和AuditDto的AutoMap,需在Kingsun.Liujb.IDServer.Application的IDServerApplicationAutoMapperProfile文件中添加以下配置:
            CreateMap<AuditLog, AuditDto>();

posted @ 2021-04-28 09:08  岭南春  阅读(1513)  评论(0)    收藏  举报