Browse Source

optional tracking entity changed

pull/96/head
cKey 5 years ago
parent
commit
c71a2a5a89
  1. 2
      aspnet-core/services/account/AuthServer.Host/AuthIdentityServerModule.cs
  2. 14
      aspnet-core/services/admin/LINGYUN.Abp.BackendAdmin.HttpApi.Host/BackendAdminHostModule.cs
  3. 14
      aspnet-core/services/apigateway/LINGYUN.ApiGateway.HttpApi.Host/ApiGatewayHttpApiHostModule.cs
  4. 13
      aspnet-core/services/identity-server/LINGYUN.Abp.IdentityServer4.HttpApi.Host/AbpIdentityServerAdminHttpApiHostModule.cs
  5. 14
      aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/AppPlatformHttpApiHostModule.cs
  6. 10
      vueJs/src/api/auditing.ts
  7. 137
      vueJs/src/views/admin/auditing/audit-log/components/AuditLogProfile.vue
  8. 31
      vueJs/src/views/admin/auditing/audit-log/index.vue

2
aspnet-core/services/account/AuthServer.Host/AuthIdentityServerModule.cs

@ -140,7 +140,7 @@ namespace AuthServer.Host
Configure<AbpAuditingOptions>(options => Configure<AbpAuditingOptions>(options =>
{ {
// options.IsEnabledForGetRequests = true; // options.IsEnabledForGetRequests = true;
options.ApplicationName = "AuthServer"; options.ApplicationName = "Identity-Server-STS";
}); });
Configure<AppUrlOptions>(options => Configure<AppUrlOptions>(options =>

14
aspnet-core/services/admin/LINGYUN.Abp.BackendAdmin.HttpApi.Host/BackendAdminHostModule.cs

@ -28,6 +28,7 @@ using Volo.Abp;
using Volo.Abp.AspNetCore.Authentication.JwtBearer; using Volo.Abp.AspNetCore.Authentication.JwtBearer;
using Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy; using Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy;
using Volo.Abp.AspNetCore.Security.Claims; using Volo.Abp.AspNetCore.Security.Claims;
using Volo.Abp.Auditing;
using Volo.Abp.AuditLogging.EntityFrameworkCore; using Volo.Abp.AuditLogging.EntityFrameworkCore;
using Volo.Abp.Authorization.Permissions; using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Autofac; using Volo.Abp.Autofac;
@ -209,6 +210,19 @@ namespace LINGYUN.Abp.BackendAdmin
options.TenantResolvers.Insert(0, new AuthorizationTenantResolveContributor()); options.TenantResolvers.Insert(0, new AuthorizationTenantResolveContributor());
}); });
Configure<AbpAuditingOptions>(options =>
{
options.ApplicationName = "Backend-Admin";
// 是否启用实体变更记录
var entitiesChangedConfig = configuration.GetSection("App:TrackingEntitiesChanged");
if (entitiesChangedConfig.Exists() && entitiesChangedConfig.Get<bool>())
{
options
.EntityHistorySelectors
.AddAllEntities();
}
});
// Swagger // Swagger
context.Services.AddSwaggerGen( context.Services.AddSwaggerGen(
options => options =>

14
aspnet-core/services/apigateway/LINGYUN.ApiGateway.HttpApi.Host/ApiGatewayHttpApiHostModule.cs

@ -16,6 +16,7 @@ using System;
using System.Text; using System.Text;
using Volo.Abp; using Volo.Abp;
using Volo.Abp.AspNetCore.Security.Claims; using Volo.Abp.AspNetCore.Security.Claims;
using Volo.Abp.Auditing;
using Volo.Abp.AuditLogging.EntityFrameworkCore; using Volo.Abp.AuditLogging.EntityFrameworkCore;
using Volo.Abp.Autofac; using Volo.Abp.Autofac;
using Volo.Abp.AutoMapper; using Volo.Abp.AutoMapper;
@ -122,6 +123,19 @@ namespace LINGYUN.ApiGateway
options.IsEnabled = false; options.IsEnabled = false;
}); });
Configure<AbpAuditingOptions>(options =>
{
options.ApplicationName = "ApiGateWay-Admin";
// 是否启用实体变更记录
var entitiesChangedConfig = configuration.GetSection("App:TrackingEntitiesChanged");
if (entitiesChangedConfig.Exists() && entitiesChangedConfig.Get<bool>())
{
options
.EntityHistorySelectors
.AddAllEntities();
}
});
//Configure<AbpTenantResolveOptions>(options => //Configure<AbpTenantResolveOptions>(options =>
//{ //{
// options.TenantResolvers.Insert(0, new AuthorizationTenantResolveContributor()); // options.TenantResolvers.Insert(0, new AuthorizationTenantResolveContributor());

