Browse Source

Merge pull request #1068 from colinin/ip-location

Ip location
pull/1070/head
yx lin 1 year ago
committed by GitHub
parent
commit
9eadb823f4
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 7
      apps/vben5/packages/@abp/auditing/src/components/audit-logs/AuditLogTable.vue
  2. 98
      apps/vben5/packages/@abp/identity/src/components/security-logs/SecurityLogDrawer.vue
  3. 7
      apps/vben5/packages/@abp/identity/src/components/security-logs/SecurityLogModal.vue
  4. 76
      apps/vben5/packages/@abp/identity/src/components/security-logs/SecurityLogTable.vue
  5. 1
      apps/vben5/packages/@abp/identity/src/constants/permissions.ts
  6. 0
      aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.IP.Location/FodyWeavers.xml
  7. 0
      aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.IP.Location/FodyWeavers.xsd
  8. 19
      aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.IP.Location/LINGYUN.Abp.AuditLogging.IP.Location.csproj
  9. 14
      aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.IP.Location/LINGYUN/Abp/AuditLogging/IP/Location/AbpAuditLoggingIPLocationModule.cs
  10. 5
      aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.IP.Location/LINGYUN/Abp/AuditLogging/IP/Location/AbpAuditLoggingIPLocationOptions.cs
  11. 35
      aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.IP.Location/LINGYUN/Abp/AuditLogging/IP/Location/IPLocationAuditingStore.cs
  12. 37
      aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.IP.Location/LINGYUN/Abp/AuditLogging/IP/Location/IPLocationSecurityLogStore.cs
  13. 5
      aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.IP2Region/LINGYUN/Abp/AuditLogging/IP2Region/AbpAuditLoggingIP2RegionOptions.cs
  14. 34
      aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.IP2Region/LINGYUN/Abp/AuditLogging/IP2Region/IP2RegionAuditingStore.cs
  15. 36
      aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.IP2Region/LINGYUN/Abp/AuditLogging/IP2Region/IP2RegionSecurityLogStore.cs
  16. 3
      aspnet-core/framework/common/LINGYUN.Abp.IP.Location/FodyWeavers.xml
  17. 30
      aspnet-core/framework/common/LINGYUN.Abp.IP.Location/FodyWeavers.xsd
  18. 21
      aspnet-core/framework/common/LINGYUN.Abp.IP.Location/LINGYUN.Abp.IP.Location.csproj
  19. 12
      aspnet-core/framework/common/LINGYUN.Abp.IP.Location/LINGYUN/Abp/IP/Location/AbpIPLocationModule.cs
  20. 14
      aspnet-core/framework/common/LINGYUN.Abp.IP.Location/LINGYUN/Abp/IP/Location/AbpIPLocationResolveOptions.cs
  21. 19
      aspnet-core/framework/common/LINGYUN.Abp.IP.Location/LINGYUN/Abp/IP/Location/AsyncLocalCurrentIPLocationAccessor.cs
  22. 40
      aspnet-core/framework/common/LINGYUN.Abp.IP.Location/LINGYUN/Abp/IP/Location/CurrentIPLocation.cs
  23. 15
      aspnet-core/framework/common/LINGYUN.Abp.IP.Location/LINGYUN/Abp/IP/Location/ICurrentIPLocation.cs
  24. 5
      aspnet-core/framework/common/LINGYUN.Abp.IP.Location/LINGYUN/Abp/IP/Location/ICurrentIPLocationAccessor.cs
  25. 11
      aspnet-core/framework/common/LINGYUN.Abp.IP.Location/LINGYUN/Abp/IP/Location/IIPLocationResolveContext.cs
  26. 9
      aspnet-core/framework/common/LINGYUN.Abp.IP.Location/LINGYUN/Abp/IP/Location/IIPLocationResolveContributor.cs
  27. 9
      aspnet-core/framework/common/LINGYUN.Abp.IP.Location/LINGYUN/Abp/IP/Location/IIPLocationResolver.cs
  28. 19
      aspnet-core/framework/common/LINGYUN.Abp.IP.Location/LINGYUN/Abp/IP/Location/IPLocation.cs
  29. 24
      aspnet-core/framework/common/LINGYUN.Abp.IP.Location/LINGYUN/Abp/IP/Location/IPLocationResolveContext.cs
  30. 9
      aspnet-core/framework/common/LINGYUN.Abp.IP.Location/LINGYUN/Abp/IP/Location/IPLocationResolveContributorBase.cs
  31. 14
      aspnet-core/framework/common/LINGYUN.Abp.IP.Location/LINGYUN/Abp/IP/Location/IPLocationResolveResult.cs
  32. 43
      aspnet-core/framework/common/LINGYUN.Abp.IP.Location/LINGYUN/Abp/IP/Location/IPLocationResolver.cs
  33. 4
      aspnet-core/framework/common/LINGYUN.Abp.IP2Region/LINGYUN.Abp.IP2Region.csproj
  34. 8
      aspnet-core/framework/common/LINGYUN.Abp.IP2Region/LINGYUN/Abp/IP2Region/AbpIP2RegionModule.cs
  35. 14
      aspnet-core/framework/common/LINGYUN.Abp.IP2Region/LINGYUN/Abp/IP2Region/IIpLocationInfoProvider.cs
  36. 68
      aspnet-core/framework/common/LINGYUN.Abp.IP2Region/LINGYUN/Abp/IP2Region/IP2RegionIPLocationResolveContributorBase.cs
  37. 68
      aspnet-core/framework/common/LINGYUN.Abp.IP2Region/LINGYUN/Abp/IP2Region/IP2RegionLocationInfoProvider.cs
  38. 8
      aspnet-core/framework/common/LINGYUN.Abp.IP2Region/LINGYUN/Abp/IP2Region/LocationInfo.cs

