Browse Source

feat: Optimize audit logs

pull/1527/head
colin 3 months ago
parent
commit
b463e102a7
  1. 34
      apps/vben5/packages/@abp/auditing/src/components/audit-logs/AuditLogDrawer.vue
  2. 2
      apps/vben5/packages/@abp/auditing/src/types/audit-logs.ts
  3. 15
      apps/vben5/packages/@abp/identity/src/components/sessions/SessionTable.vue
  4. 91
      apps/vben5/packages/@abp/identity/src/components/users/UserTable.vue
  5. 7
      apps/vben5/packages/@abp/identity/src/types/sessions.ts
  6. 1
      aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.Elasticsearch/LINGYUN.Abp.AuditLogging.Elasticsearch.csproj
  7. 4
      aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/AuditLogQueue.cs
  8. 4
      aspnet-core/modules/auditing/LINGYUN.Abp.Auditing.Application.Contracts/LINGYUN/Abp/Auditing/AuditLogs/AuditLogDto.cs
  9. 1
      aspnet-core/modules/auditing/LINGYUN.Abp.Auditing.Application.Contracts/LINGYUN/Abp/Auditing/Features/AuditingFeatureDefinitionProvider.cs

34
apps/vben5/packages/@abp/auditing/src/components/audit-logs/AuditLogDrawer.vue

