菜单栏

如何在应用层获取客户端IP地址?-ABP Framework 问题解答#2305

@iEricLee 创建时间 : 2023-06-28 15:18:40 最后修改时间 : 2023-06-28 15:31:49

来自 ABP Framework 研习社(群号:726299208)群友 @JUYO 的提问:

abp_app_service_ip.jpg

在 ABP Framework 审计日志和安全日志中会记录客端IP地址,为了验证是不是框架本身Bug,查看生产环境数据库 AbpSecurityLogs 表中的记录:

abp_security_logs.png

其中 ClientIpAddress 列记录的IP地址是正常的。

接下来,对问题进行分析:

1. 客户端IP怎么在应用层获取?

IP地址信息保存在HTTP上下文的请求中,所以要获取IP地址信息首先要获取HTTP上下文 HttpContext

在 WebForms 和 ASP.NET MVC WEB应用程序中可以直接通过 HttpContextCurrent.Request 获取请求。

示例:在 ASP.NET MVC 中获取 IP 地址信息

var ip = HttpContext.Current.Request.UserHostAddress;

在 ASP.NET Core MVC WEB应用程序中以上方式不起作用,需要通过 IHttpContextAccessor 来获取HTTP上下文

ABP Framework 基于 .NE Core 构建,所以,在应用层获取客户端IP地址,只需要在应用服务类中的构造函数中注入接口 IHttpContextAccessor ,获取其实例。

示例:在应用服务中获取IP地址信息

using Microsoft.AspNetCore.Http;

public class IpAddressAppService{
    private readonly IHttpContextAccessor httpContextAccessor;
    public IpAddressAppService(IHttpContextAccessor httpContextAccessor)
    {
        this.httpContextAccessor = httpContextAccessor;
    }
    
    public string GetClientIpAddress()
    {
        return httpContextAccessor.HttpContext?.Connection.RemoteIpAddress.ToString();
    }
}

2. 为什么 IHttpContextAccessor 不可用?

在 .NET Core 中使用构造函数注入服务之前,需要先进行服务注册,否则无法获取服务实例。如果 IHttpContextAccessor 不可用,则说明并没有注册该服务。

最简单的方式,直接手动注册。通常是在启动程序模块定义类中注册,这样除了在应用服务类使用之外,还可以在控制器类中使用。

实例:在启动程序模块类中注册 IHttpContextAccessor 接口

public class AppModule : AbpModule
{
    public override void ConfigureServices(ServiceConfigurationContext context)
    {
        //...
        context.Services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
    }
}

通过以上设置,就可以在构造函数中正常获取 IHttpContextAccessor 服务了。

3. 深入分析

ABP Framework 和 ASP.NET Core 整合

正常情况下,在 ABP Framework 中不需要手动注册 IHttpContextAccessor ,因为在 Volo.Abp.AspNetCore 模块定义类中进行了服务注册:

private static void AddAspNetServices(IServiceCollection services)
{
    services.AddHttpContextAccessor();
}

AddHttpContextAccessor 是 .NET Core 程序集 Microsoft.AspNetCore.Http.dll 中为 IServiceCollection 提供的一个扩展方法,该扩展方法用来注册 IHttpContextAccessor 服务,查看该方法源码,可以看到其内部实现也是使用上述手动注册代码:

public static IServiceCollection AddHttpContextAccessor(this IServiceCollection services)
{
    ArgumentNullException.ThrowIfNull(services);

    services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
    return services;
}

所以,如果使用 ABP Framework 则只需要对 Volo.Abp.AspNetCore 模块直接或间接依赖即可。

如果在应用服务层中不能正常使用 IHttpContextAccessor ,请检查在应用程序模块类中是否已经添加对 Volo.Abp.AspNetCore 模块的依赖。

WEB客户端信息提供程序

在 ABP Framework 中定义了 IWebClientInfoProvider 接口,提供获取 IP地址属性 ClientIpAddress 以及 浏览器信息属性 BrowserInfo

接口定义和实现代码位于 Volo.Abp.AspNetCore 程序集,默认实现为HttpContextWebClientInfoProvider,该实现内部也是通过 IHttpContextAccessor 获取IP地址。

因此,在需要获取客户端IP地址浏览器信息 应该统一使用 IWebClientInfoProvider 接口。

同样,在 ABP Framework 框架中,审计日志和安全日志等功能统一采用该接口获取IP地址信息:

  • 审计日志提供程序 AspNetCoreAuditLogContributor
  • 安全日志管理器 AspNetCoreSecurityLogManager

在本文档中
Copyright © 2024 知识乐 湘ICP备2022022129号-1