You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于IP地址保护API Platform与Symfony构建的API

问题原因与解决方案

核心原因

  1. 路径正则匹配错误
    你使用的^/*正则无法正确匹配/articles/stocks这类API端点,它仅能匹配空路径、单斜杠或多斜杠开头的路径,而非所有以/开头的子路径,导致IP限制规则未覆盖到实际端点。

  2. IP限制逻辑漏洞
    原配置中IS_AUTHENTICATED_ANONYMOUSLY是所有未认证用户默认拥有的角色,这条规则仅允许指定IP的用户匿名访问,但未对非指定IP的请求做拒绝处理。如果防火墙开启了anonymous: true,非指定IP的用户仍能绕过限制访问端点。

  3. 自定义角色未被正确授予
    使用ROLE_IP_USER时,你没有通过事件监听器或其他机制给指定IP的请求自动添加该角色,导致is_granted('ROLE_IP_USER')校验无法生效,而防火墙的匿名访问规则优先级更高,使得端点仍处于开放状态。


解决方案

方案1:直接修正access_control规则(快速生效)

通过规则顺序和IP限制,直接拒绝非指定IP的请求:

# config/packages/security.yaml
access_control:
    # 允许首页文档公共访问
    - { path: ^/$, roles: PUBLIC_ACCESS }
    # 允许指定IP的用户匿名访问所有API端点
    - { path: ^/.*, roles: IS_AUTHENTICATED_ANONYMOUSLY, ips: [109.239.112.139, 45.10.152.49] }
    # 拒绝所有非指定IP的用户访问API端点
    - { path: ^/.*, roles: ROLE_NO_ACCESS }

注:ROLE_NO_ACCESS是一个不存在的角色,确保所有用户都不具备,从而触发访问拒绝。

方案2:自定义角色+事件监听器(更灵活)

  1. 创建IP角色监听器
    给指定IP的请求自动添加ROLE_IP_USER角色:
// src/EventListener/IpRoleListener.php
namespace App\EventListener;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Role\Role;

class IpRoleListener implements EventSubscriberInterface
{
    private $tokenStorage;
    private $allowedIps;

    public function __construct(TokenStorageInterface $tokenStorage, array $allowedIps)
    {
        $this->tokenStorage = $tokenStorage;
        $this->allowedIps = $allowedIps;
    }

    public static function getSubscribedEvents()
    {
        return [RequestEvent::class => 'onKernelRequest'];
    }

    public function onKernelRequest(RequestEvent $event)
    {
        if (!$event->isMainRequest()) return;

        $clientIp = $event->getRequest()->getClientIp();
        if (!in_array($clientIp, $this->allowedIps)) return;

        $token = $this->tokenStorage->getToken();
        if (!$token) return;

        // 给当前请求的用户添加ROLE_IP_USER角色
        $roles = $token->getRoles();
        $roles[] = new Role('ROLE_IP_USER');
        $newToken = clone $token;
        $newToken->setRoles($roles);
        $this->tokenStorage->setToken($newToken);
    }
}
  1. 配置监听器服务
# config/services.yaml
services:
    App\EventListener\IpRoleListener:
        arguments:
            $allowedIps: ['109.239.112.139', '45.10.152.49']
        tags: [{ name: kernel.event_subscriber }]
  1. 更新security配置
# config/packages/security.yaml
access_control:
    - { path: ^/$, roles: PUBLIC_ACCESS }
    - { path: ^/.*, roles: ROLE_IP_USER }
  1. 保留ApiResource注解
#[ApiResource(
    operations: [
        new Get(),
        new GetCollection(),
    ],
    order: ['createdAt' => 'DESC'],
    paginationClientItemsPerPage: true,
    paginationItemsPerPage: 30,
    security: 'is_granted(\'ROLE_IP_USER\')'
)]

额外注意事项

  • 如果应用部署在反向代理(如Nginx、Apache)后,需要在config/packages/framework.yaml中配置trusted_proxies,确保Symfony能获取真实客户端IP:
# config/packages/framework.yaml
framework:
    trusted_proxies: ['127.0.0.1', '你的代理服务器IP']
    trusted_headers: ['x-forwarded-for', 'x-forwarded-host', 'x-forwarded-proto']

内容的提问来源于stack exchange,提问作者Cedric Petetin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 04:56:03