7
apps/vben5/packages/@abp/auditing/src/components/audit-logs/AuditLogTable.vue

@ -163,6 +163,7 @@ const gridOptions: VxeGridProps<AuditLogDto> = {
{
align: 'left',
field: 'clientIpAddress',
slots: { default: 'clientIpAddress' },
sortable: true,
title: $t('AbpAuditLogging.ClientIpAddress'),
width: 150,
@ -280,6 +281,12 @@ function onFilter(field: string, value: any) {
<template>
<Grid :table-title="$t('AbpAuditLogging.AuditLog')">
<template #clientIpAddress="{ row }">
<Tag v-if="row.extraProperties?.Location" color="blue">
{{ row.extraProperties?.Location }}
</Tag>
<span>{{ row.clientIpAddress }}</span>
</template>
<template #url="{ row }">
<Tag
:color="getHttpStatusCodeColor(row.httpStatusCode)"

98
apps/vben5/packages/@abp/identity/src/components/security-logs/SecurityLogDrawer.vue

@ -0,0 +1,98 @@
<script setup lang="ts">
import type { SecurityLogDto } from '../../types/security-logs';
import { ref } from 'vue';
import { useVbenDrawer } from '@vben/common-ui';
import { $t } from '@vben/locales';
import { formatToDateTime } from '@abp/core';
import { Descriptions } from 'ant-design-vue';
import { getApi } from '../../api/security-logs';
defineOptions({
name: 'SecurityLogDrawer',
});
const DescriptionsItem = Descriptions.Item;
const formModel = ref<SecurityLogDto>({} as SecurityLogDto);
const [Drawer, drawerApi] = useVbenDrawer({
class: 'w-auto',
onCancel() {
drawerApi.close();
},
onConfirm: async () => {},
onOpenChange: async (isOpen: boolean) => {
formModel.value = {} as SecurityLogDto;
if (isOpen) {
try {
drawerApi.setState({ loading: true });
const dto = drawerApi.getData<SecurityLogDto>();
await onGet(dto.id);
} finally {
drawerApi.setState({ loading: false });
}
}
},
title: $t('AbpAuditLogging.SecurityLog'),
});
/** 查询审计日志 */
async function onGet(id: string) {
const dto = await getApi(id);
formModel.value = dto;
}
</script>
<template>
<Drawer>
<div style="width: 800px">
<Descriptions :colon="false" :column="2" bordered size="small">
<DescriptionsItem :label="$t('AbpAuditLogging.ApplicationName')">
{{ formModel.applicationName }}
</DescriptionsItem>
<DescriptionsItem :label="$t('AbpAuditLogging.CreationTime')">
{{ formatToDateTime(formModel.creationTime) }}
</DescriptionsItem>
<DescriptionsItem :label="$t('AbpAuditLogging.Identity')">
{{ formModel.identity }}
</DescriptionsItem>
<DescriptionsItem :label="$t('AbpAuditLogging.TenantName')">
{{ formModel.tenantName }}
</DescriptionsItem>
<DescriptionsItem :label="$t('AbpAuditLogging.Actions')">
{{ formModel.action }}
</DescriptionsItem>
<DescriptionsItem :label="$t('AbpAuditLogging.CorrelationId')">
{{ formModel.correlationId }}
</DescriptionsItem>
<DescriptionsItem :label="$t('AbpAuditLogging.UserId')">
{{ formModel.userId }}
</DescriptionsItem>
<DescriptionsItem :label="$t('AbpAuditLogging.UserName')">
{{ formModel.userName }}
</DescriptionsItem>
<DescriptionsItem :label="$t('AbpAuditLogging.ClientId')">
{{ formModel.clientId }}
</DescriptionsItem>
<DescriptionsItem :label="$t('AbpAuditLogging.ClientIpAddress')">
{{ formModel.clientIpAddress }}
</DescriptionsItem>
<DescriptionsItem
:label="$t('AbpAuditLogging.BrowserInfo')"
:label-style="{ width: '110px' }"
:span="2"
>
{{ formModel.browserInfo }}
</DescriptionsItem>
<DescriptionsItem :label="$t('AbpAuditLogging.Additional')" :span="2">
{{ formModel.extraProperties }}
</DescriptionsItem>
</Descriptions>
</div>
</Drawer>
</template>
<style scoped></style>

7
apps/vben5/packages/@abp/identity/src/components/security-logs/SecurityLogModal.vue

@ -1,7 +0,0 @@
<script setup lang="ts"></script>
<template>
<div></div>
</template>
<style scoped></style>

76
apps/vben5/packages/@abp/identity/src/components/security-logs/SecurityLogTable.vue

@ -3,14 +3,15 @@ import type { VbenFormProps, VxeGridListeners, VxeGridProps } from '@abp/ui';
import type { SecurityLogDto } from '../../types/security-logs';
import { h } from 'vue';
import { defineAsyncComponent, h } from 'vue';
import { useVbenDrawer } from '@vben/common-ui';
import { $t } from '@vben/locales';
import { formatToDateTime } from '@abp/core';
import { formatToDateTime, type SortOrder } from '@abp/core';
import { useVbenVxeGrid } from '@abp/ui';
import { DeleteOutlined } from '@ant-design/icons-vue';
import { Button, message, Modal } from 'ant-design-vue';
import { DeleteOutlined, EditOutlined } from '@ant-design/icons-vue';
import { Button, message, Modal, Tag } from 'ant-design-vue';
import { deleteApi, getPagedListApi } from '../../api/security-logs';
import { SecurityLogPermissions } from '../../constants/permissions';
@ -76,69 +77,80 @@ const gridOptions: VxeGridProps<SecurityLogDto> = {
formatter: ({ cellValue }) => {
return cellValue ? formatToDateTime(cellValue) : cellValue;
},
sortable: true,
title: $t('AbpAuditLogging.CreationTime'),
width: 180,
},
{
align: 'left',
field: 'identity',
sortable: true,
title: $t('AbpAuditLogging.Identity'),
width: 180,
},
{
align: 'left',
field: 'userName',
sortable: true,
title: $t('AbpAuditLogging.UserName'),
width: 150,
},
{
align: 'left',
field: 'clientId',
sortable: true,
title: $t('AbpAuditLogging.ClientId'),
width: 200,
},
{
align: 'left',
field: 'clientIpAddress',
slots: { default: 'clientIpAddress' },
sortable: true,
title: $t('AbpAuditLogging.ClientIpAddress'),
width: 200,
},
{
align: 'left',
field: 'applicationName',
sortable: true,
title: $t('AbpAuditLogging.ApplicationName'),
width: 200,
},
{
align: 'left',
field: 'tenantName',
sortable: true,
title: $t('AbpAuditLogging.TenantName'),
width: 180,
},
{
align: 'left',
field: 'actions',
field: 'action',
sortable: true,
title: $t('AbpAuditLogging.Actions'),
width: 180,
},
{
align: 'left',
field: 'correlationId',
sortable: true,
title: $t('AbpAuditLogging.CorrelationId'),
width: 200,
},
{
align: 'left',
field: 'browserInfo',
sortable: true,
title: $t('AbpAuditLogging.BrowserInfo'),
width: 'auto',
},
{
field: 'action',
field: 'actions',
fixed: 'right',
slots: { default: 'action' },
title: $t('AbpUi.Actions'),
width: 150,
width: 220,
},
],
exportConfig: {},
@ -168,50 +180,74 @@ const gridOptions: VxeGridProps<SecurityLogDto> = {
};
const gridEvents: VxeGridListeners<SecurityLogDto> = {
cellClick: () => {},
sortChange: onSort,
};
const [Grid, { query }] = useVbenVxeGrid({
const [Grid, gridApi] = useVbenVxeGrid({
formOptions,
gridEvents,
gridOptions,
});
const [SecurityLogDrawer, drawerApi] = useVbenDrawer({
connectedComponent: defineAsyncComponent(
() => import('./SecurityLogDrawer.vue'),
),
});
function onUpdate(row: SecurityLogDto) {
drawerApi.setData(row);
drawerApi.open();
}
const handleDelete = (row: SecurityLogDto) => {
function onDelete(row: SecurityLogDto) {
Modal.confirm({
centered: true,
content: $t('AbpUi.ItemWillBeDeletedMessage'),
onOk: async () => {
await deleteApi(row.id);
message.success($t('AbpUi.SuccessfullyDeleted'));
query();
gridApi.query();
},
title: $t('AbpUi.AreYouSure'),
});
};
}
function onSort(params: { field: string; order: SortOrder }) {
const sorting = params.order ? `${params.field} ${params.order}` : undefined;
gridApi.query({ sorting });
}
</script>
<template>
<Grid :table-title="$t('AbpAuditLogging.SecurityLog')">
<template #clientIpAddress="{ row }">
<Tag v-if="row.extraProperties?.Location" color="blue">
{{ row.extraProperties?.Location }}
</Tag>
<span>{{ row.clientIpAddress }}</span>
</template>
<template #action="{ row }">
<div class="flex flex-row">
<Button
:icon="h(EditOutlined)"
block
type="link"
v-access:code="[SecurityLogPermissions.Default]"
@click="onUpdate(row)"
>
{{ $t('AbpUi.Edit') }}
</Button>
<Button
:icon="h(DeleteOutlined)"
block
danger
type="link"
v-access:code="[SecurityLogPermissions.Delete]"
@click="handleDelete(row)"
@click="onDelete(row)"
>
{{ $t('AbpUi.Delete') }}
</Button>
</div>
</template>
</Grid>
<SecurityLogDrawer />
</template>
<style lang="scss" scoped>
.checkbox-box {
display: flex;
justify-content: center;
}
</style>

1
apps/vben5/packages/@abp/identity/src/constants/permissions.ts

@ -42,6 +42,7 @@ export const OrganizationUnitPermissions = {
};
/** 安全日志权限 */
export const SecurityLogPermissions = {
Default: 'AbpAuditing.SecurityLog',
/** 删除 */
Delete: 'AbpAuditing.SecurityLog.Delete',
};

0
aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.IP2Region/FodyWeavers.xml → aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.IP.Location/FodyWeavers.xml

0
aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.IP2Region/FodyWeavers.xsd → aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.IP.Location/FodyWeavers.xsd

19
aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.IP2Region/LINGYUN.Abp.AuditLogging.IP2Region.csproj → aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.IP.Location/LINGYUN.Abp.AuditLogging.IP.Location.csproj

@ -7,19 +7,20 @@
<TargetFrameworks>netstandard2.0;netstandard2.1;net8.0</TargetFrameworks>
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
<AssemblyName>LINGYUN.Abp.AuditLogging.IP2Region</AssemblyName>
<PackageId>LINGYUN.Abp.AuditLogging.IP2Region</PackageId>
<AssemblyName>LINGYUN.Abp.AuditLogging.IP.Location</AssemblyName>
<PackageId>LINGYUN.Abp.AuditLogging.IP.Location</PackageId>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<RootNamespace />
</PropertyGroup><PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
</PropertyGroup>
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\common\LINGYUN.Abp.IP2Region\LINGYUN.Abp.IP2Region.csproj" />
<ProjectReference Include="..\LINGYUN.Abp.AuditLogging\LINGYUN.Abp.AuditLogging.csproj" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\common\LINGYUN.Abp.IP.Location\LINGYUN.Abp.IP.Location.csproj" />
<ProjectReference Include="..\LINGYUN.Abp.AuditLogging\LINGYUN.Abp.AuditLogging.csproj" />
</ItemGroup>
</Project>

14
aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.IP2Region/LINGYUN/Abp/AuditLogging/IP2Region/AbpAuditLoggingIP2RegionModule.cs → aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.IP.Location/LINGYUN/Abp/AuditLogging/IP/Location/AbpAuditLoggingIPLocationModule.cs

@ -1,26 +1,26 @@
using LINGYUN.Abp.IP2Region;
using LINGYUN.Abp.IP.Location;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Volo.Abp.Auditing;
using Volo.Abp.Modularity;
using Volo.Abp.SecurityLog;
namespace LINGYUN.Abp.AuditLogging.IP2Region;
namespace LINGYUN.Abp.AuditLogging.IP.Location;
[DependsOn(
typeof(AbpIP2RegionModule),
typeof(AbpIPLocationModule),
typeof(AbpAuditLoggingModule))]
public class AbpAuditLoggingIP2RegionModule : AbpModule
public class AbpAuditLoggingIPLocationModule : AbpModule
{
public override void PostConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Services.GetConfiguration();
Configure<AbpAuditLoggingIP2RegionOptions>(configuration.GetSection("AuditLogging:IP2Region"));
Configure<AbpAuditLoggingIPLocationOptions>(configuration.GetSection("AuditLogging:IPLocation"));
context.Services.Replace(
ServiceDescriptor.Transient<IAuditingStore, IP2RegionAuditingStore>());
ServiceDescriptor.Transient<IAuditingStore, IPLocationAuditingStore>());
context.Services.Replace(
ServiceDescriptor.Transient<ISecurityLogStore, IP2RegionSecurityLogStore>());
ServiceDescriptor.Transient<ISecurityLogStore, IPLocationSecurityLogStore>());
}
}

5
aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.IP.Location/LINGYUN/Abp/AuditLogging/IP/Location/AbpAuditLoggingIPLocationOptions.cs

@ -0,0 +1,5 @@
namespace LINGYUN.Abp.AuditLogging.IP.Location;
public class AbpAuditLoggingIPLocationOptions
{
public bool IsEnabled { get; set; }
}

35
aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.IP.Location/LINGYUN/Abp/AuditLogging/IP/Location/IPLocationAuditingStore.cs

@ -0,0 +1,35 @@
using LINGYUN.Abp.IP.Location;
using Microsoft.Extensions.Options;
using System;
using System.Threading.Tasks;
using Volo.Abp.Auditing;
namespace LINGYUN.Abp.AuditLogging.IP.Location;
public class IPLocationAuditingStore : AuditingStore
{
private readonly AbpAuditLoggingIPLocationOptions _options;
private readonly IIPLocationResolver _iPLocationResolver;
public IPLocationAuditingStore(
IOptionsMonitor<AbpAuditLoggingIPLocationOptions> options,
IIPLocationResolver iPLocationResolver,
IAuditLogManager manager)
: base(manager)
{
_options = options.CurrentValue;
_iPLocationResolver = iPLocationResolver;
}
public async override Task SaveAsync(AuditLogInfo auditInfo)
{
if (_options.IsEnabled && !auditInfo.ClientIpAddress.IsNullOrWhiteSpace())
{
var result = await _iPLocationResolver.ResolveAsync(auditInfo.ClientIpAddress);
if (result.Location?.Remarks?.IsNullOrWhiteSpace() == false)
{
auditInfo.ExtraProperties.Add("Location", $"{result.Location.Remarks}");
}
}
await base.SaveAsync(auditInfo);
}
}

37
aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.IP.Location/LINGYUN/Abp/AuditLogging/IP/Location/IPLocationSecurityLogStore.cs

@ -0,0 +1,37 @@
using LINGYUN.Abp.IP.Location;
using Microsoft.Extensions.Options;
using System;
using System.Threading.Tasks;
using Volo.Abp.SecurityLog;
namespace LINGYUN.Abp.AuditLogging.IP.Location;
public class IPLocationSecurityLogStore : SecurityLogStore
{
private readonly AbpAuditLoggingIPLocationOptions _options;
private readonly IIPLocationResolver _iPLocationResolver;
public IPLocationSecurityLogStore(
IOptionsMonitor<AbpAuditLoggingIPLocationOptions> options,
IIPLocationResolver iPLocationResolver,
ISecurityLogManager manager)
: base(manager)
{
_options = options.CurrentValue;
_iPLocationResolver = iPLocationResolver;
}
public async override Task SaveAsync(SecurityLogInfo securityLogInfo)
{
if (_options.IsEnabled && !securityLogInfo.ClientIpAddress.IsNullOrWhiteSpace())
{
var result = await _iPLocationResolver.ResolveAsync(securityLogInfo.ClientIpAddress);
if (result.Location?.Remarks?.IsNullOrWhiteSpace() == false)
{
securityLogInfo.ExtraProperties.Add("Location", $"{result.Location.Remarks}");
}
}
await base.SaveAsync(securityLogInfo);
}
}

5
aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.IP2Region/LINGYUN/Abp/AuditLogging/IP2Region/AbpAuditLoggingIP2RegionOptions.cs

@ -1,5 +0,0 @@
namespace LINGYUN.Abp.AuditLogging.IP2Region;
public class AbpAuditLoggingIP2RegionOptions
{
public bool IsEnabled { get; set; }
}

34
aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.IP2Region/LINGYUN/Abp/AuditLogging/IP2Region/IP2RegionAuditingStore.cs

@ -1,34 +0,0 @@
using LINGYUN.Abp.IP2Region;
using Microsoft.Extensions.Options;
using System;
using System.Threading.Tasks;
using Volo.Abp.Auditing;
namespace LINGYUN.Abp.AuditLogging.IP2Region;
public class IP2RegionAuditingStore : AuditingStore
{
private readonly AbpAuditLoggingIP2RegionOptions _options;
private readonly IIpLocationInfoProvider _ipLocationInfoProvider;
public IP2RegionAuditingStore(
IOptionsMonitor<AbpAuditLoggingIP2RegionOptions> options,
IIpLocationInfoProvider ipLocationInfoProvider,
IAuditLogManager manager)
: base(manager)
{
_options = options.CurrentValue;
_ipLocationInfoProvider = ipLocationInfoProvider;
}
public async override Task SaveAsync(AuditLogInfo auditInfo)
{
if (_options.IsEnabled && !auditInfo.ClientIpAddress.IsNullOrWhiteSpace())
{
var locationInfo = await _ipLocationInfoProvider.GetLocationInfoAsync(auditInfo.ClientIpAddress);
if (locationInfo?.Remarks?.IsNullOrWhiteSpace() == false)
{
auditInfo.ExtraProperties.Add("Location", $"{locationInfo.Remarks}");
}
}
await base.SaveAsync(auditInfo);
}
}

36
aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.IP2Region/LINGYUN/Abp/AuditLogging/IP2Region/IP2RegionSecurityLogStore.cs

@ -1,36 +0,0 @@
using LINGYUN.Abp.IP2Region;
using Microsoft.Extensions.Options;
using System;
using System.Threading.Tasks;
using Volo.Abp.SecurityLog;
namespace LINGYUN.Abp.AuditLogging.IP2Region;
public class IP2RegionSecurityLogStore : SecurityLogStore
{
private readonly AbpAuditLoggingIP2RegionOptions _options;
private readonly IIpLocationInfoProvider _ipLocationInfoProvider;
public IP2RegionSecurityLogStore(
IOptionsMonitor<AbpAuditLoggingIP2RegionOptions> options,
IIpLocationInfoProvider ipLocationInfoProvider,
ISecurityLogManager manager)
: base(manager)
{
_options = options.CurrentValue;
_ipLocationInfoProvider = ipLocationInfoProvider;
}
public async override Task SaveAsync(SecurityLogInfo securityLogInfo)
{
if (_options.IsEnabled && !securityLogInfo.ClientIpAddress.IsNullOrWhiteSpace())
{
var locationInfo = await _ipLocationInfoProvider.GetLocationInfoAsync(securityLogInfo.ClientIpAddress);
if (locationInfo?.Remarks?.IsNullOrWhiteSpace() == false)
{
securityLogInfo.ExtraProperties.Add("Location", $"{locationInfo.Remarks}");
}
}
await base.SaveAsync(securityLogInfo);
}
}

3
aspnet-core/framework/common/LINGYUN.Abp.IP.Location/FodyWeavers.xml

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

30
aspnet-core/framework/common/LINGYUN.Abp.IP.Location/FodyWeavers.xsd

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

21
aspnet-core/framework/common/LINGYUN.Abp.IP.Location/LINGYUN.Abp.IP.Location.csproj

@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\..\configureawait.props" />
<Import Project="..\..\..\..\common.props" />
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netstandard2.1;net8.0</TargetFrameworks>
<AssemblyName>LINGYUN.Abp.IP.Location</AssemblyName>
<PackageId>LINGYUN.Abp.IP.Location</PackageId>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<Nullable>enable</Nullable>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.Core" />
</ItemGroup>
</Project>

12
aspnet-core/framework/common/LINGYUN.Abp.IP.Location/LINGYUN/Abp/IP/Location/AbpIPLocationModule.cs

@ -0,0 +1,12 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Modularity;
namespace LINGYUN.Abp.IP.Location;
public class AbpIPLocationModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddSingleton<ICurrentIPLocationAccessor>(AsyncLocalCurrentIPLocationAccessor.Instance);
}
}

