Abp-VNext是基於aspnetboilerplate的先行版本,在我看來,具有下面三個特點:
1,一個全面的技術框架:基本上囊括了.Net 技術棧上各種流行的技術應用,並且在集成度上也做得很好。
2,基於領域驅動的分層設計模型:提供了DDD分層設計的最佳實踐,明確了各層的工作職責
3,模塊化的開發模式
參考:aspnetboilerplate,ABP-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 {
get
;
set
; }
public
string
UserId {
get
;
set
; }
public
string
UserName {
get
;
set
; }
public
string
TenantName {
get
;
set
; }
public
DateTime ExecutionTime {
get
;
set
; }
public
int
ExecutionDuration {
get
;
set
; }
public
string
ClientIpAddress {
get
;
set
; }
public
string
ClientName {
get
;
set
; }
public
string
BrowserInfo {
get
;
set
; }
public
string
HttpMethod {
get
;
set
; }
public
string
Url {
get
;
set
; }
public
string
Exceptions {
get
;
set
; }
public
int
HttpStatusCode {
get
;
set
; }
}
public
class
GetAuditlogInput: PagedAndSortedResultRequestDto
{
public
string
Filter {
get
;
set
; }
}
|
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管理模塊。
此處有另一個錯誤,沒有配置AuditLog和AuditDto的AutoMap,需在Kingsun.Liujb.IDServer.Application的IDServerApplicationAutoMapperProfile文件中添加以下配置:
CreateMap<AuditLog, AuditDto>();