@ -148,17 +148,43 @@ async function onGet(id: string) {
<DescriptionsItem :label="$t('AbpAuditLogging.UserName')">
{{ auditLogModel.userName }}
</DescriptionsItem>
<DescriptionsItem :label="$t('AbpAuditLogging.HttpMethod')">
<Tag :color="getHttpMethodColor(auditLogModel.httpMethod)">
{{ auditLogModel.httpMethod }}
</Tag>
<DescriptionsItem :label="$t('AbpAuditLogging.TenantName')">
<span v-if="auditLogModel.tenantId">
{{ auditLogModel.tenantId }}/{{ auditLogModel.tenantName }}
</span>
</DescriptionsItem>
<template v-if="auditLogModel.impersonatorUserName">
<DescriptionsItem
:label="$t('AbpAuditLogging.ImpersonatorTenantId')"
>
<span v-if="auditLogModel.impersonatorTenantId">
{{ auditLogModel.impersonatorTenantId }}/{{
auditLogModel.impersonatorTenantName
}}
</span>
</DescriptionsItem>
<DescriptionsItem
:label="$t('AbpAuditLogging.ImpersonatorUserId')"
>
{{ auditLogModel.impersonatorUserId }}/{{
auditLogModel.impersonatorUserName
}}
</DescriptionsItem>
</template>
<DescriptionsItem
:label="$t('AbpAuditLogging.RequestUrl')"
:span="2"
>
{{ auditLogModel.url }}
</DescriptionsItem>
<DescriptionsItem
:label="$t('AbpAuditLogging.HttpMethod')"
:span="2"
>
<Tag :color="getHttpMethodColor(auditLogModel.httpMethod)">
{{ auditLogModel.httpMethod }}
</Tag>
</DescriptionsItem>
<DescriptionsItem :label="$t('AbpAuditLogging.HttpStatusCode')">
<Tag
:color="getHttpStatusCodeColor(auditLogModel.httpStatusCode)"

2
apps/vben5/packages/@abp/auditing/src/types/audit-logs.ts

@ -39,7 +39,9 @@ interface AuditLogDto {
httpStatusCode?: number;
id: string;
impersonatorTenantId?: string;
impersonatorTenantName?: string;
impersonatorUserId?: string;
impersonatorUserName?: string;
tenantId?: string;
tenantName?: string;
url?: string;

15
apps/vben5/packages/@abp/identity/src/components/sessions/SessionTable.vue

@ -85,6 +85,19 @@ const gridOptions: VxeGridProps<IdentitySessionDto> = {
sortable: true,
title: $t('AbpIdentity.DisplayName:SessionId'),
},
{
align: 'left',
field: 'userId',
formatter: ({ row }) => {
if (row.extraProperties?.UserName) {
return `${row.extraProperties.UserName} (${row.userId})`;
}
return row.userId;
},
minWidth: 150,
sortable: true,
title: $t('AbpIdentity.DisplayName:UserId'),
},
{
align: 'left',
field: 'device',
@ -98,7 +111,7 @@ const gridOptions: VxeGridProps<IdentitySessionDto> = {
field: 'deviceInfo',
sortable: true,
title: $t('AbpIdentity.DisplayName:DeviceInfo'),
width: 'auto',
minWidth: 200,
},
{
align: 'left',

91
apps/vben5/packages/@abp/identity/src/components/users/UserTable.vue

@ -61,20 +61,68 @@ const PermissionsOutlined = createIconifyIcon('icon-park-outline:permissions');
const SessionIcon = createIconifyIcon('carbon:prompt-session');
const AuditLogIcon = createIconifyIcon('fluent-mdl2:compliance-audit');
const getLockEnd = computed(() => {
return (row: IdentityUserDto) => {
if (row.lockoutEnd) {
const lockTime = new Date(row.lockoutEnd);
if (lockTime) {
// 锁定时间高于当前时间不显示
const nowTime = new Date();
return lockTime < nowTime;
}
const isCurrentUser = (user: IdentityUserDto) => {
return abpStore.application?.currentUser.id === user.id;
};
const getLockEnd = (row: IdentityUserDto) => {
if (row.lockoutEnd) {
const lockTime = new Date(row.lockoutEnd);
if (lockTime) {
// 锁定时间高于当前时间不显示
const nowTime = new Date();
return lockTime < nowTime;
}
return true;
}
return true;
};
const isDeleteEnabled = computed(() => {
return (user: IdentityUserDto) => {
return (
!isCurrentUser(user) && hasAccessByCodes([IdentityUserPermissions.Delete])
);
};
});
const isLockEnabled = computed(() => {
return (user: IdentityUserDto) => {
return (
!isCurrentUser(user) &&
user.isActive &&
getLockEnd(user) &&
hasAccessByCodes([IdentityUserPermissions.Update])
);
};
});
const isUnLockEnabled = computed(() => {
return (user: IdentityUserDto) => {
return (
!isCurrentUser(user) &&
user.isActive &&
!getLockEnd(user) &&
hasAccessByCodes([IdentityUserPermissions.Update])
);
};
});
const isImpersonationEnabled = computed(() => {
return (user: IdentityUserDto) => {
return (
!isCurrentUser(user) &&
hasAccessByCodes([IdentityUserPermissions.Impersonation])
);
};
});
const isAuditLogEnabled = computed(() => {
return (
isEnabled('AbpAuditing.Logging.AuditLog') &&
hasAccessByCodes([AuditLogPermissions.Default])
);
});
const abpStore = useAbpStore();
const { isEnabled } = useFeatures();
const { hasAccessByCodes } = useAccess();
@ -385,7 +433,7 @@ const handleMenuClick = async (row: IdentityUserDto, info: MenuInfo) => {
block
danger
type="link"
v-access:code="[IdentityUserPermissions.Delete]"
:disabled="!isDeleteEnabled(row)"
@click="handleDelete(row)"
>
{{ $t('AbpUi.Delete') }}
@ -396,22 +444,14 @@ const handleMenuClick = async (row: IdentityUserDto, info: MenuInfo) => {
<template #overlay>
<Menu @click="(info: MenuInfo) => handleMenuClick(row, info)">
<MenuItem
v-if="
hasAccessByCodes([IdentityUserPermissions.Update]) &&
row.isActive &&
getLockEnd(row)
"
v-if="isLockEnabled(row)"
key="lock"
:icon="h(LockOutlined)"
>
{{ $t('AbpIdentity.Lock') }}
</MenuItem>
<MenuItem
v-if="
hasAccessByCodes([IdentityUserPermissions.Update]) &&
row.isActive &&
!getLockEnd(row)
"
v-if="isUnLockEnabled(row)"
key="unlock"
:icon="h(UnlockOutlined)"
>
@ -446,9 +486,7 @@ const handleMenuClick = async (row: IdentityUserDto, info: MenuInfo) => {
{{ $t('AbpIdentity.ManageClaim') }}
</MenuItem>
<MenuItem
v-if="
hasAccessByCodes([IdentityUserPermissions.Impersonation])
"
v-if="isImpersonationEnabled(row)"
key="impersonation"
:icon="h(LoginOutlined)"
>
@ -472,10 +510,7 @@ const handleMenuClick = async (row: IdentityUserDto, info: MenuInfo) => {
</MenuItem>
<MenuDivider />
<MenuItem
v-if="
isEnabled('AbpAuditing.Logging.AuditLog') &&
hasAccessByCodes([AuditLogPermissions.Default])
"
v-if="isAuditLogEnabled"
key="entity-changes"
:icon="h(AuditLogIcon)"
>

7
apps/vben5/packages/@abp/identity/src/types/sessions.ts

@ -1,6 +1,9 @@
import type { EntityDto, PagedAndSortedResultRequestDto } from '@abp/core';
import type {
ExtensibleEntityDto,
PagedAndSortedResultRequestDto,
} from '@abp/core';
interface IdentitySessionDto extends EntityDto<string> {
interface IdentitySessionDto extends ExtensibleEntityDto<string> {
clientId?: string;
device: string;
deviceInfo: string;

1
aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.Elasticsearch/LINGYUN.Abp.AuditLogging.Elasticsearch.csproj

@ -15,7 +15,6 @@
<ItemGroup>
<PackageReference Include="Volo.Abp.Json" />
<PackageReference Include="System.Threading.Channels" />
</ItemGroup>
<ItemGroup>

4
aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/AuditLogQueue.cs

@ -30,7 +30,7 @@ public class AuditLogQueue : AuditLoggingQueue<AuditLogInfo>, IAuditLogQueue, IS
protected async override Task BulkWriteAsync(IEnumerable<AuditLogInfo> auditLogInfos, CancellationToken cancellationToken = default)
{
var tenantAuditlogGroup = auditLogInfos.GroupBy(x => x.ImpersonatorTenantId ?? x.TenantId);
var tenantAuditlogGroup = auditLogInfos.GroupBy(x => x.TenantId);
foreach (var tenantAuditlogs in tenantAuditlogGroup)
{
using (_currentTenant.Change(tenantAuditlogs.Key))
@ -42,7 +42,7 @@ public class AuditLogQueue : AuditLoggingQueue<AuditLogInfo>, IAuditLogQueue, IS
protected async override Task WriteAsync(AuditLogInfo auditLogInfo, CancellationToken cancellationToken = default)
{
using (_currentTenant.Change(auditLogInfo.ImpersonatorTenantId ?? auditLogInfo.TenantId))
using (_currentTenant.Change(auditLogInfo.TenantId))
{
await _auditLogWriter.WriteAsync(auditLogInfo, cancellationToken);
}

4
aspnet-core/modules/auditing/LINGYUN.Abp.Auditing.Application.Contracts/LINGYUN/Abp/Auditing/AuditLogs/AuditLogDto.cs

@ -18,8 +18,12 @@ public class AuditLogDto : ExtensibleEntityDto<Guid>
public Guid? ImpersonatorUserId { get; set; }
public string ImpersonatorUserName { get; set; }
public Guid? ImpersonatorTenantId { get; set; }
public string ImpersonatorTenantName { get; set; }
public DateTime ExecutionTime { get; set; }
public int ExecutionDuration { get; set; }

1
aspnet-core/modules/auditing/LINGYUN.Abp.Auditing.Application.Contracts/LINGYUN/Abp/Auditing/Features/AuditingFeatureDefinitionProvider.cs

@ -15,6 +15,7 @@ public class AuditingFeatureDefinitionProvider : FeatureDefinitionProvider
var loggingEnableFeature = auditingGroup.AddFeature(
name: AuditingFeatureNames.Logging.Enable,
defaultValue: true.ToString(),
displayName: L("Features:Auditing"),
description: L("Features:AuditingDesc")
);

Loading…
Cancel
Save