14
aspnet-core/framework/common/LINGYUN.Abp.IP.Location/LINGYUN/Abp/IP/Location/AbpIPLocationResolveOptions.cs

@ -0,0 +1,14 @@
using JetBrains.Annotations;
using System.Collections.Generic;
namespace LINGYUN.Abp.IP.Location;
public class AbpIPLocationResolveOptions
{
[NotNull]
public List<IIPLocationResolveContributor> IPLocationResolvers { get; }
public AbpIPLocationResolveOptions()
{
IPLocationResolvers = new List<IIPLocationResolveContributor>();
}
}

19
aspnet-core/framework/common/LINGYUN.Abp.IP.Location/LINGYUN/Abp/IP/Location/AsyncLocalCurrentIPLocationAccessor.cs

@ -0,0 +1,19 @@
using System.Threading;
namespace LINGYUN.Abp.IP.Location;
public class AsyncLocalCurrentIPLocationAccessor : ICurrentIPLocationAccessor
{
public static AsyncLocalCurrentIPLocationAccessor Instance { get; } = new();
public IPLocation? Current {
get => _currentScope.Value;
set => _currentScope.Value = value;
}
private readonly AsyncLocal<IPLocation?> _currentScope;
private AsyncLocalCurrentIPLocationAccessor()
{
_currentScope = new AsyncLocal<IPLocation?>();
}
}

