根据客户端IP地址授权应用服务

Authorize application service based on client IP address

我们在未经任何许可的情况下实施了一些应用程序服务方法。我们如何实现基于客户端IP地址的授权来执行方法?

例如,这是GetParsedData方法:

public GetParsedDataOutput GetParsedData(GetParsedDataInput input)
{
    return _cacheManager.GetCache(nameof(GetData)).Get(input.ToString(), () => gpd(input)) as GetParsedDataOutput;
}

我们如何通过IP地址检查用户权限?假设 IP 地址为 192.168.5.2 的客户端被授予执行此方法的权限。

您可以注入 IClientInfoProvider 以获得 ClientIpAddress

授权经过身份验证的用户

覆盖 PermissionChecker 中的 IsGrantedAsync:

public override async Task<bool> IsGrantedAsync(long userId, string permissionName)
{
    if (permissionName == MyClientIpAddressPermissionName)
    {
        return Task.Run(() => { return _clientInfoProvider.ClientIpAddress == "192.168.5.2"; });
    }

    return await base.IsGrantedAsync(userId, permissionName);
}

用法:

[AbpAuthorize(MyClientIpAddressPermissionName)]
public GetParsedDataOutput GetParsedData(GetParsedDataInput input)
{
    // ...
}

授权匿名用户

由于 AbpAuthorize 需要用户,您应该使用自定义 (i) 属性、(ii) 拦截器和 (iii) 拦截器注册器。

(i) 属性:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class ClientIpAuthorizeAttribute : Attribute
{
    public string AllowedIpAddress { get; set; }
}

(ii) 拦截器:

internal class ClientIpAuthorizationInterceptor : IInterceptor
{
    private readonly IClientInfoProvider _clientInfoProvider;

    public ClientIpAuthorizationInterceptor(IClientInfoProvider clientInfoProvider)
    {
        _clientInfoProvider = clientInfoProvider;
    }

    public void Intercept(IInvocation invocation)
    {
        var methodInfo = invocation.MethodInvocationTarget;
        var clientIpAuthorizeAttribute = methodInfo.GetCustomAttributes(true).OfType<ClientIpAuthorizeAttribute>().FirstOrDefault()
                        ?? methodInfo.DeclaringType.GetCustomAttributes(true).OfType<ClientIpAuthorizeAttribute>().FirstOrDefault();

        if (clientIpAuthorizeAttribute != null &&
            clientIpAuthorizeAttribute.AllowedIpAddress != _clientInfoProvider.ClientIpAddress)
        {
            throw new AbpAuthorizationException();
        }

        invocation.Proceed();
    }
}

(iii) 拦截器注册器:

internal static class ClientIpAuthorizationInterceptorRegistrar
{
    public static void Initialize(IIocManager iocManager)
    {
        iocManager.IocContainer.Kernel.ComponentRegistered += (key, handler) =>
        {
            if (ShouldIntercept(handler.ComponentModel.Implementation))
            {
                handler.ComponentModel.Interceptors.Add(new InterceptorReference(typeof(ClientIpAuthorizationInterceptor)));
            }
        };
    }

    private static bool ShouldIntercept(Type type)
    {
        if (type.GetTypeInfo().IsDefined(typeof(ClientIpAuthorizeAttribute), true))
        {
            return true;
        }

        if (type.GetMethods().Any(m => m.IsDefined(typeof(ClientIpAuthorizeAttribute), true)))
        {
            return true;
        }

        return false;
    }
}

在您的应用程序模块中初始化注册器:

public override void PreInitialize()
{
    ClientIpAuthorizationInterceptorRegistrar.Initialize(IocManager);
}

用法:

[ClientIpAuthorize(AllowedIpAddress = "192.168.5.2")]
public GetParsedDataOutput GetParsedData(GetParsedDataInput input)
{
    // ...
}

您应该能够自己将其扩展到 allow/disallow 个多个 IP 地址。

要回退经过身份验证的用户的权限名称,请在属性中将权限名称添加为 string 属性。然后在拦截器中注入IAbpSessionIPermissionChecker调用IsGrantedAsync方法

您可以为 IApplicationService 编写自己的注入器服务。并且在应用程序服务方法执行之前,您可以进行预检查。

看看如何实现注入 https://aspnetboilerplate.com/Pages/Documents/Dependency-Injection