13
aspnet-core/services/identity-server/LINGYUN.Abp.IdentityServer4.HttpApi.Host/AbpIdentityServerAdminHttpApiHostModule.cs

@ -24,6 +24,7 @@ using Volo.Abp.Account;
using Volo.Abp.AspNetCore.Authentication.JwtBearer; using Volo.Abp.AspNetCore.Authentication.JwtBearer;
using Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy; using Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy;
using Volo.Abp.AspNetCore.Security.Claims; using Volo.Abp.AspNetCore.Security.Claims;
using Volo.Abp.Auditing;
using Volo.Abp.AuditLogging.EntityFrameworkCore; using Volo.Abp.AuditLogging.EntityFrameworkCore;
using Volo.Abp.Authorization.Permissions; using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Autofac; using Volo.Abp.Autofac;
@ -150,6 +151,18 @@ namespace LINGYUN.Abp.IdentityServer4
options.DefaultReceiveEmail = "colin.in@foxmail.com"; options.DefaultReceiveEmail = "colin.in@foxmail.com";
}); });
Configure<AbpAuditingOptions>(options =>
{
options.ApplicationName = "Identity-Server-Admin";
// 是否启用实体变更记录
var entitiesChangedConfig = configuration.GetSection("App:TrackingEntitiesChanged");
if (entitiesChangedConfig.Exists() && entitiesChangedConfig.Get<bool>())
{
options
.EntityHistorySelectors
.AddAllEntities();
}
});
Configure<AbpDistributedCacheOptions>(options => Configure<AbpDistributedCacheOptions>(options =>
{ {

14
aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/AppPlatformHttpApiHostModule.cs

@ -26,6 +26,7 @@ using Volo.Abp;
using Volo.Abp.AspNetCore.Authentication.JwtBearer; using Volo.Abp.AspNetCore.Authentication.JwtBearer;
using Volo.Abp.AspNetCore.MultiTenancy; using Volo.Abp.AspNetCore.MultiTenancy;
using Volo.Abp.AspNetCore.Security.Claims; using Volo.Abp.AspNetCore.Security.Claims;
using Volo.Abp.Auditing;
using Volo.Abp.AuditLogging.EntityFrameworkCore; using Volo.Abp.AuditLogging.EntityFrameworkCore;
using Volo.Abp.Autofac; using Volo.Abp.Autofac;
using Volo.Abp.BlobStoring; using Volo.Abp.BlobStoring;
@ -184,6 +185,19 @@ namespace LINGYUN.Platform
options.IsEnabled = true; options.IsEnabled = true;
}); });
Configure<AbpAuditingOptions>(options =>
{
options.ApplicationName = "Platform";
// 是否启用实体变更记录
var entitiesChangedConfig = configuration.GetSection("App:TrackingEntitiesChanged");
if (entitiesChangedConfig.Exists() && entitiesChangedConfig.Get<bool>())
{
options
.EntityHistorySelectors
.AddAllEntities();
}
});
Configure<AbpTenantResolveOptions>(options => Configure<AbpTenantResolveOptions>(options =>
{ {
options.TenantResolvers.Insert(0, new AuthorizationTenantResolveContributor()); options.TenantResolvers.Insert(0, new AuthorizationTenantResolveContributor());

10
vueJs/src/api/auditing.ts

@ -82,6 +82,12 @@ export class SecurityLog {
extraProperties?: {[key: string]: any} extraProperties?: {[key: string]: any}
} }
export enum ChangeType {
Created = 0,
Updated = 1,
Deleted = 2
}
export class PropertyChange { export class PropertyChange {
id!: string id!: string
newValue?: string newValue?: string
@ -93,7 +99,7 @@ export class PropertyChange {
export class EntityChange { export class EntityChange {
id!: string id!: string
changeTime?: Date changeTime?: Date
changeType?: number changeType?: ChangeType
entityTenantId?: string entityTenantId?: string
entityId?: string entityId?: string
entityTypeFullName?: string entityTypeFullName?: string
@ -106,7 +112,7 @@ export class Action {
serviceName?: string serviceName?: string
methodName?: string methodName?: string
parameters?: string parameters?: string
executionTime?: Date executionTime!: Date
executionDuration?: number executionDuration?: number
extraProperties?: {[key: string]: any} extraProperties?: {[key: string]: any}
} }

137
vueJs/src/views/admin/auditing/audit-log/components/AuditLogProfile.vue

@ -136,7 +136,7 @@
v-for="(action, index) in getActions" v-for="(action, index) in getActions"
:key="index" :key="index"
:timestamp="getFormatDateTime(action.executionTime)" :timestamp="getFormatDateTime(action.executionTime)"
:type="auditLog.httpStatusCode | httpStatusCodeFilter" :type="auditLog.httpStatusCode | httpStatusCodeTimelineFilter"
placement="top" placement="top"
> >
<el-card> <el-card>
@ -167,6 +167,100 @@
</el-timeline-item> </el-timeline-item>
</el-timeline> </el-timeline>
</el-tab-pane> </el-tab-pane>
<el-tab-pane
v-if="getEntitiesChanges.length > 0"
label="实体变更"
name="entitiesChanged"
style="height:300px;overflow-y:auto;overflow-x:hidden;"
>
<el-timeline>
<el-timeline-item
v-for="(entity, index) in getEntitiesChanges"
:key="index"
:timestamp="getFormatDateTime(entity.changeTime)"
:type="entity.changeType | entityChangeTypeTimelineFilter"
placement="top"
>
<el-card>
<el-form-item label="变更类型">
<el-input
:value="entity.changeType | entityChangeTypeNameFilter"
readonly
/>
</el-form-item>
<el-form-item label="实体类型">
<el-input
v-model="entity.entityTypeFullName"
readonly
/>
</el-form-item>
<el-form-item label="实体标识">
<el-input
v-model="entity.entityId"
readonly
/>
</el-form-item>
<el-form-item label="租户标识">
<el-input
v-model="entity.entityTenantId"
readonly
/>
</el-form-item>
<el-form-item label="属性变更">
<el-table
row-key="id"
:data="entity.propertyChanges"
border
fit
highlight-current-row
style="width: 100%;"
>
<el-table-column
label="属性名称"
prop="propertyName"
sortable
width="200px"
>
<template slot-scope="{row}">
<span>{{ row.propertyName }}</span>
</template>
</el-table-column>
<el-table-column
label="当前值"
prop="newValue"
sortable
width="320px"
>
<template slot-scope="{row}">
<span>{{ row.newValue }}</span>
</template>
</el-table-column>
<el-table-column
label="原始值"
prop="originalValue"
sortable
width="320px"
>
<template slot-scope="{row}">
<span>{{ row.originalValue }}</span>
</template>
</el-table-column>
<el-table-column
label="属性类型"
prop="propertyTypeFullName"
sortable
width="500px"
>
<template slot-scope="{row}">
<span>{{ row.propertyTypeFullName }}</span>
</template>
</el-table-column>
</el-table>
</el-form-item>
</el-card>
</el-timeline-item>
</el-timeline>
</el-tab-pane>
<el-tab-pane <el-tab-pane
v-if="hasException" v-if="hasException"
label="异常信息" label="异常信息"
@ -204,17 +298,28 @@
<script lang="ts"> <script lang="ts">
import { Component, Vue, Prop, Watch } from 'vue-property-decorator' import { Component, Vue, Prop, Watch } from 'vue-property-decorator'
import AuditingService, { Action, AuditLog } from '@/api/auditing' import AuditingService, { Action, AuditLog, EntityChange, ChangeType } from '@/api/auditing'
import { dateFormat } from '@/utils' import { dateFormat } from '@/utils'
import JsonEditor from '@/components/JsonEditor/index.vue' import JsonEditor from '@/components/JsonEditor/index.vue'
const entityChangeTypeNameMap: { [key: number]: string } = {
[ChangeType.Created]: '新增',
[ChangeType.Updated]: '修改',
[ChangeType.Deleted]: '删除'
}
const entityChangeTypeTimelineMap: { [key: number]: string } = {
[ChangeType.Created]: 'success',
[ChangeType.Updated]: 'warning',
[ChangeType.Deleted]: 'danger'
}
@Component({ @Component({
name: 'AuditLogProfile', name: 'AuditLogProfile',
components: { components: {
JsonEditor JsonEditor
}, },
filters: { filters: {
httpStatusCodeFilter(httpStatusCode: number) { httpStatusCodeTimelineFilter(httpStatusCode: number) {
if (httpStatusCode >= 200 && httpStatusCode < 300) { if (httpStatusCode >= 200 && httpStatusCode < 300) {
return 'success' return 'success'
} }
@ -225,6 +330,12 @@ import JsonEditor from '@/components/JsonEditor/index.vue'
return 'danger' return 'danger'
} }
return 'primary' return 'primary'
},
entityChangeTypeNameFilter(type: ChangeType) {
return entityChangeTypeNameMap[type]
},
entityChangeTypeTimelineFilter(type: ChangeType) {
return entityChangeTypeTimelineMap[type]
} }
}, },
computed: { computed: {
@ -276,10 +387,28 @@ export default class extends Vue {
get getActions() { get getActions() {
if (this.auditLog.actions && this.auditLog.actions.length > 0) { if (this.auditLog.actions && this.auditLog.actions.length > 0) {
return this.auditLog.actions.reverse() return this.sortByDateTime(this.auditLog.actions, 'executionTime')
} }
return new Array<Action>() return new Array<Action>()
} }
get getEntitiesChanges() {
if (this.auditLog.entityChanges && this.auditLog.entityChanges.length > 0) {
return this.sortByDateTime(this.auditLog.entityChanges, 'changeTime')
}
return new Array<EntityChange>()
}
private sortByDateTime(array: Array<any>, sortField: string) {
return array.sort((obj1, obj2) => {
if (obj1[sortField] && obj2[sortField]) {
const time1 = new Date(obj1[sortField])
const time2 = new Date(obj2[sortField])
return time1.getTime() - time2.getTime()
}
return 0
})
}
} }
</script> </script>

31
vueJs/src/views/admin/auditing/audit-log/index.vue

@ -157,6 +157,21 @@
</el-tag> </el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column
label="响应时间"
prop="executionDuration"
sortable
width="130px"
align="center"
>
<template slot-scope="{row}">
<el-tag
:type="row.executionDuration | executionDurationFilter"
>
{{ row.executionDuration }}
</el-tag>
</template>
</el-table-column>
<el-table-column <el-table-column
label="状态码" label="状态码"
prop="httpStatusCode" prop="httpStatusCode"
@ -312,6 +327,20 @@ const statusMap: { [key: string]: string } = {
return 'danger' return 'danger'
} }
return '' return ''
},
executionDurationFilter(executionDuration: number) {
if (executionDuration < 100) {
return 'success'
}
if (executionDuration < 500) {
return 'primary'
}
if (executionDuration < 1000) {
return 'warning'
}
if (executionDuration > 1000) {
return 'danger'
}
} }
}, },
methods: { methods: {
@ -361,7 +390,7 @@ export default class extends mixins(DataListMiXin) {
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss">
.data-filter-collapse-title { .data-filter-collapse-title {
font-size: 15px; font-size: 15px;
} }

Loading…
Cancel
Save