40
aspnet-core/framework/common/LINGYUN.Abp.IP.Location/LINGYUN/Abp/IP/Location/CurrentIPLocation.cs

@ -0,0 +1,40 @@
using System;
using Volo.Abp;
using Volo.Abp.DependencyInjection;
namespace LINGYUN.Abp.IP.Location;
public class CurrentIPLocation : ICurrentIPLocation, ITransientDependency
{
public string? Country => _currentIPLocationAccessor.Current?.Country;
public string? Province => _currentIPLocationAccessor.Current?.Province;
public string? City => _currentIPLocationAccessor.Current?.City;
public string? Remarks => _currentIPLocationAccessor.Current?.Remarks;
private readonly ICurrentIPLocationAccessor _currentIPLocationAccessor;
public CurrentIPLocation(ICurrentIPLocationAccessor currentIPLocationAccessor)
{
_currentIPLocationAccessor = currentIPLocationAccessor;
}
public IDisposable Change(IPLocation? location = null)
{
return SetCurrent(location);
}
private IDisposable SetCurrent(IPLocation? location = null)
{
var parentScope = _currentIPLocationAccessor.Current;
_currentIPLocationAccessor.Current = location;
return new DisposeAction<ValueTuple<ICurrentIPLocationAccessor, IPLocation?>>(static (state) =>
{
var (currentIPLocationAccessor, parentScope) = state;
currentIPLocationAccessor.Current = parentScope;
}, (_currentIPLocationAccessor, parentScope));
}
}

15
aspnet-core/framework/common/LINGYUN.Abp.IP.Location/LINGYUN/Abp/IP/Location/ICurrentIPLocation.cs

@ -0,0 +1,15 @@
using System;
namespace LINGYUN.Abp.IP.Location;
public interface ICurrentIPLocation
{
string? Country { get; }
string? Province { get; }
string? City { get; }
string? Remarks { get; }
IDisposable Change(IPLocation? location = null);
}

5
aspnet-core/framework/common/LINGYUN.Abp.IP.Location/LINGYUN/Abp/IP/Location/ICurrentIPLocationAccessor.cs

@ -0,0 +1,5 @@
namespace LINGYUN.Abp.IP.Location;
public interface ICurrentIPLocationAccessor
{
IPLocation? Current { get; set; }
}

11
aspnet-core/framework/common/LINGYUN.Abp.IP.Location/LINGYUN/Abp/IP/Location/IIPLocationResolveContext.cs

@ -0,0 +1,11 @@
using Volo.Abp.DependencyInjection;
namespace LINGYUN.Abp.IP.Location;
public interface IIPLocationResolveContext : IServiceProviderAccessor
{
string IpAddress { get; }
IPLocation? Location { get; set; }
bool Handled { get; set; }
}

9
aspnet-core/framework/common/LINGYUN.Abp.IP.Location/LINGYUN/Abp/IP/Location/IIPLocationResolveContributor.cs

@ -0,0 +1,9 @@
using System.Threading.Tasks;
namespace LINGYUN.Abp.IP.Location;
public interface IIPLocationResolveContributor
{
string Name { get; }
Task ResolveAsync(IIPLocationResolveContext context);
}

9
aspnet-core/framework/common/LINGYUN.Abp.IP.Location/LINGYUN/Abp/IP/Location/IIPLocationResolver.cs

@ -0,0 +1,9 @@
using JetBrains.Annotations;
using System.Threading.Tasks;
namespace LINGYUN.Abp.IP.Location;
public interface IIPLocationResolver
{
[NotNull]
Task<IPLocationResolveResult> ResolveAsync(string ipAddress);
}

19
aspnet-core/framework/common/LINGYUN.Abp.IP.Location/LINGYUN/Abp/IP/Location/IPLocation.cs

@ -0,0 +1,19 @@
namespace LINGYUN.Abp.IP.Location;
public class IPLocation
{
public string? Country { get; }
public string? Province { get;}
public string? City { get; }
public string? Remarks { get; set; }
public IPLocation(
string? country = null,
string? province = null,
string? city = null,
string? remarks = null)
{
Country = country;
Province = province;
City = city;
Remarks = remarks;
}
}

24
aspnet-core/framework/common/LINGYUN.Abp.IP.Location/LINGYUN/Abp/IP/Location/IPLocationResolveContext.cs

@ -0,0 +1,24 @@
using System;
namespace LINGYUN.Abp.IP.Location;
public class IPLocationResolveContext : IIPLocationResolveContext
{
public IServiceProvider ServiceProvider { get; }
public string IpAddress { get; }
public IPLocation? Location { get; set; }
public bool Handled { get; set; }
public bool HasResolvedIPLocation()
{
return Handled || Location != null;
}
public IPLocationResolveContext(string ipAddress, IServiceProvider serviceProvider)
{
IpAddress = ipAddress;
ServiceProvider = serviceProvider;
}
}

9
aspnet-core/framework/common/LINGYUN.Abp.IP.Location/LINGYUN/Abp/IP/Location/IPLocationResolveContributorBase.cs

@ -0,0 +1,9 @@
using System.Threading.Tasks;
namespace LINGYUN.Abp.IP.Location;
public abstract class IPLocationResolveContributorBase : IIPLocationResolveContributor
{
public abstract string Name { get; }
public abstract Task ResolveAsync(IIPLocationResolveContext context);
}

14
aspnet-core/framework/common/LINGYUN.Abp.IP.Location/LINGYUN/Abp/IP/Location/IPLocationResolveResult.cs

@ -0,0 +1,14 @@
using System.Collections.Generic;
namespace LINGYUN.Abp.IP.Location;
public class IPLocationResolveResult
{
public IPLocation? Location { get; set; }
public List<string> AppliedResolvers { get; }
public IPLocationResolveResult()
{
AppliedResolvers = new List<string>();
}
}

43
aspnet-core/framework/common/LINGYUN.Abp.IP.Location/LINGYUN/Abp/IP/Location/IPLocationResolver.cs

@ -0,0 +1,43 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using System;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
namespace LINGYUN.Abp.IP.Location;
public class IPLocationResolver : IIPLocationResolver, ITransientDependency
{
private readonly IServiceProvider _serviceProvider;
private readonly AbpIPLocationResolveOptions _options;
public IPLocationResolver(IOptions<AbpIPLocationResolveOptions> options, IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
_options = options.Value;
}
public virtual async Task<IPLocationResolveResult> ResolveAsync(string ipAddress)
{
var result = new IPLocationResolveResult();
using (var serviceScope = _serviceProvider.CreateScope())
{
var context = new IPLocationResolveContext(ipAddress, serviceScope.ServiceProvider);
foreach (var ipLocationResolver in _options.IPLocationResolvers)
{
await ipLocationResolver.ResolveAsync(context);
result.AppliedResolvers.Add(ipLocationResolver.Name);
if (context.HasResolvedIPLocation())
{
result.Location = context.Location;
break;
}
}
}
return result;
}
}

4
aspnet-core/framework/common/LINGYUN.Abp.IP2Region/LINGYUN.Abp.IP2Region.csproj

@ -24,4 +24,8 @@
<PackageReference Include="IP2Region.Net" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LINGYUN.Abp.IP.Location\LINGYUN.Abp.IP.Location.csproj" />
</ItemGroup>
</Project>

8
aspnet-core/framework/common/LINGYUN.Abp.IP2Region/LINGYUN/Abp/IP2Region/AbpIP2RegionModule.cs

@ -1,12 +1,13 @@
using IP2Region.Net.Abstractions;
using IP2Region.Net.XDB;
using LINGYUN.Abp.IP.Location;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Volo.Abp.Modularity;
using Volo.Abp.VirtualFileSystem;
namespace LINGYUN.Abp.IP2Region;
[DependsOn(typeof(AbpIPLocationModule))]
[DependsOn(typeof(AbpVirtualFileSystemModule))]
public class AbpIP2RegionModule : AbpModule
{
@ -26,6 +27,9 @@ public class AbpIP2RegionModule : AbpModule
return searcher;
});
context.Services.TryAddTransient<IIpLocationInfoProvider, IP2RegionLocationInfoProvider>();
Configure<AbpIPLocationResolveOptions>(options =>
{
options.IPLocationResolvers.Add(new IP2RegionIPLocationResolveContributorBase());
});
}
}

14
aspnet-core/framework/common/LINGYUN.Abp.IP2Region/LINGYUN/Abp/IP2Region/IIpLocationInfoProvider.cs

@ -1,14 +0,0 @@
using System.Threading.Tasks;
namespace LINGYUN.Abp.IP2Region;
public interface IIpLocationInfoProvider
{
/// <summary>
/// 通过ip地址获取地理信息
/// </summary>
/// <param name="ipAddress">ip地址</param>
/// <returns>
/// 如果解析成功返回地理信息,否则返回null
/// </returns>
Task<LocationInfo?> GetLocationInfoAsync(string ipAddress);
}

68
aspnet-core/framework/common/LINGYUN.Abp.IP2Region/LINGYUN/Abp/IP2Region/IP2RegionIPLocationResolveContributorBase.cs

@ -0,0 +1,68 @@
using IP2Region.Net.Abstractions;
using LINGYUN.Abp.IP.Location;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Threading.Tasks;
namespace LINGYUN.Abp.IP2Region;
public class IP2RegionIPLocationResolveContributorBase : IPLocationResolveContributorBase
{
public const string ContributorName = "IP2Region";
public override string Name => ContributorName;
public override Task ResolveAsync(IIPLocationResolveContext context)
{
var searcher = context.ServiceProvider.GetRequiredService<ISearcher>();
var region = searcher.Search(context.IpAddress);
if (string.IsNullOrWhiteSpace(region))
{
return Task.CompletedTask;
}
var regions = region!.Split('|');
// | 0 | 1 | 2 |3| 4 | 5 | 6 |
// 39.128.0.0|39.128.31.255|中国|0|云南省|昆明市|移动
// regions:
// 中国 0 云南省 昆明市 移动
var ipLocation = new IPLocation(
regions.Length >= 1 && !string.Equals(regions[0], "0") ? regions[0] : null,
regions.Length >= 3 && !string.Equals(regions[2], "0") ? regions[2] : null,
regions.Length >= 4 && !string.Equals(regions[3], "0") ? regions[3] : null);
// 36.133.108.0|36.133.119.255|中国|0|重庆|重庆市|移动
if (!ipLocation.Province.IsNullOrWhiteSpace() && !ipLocation.City.IsNullOrWhiteSpace())
{
if (ipLocation.Province.Length < ipLocation.City.Length &&
ipLocation.City.StartsWith(ipLocation.Province, StringComparison.InvariantCultureIgnoreCase))
{
// 重庆市
ipLocation.Remarks = $"{ipLocation.City}";
}
// 111.26.31.0|111.26.31.127|中国|0|吉林省|吉林市|移动
else
{
// 吉林省吉林市
ipLocation.Remarks = $"{ipLocation.Province}{ipLocation.City}";
}
}
// 220.246.0.0|220.246.255.255|中国|0|香港|0|电讯盈科
else if (!ipLocation.Country.IsNullOrWhiteSpace() && !ipLocation.Province.IsNullOrWhiteSpace())
{
// 中国香港
ipLocation.Remarks = $"{ipLocation.Country}{ipLocation.Province}";
}
// 220.247.4.0|220.247.31.255|日本|0|0|0|0
else
{
// 日本
ipLocation.Remarks = $"{ipLocation.Country}";
}
context.Location = ipLocation;
return Task.CompletedTask;
}
}

68
aspnet-core/framework/common/LINGYUN.Abp.IP2Region/LINGYUN/Abp/IP2Region/IP2RegionLocationInfoProvider.cs

@ -1,68 +0,0 @@
using IP2Region.Net.Abstractions;
using System;
using System.Threading.Tasks;
namespace LINGYUN.Abp.IP2Region;
public class IP2RegionLocationInfoProvider : IIpLocationInfoProvider
{
protected static readonly LocationInfo? _nullCache = null;
protected ISearcher Searcher { get; }
public IP2RegionLocationInfoProvider(ISearcher searcher)
{
Searcher = searcher;
}
public virtual Task<LocationInfo?> GetLocationInfoAsync(string ipAddress)
{
var region = Searcher.Search(ipAddress);
if (string.IsNullOrWhiteSpace(region))
{
return Task.FromResult(_nullCache);
}
var regions = region!.Split('|');
// | 0 | 1 | 2 |3| 4 | 5 | 6 |
// 39.128.0.0|39.128.31.255|中国|0|云南省|昆明市|移动
// regions:
// 中国 0 云南省 昆明市 移动
var locationInfo = new LocationInfo
{
Country = regions.Length >= 1 && !string.Equals(regions[0], "0") ? regions[0] : null,
Province = regions.Length >= 3 && !string.Equals(regions[2], "0") ? regions[2] : null,
City = regions.Length >= 4 && !string.Equals(regions[3], "0") ? regions[3] : null,
};
// 36.133.108.0|36.133.119.255|中国|0|重庆|重庆市|移动
if (!locationInfo.Province.IsNullOrWhiteSpace() && !locationInfo.City.IsNullOrWhiteSpace())
{
if (locationInfo.Province.Length < locationInfo.City.Length &&
locationInfo.City.StartsWith(locationInfo.Province, StringComparison.InvariantCultureIgnoreCase))
{
// 重庆市
locationInfo.Remarks = $"{locationInfo.City}";
}
// 111.26.31.0|111.26.31.127|中国|0|吉林省|吉林市|移动
else
{
// 吉林省吉林市
locationInfo.Remarks = $"{locationInfo.Province}{locationInfo.City}";
}
}
// 220.246.0.0|220.246.255.255|中国|0|香港|0|电讯盈科
else if (!locationInfo.Country.IsNullOrWhiteSpace() && !locationInfo.Province.IsNullOrWhiteSpace())
{
// 中国香港
locationInfo.Remarks = $"{locationInfo.Country}{locationInfo.Province}";
}
// 220.247.4.0|220.247.31.255|日本|0|0|0|0
else
{
// 日本
locationInfo.Remarks = $"{locationInfo.Country}";
}
return Task.FromResult<LocationInfo?>(locationInfo);
}
}

8
aspnet-core/framework/common/LINGYUN.Abp.IP2Region/LINGYUN/Abp/IP2Region/LocationInfo.cs

@ -1,8 +0,0 @@
namespace LINGYUN.Abp.IP2Region;
public class LocationInfo
{
public string? Country { get; set; }
public string? Province { get; set; }
public string? City { get; set; }
public string? Remarks { get; set; }
}
Loading…
Cancel
Save