Skip to content

自定义匹配器 (SPI)

CoSec 的策略系统通过两个 SPI(服务提供者接口)扩展点实现完全可扩展:ActionMatcherFactory 用于定义请求如何匹配操作,ConditionMatcherFactory 用于定义策略语句的附加条件。自定义匹配器通过 Java 的 ServiceLoader 和 Spring 的 ApplicationContext 自动发现。

扩展架构

mermaid
graph TD
    subgraph "SPI Discovery"
        A["Java ServiceLoader<br>(META-INF/services)"]
        B["Spring ApplicationContext<br>(bean discovery)"]
    end
    subgraph "Provider Registry"
        C["ActionMatcherFactoryProvider<br>(ConcurrentHashMap)"]
        D["ConditionMatcherFactoryProvider<br>(ConcurrentHashMap)"]
    end
    subgraph "Runtime"
        E["Policy Deserialization"]
        E --> F["ActionMatcherFactory.create(config)"]
        E --> G["ConditionMatcherFactory.create(config)"]
    end
    A --> C
    B --> C
    B --> D
    A --> D
    C --> F
    D --> G

    style A fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style B fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style C fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style D fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style E fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style F fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style G fill:#2d333b,stroke:#6d5dfc,color:#e6edf3

ActionMatcherFactory

用于创建 ActionMatcher 实例的工厂接口。每个工厂通过唯一的 type 字符串标识,该字符串在策略 JSON 中用于引用匹配器。

kotlin
interface ActionMatcherFactory {
    val type: String
    fun create(configuration: Configuration): ActionMatcher
}

内置操作匹配器

工厂类类型描述
AllActionMatcherFactoryall无条件匹配所有操作
PathActionMatcherFactorypath按 URL 路径模式和 HTTP 方法匹配
CompositeActionMatcherFactorycomposite使用 AND/OR 逻辑组合多个匹配器

ConditionMatcherFactory

用于创建 ConditionMatcher 实例的工厂接口。条件匹配器在操作匹配之外添加额外的约束条件。

kotlin
interface ConditionMatcherFactory {
    val type: String
    fun create(configuration: Configuration): ConditionMatcher
}

内置条件匹配器

类别匹配器描述
基于路径EqContainsStartsWithEndsWithInRegular将请求属性与值进行匹配
基于上下文AuthenticatedInRoleInTenant匹配安全上下文属性
速率限制速率限制匹配器强制执行请求速率限制
表达式OGNLSpEL计算自定义表达式

注册流程

步骤 1:Java ServiceLoader (META-INF/services)

对于非 Spring 上下文,工厂在类加载时通过 ServiceLoader 发现。

文件META-INF/services/me.ahoo.cosec.policy.action.ActionMatcherFactory

me.ahoo.cosec.policy.action.AllActionMatcherFactory
me.ahoo.cosec.policy.action.PathActionMatcherFactory
me.ahoo.cosec.policy.action.CompositeActionMatcherFactory

文件META-INF/services/me.ahoo.cosec.policy.condition.ConditionMatcherFactory

me.ahoo.cosec.policy.condition.AllConditionMatcherFactory
me.ahoo.cosec.policy.condition.authenticated.AuthenticatedConditionMatcherFactory
me.ahoo.cosec.policy.condition.eq.EqConditionMatcherFactory
...

步骤 2:提供者注册表

ActionMatcherFactoryProviderConditionMatcherFactoryProvider 单例维护一个包含所有已注册工厂的 ConcurrentHashMap

mermaid
sequenceDiagram
    autonumber
    participant SL as ServiceLoader
    participant Provider as ActionMatcherFactoryProvider
    participant Map as ConcurrentHashMap

    Note over Provider: Static init block
    Provider->>SL: load(ActionMatcherFactory::class.java)
    SL-->>Provider: Iterator of factories
    loop For each factory
        Provider->>Map: put(factory.type, factory)
    end
    Note over Provider: Factories now available via get() / getRequired()

步骤 3:Spring SmartLifecycle (MatcherFactoryRegister)

在 Spring 上下文中运行时,MatcherFactoryRegister 实现 SmartLifecycle,将所有 Spring 管理的工厂 Bean 注册到提供者单例。此操作在启动时运行,确保定义为 @Bean 的自定义工厂可用于策略评估。

kotlin
class MatcherFactoryRegister(
    private val applicationContext: ApplicationContext
) : SmartLifecycle {
    override fun start() {
        applicationContext.getBeansOfType<ConditionMatcherFactory>().values.forEach {
            ConditionMatcherFactoryProvider.register(it)
        }
        applicationContext.getBeansOfType<ActionMatcherFactory>().values.forEach {
            ActionMatcherFactoryProvider.register(it)
        }
    }
}
mermaid
graph TD
    A["Spring ApplicationContext"] --> B["MatcherFactoryRegister<br>(SmartLifecycle.start())"]
    B --> C["Get all ActionMatcherFactory beans"]
    B --> D["Get all ConditionMatcherFactory beans"]
    C --> E["ActionMatcherFactoryProvider.register()"]
    D --> F["ConditionMatcherFactoryProvider.register()"]

    style A fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style B fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style C fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style D fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style E fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style F fill:#2d333b,stroke:#6d5dfc,color:#e6edf3

创建自定义操作匹配器

步骤 1:实现匹配器

kotlin
class HttpMethodActionMatcher(private val method: String) : ActionMatcher {
    override fun match(request: Request): Boolean {
        return request.method.equals(method, ignoreCase = true)
    }
}

步骤 2:实现工厂

kotlin
class HttpMethodActionMatcherFactory : ActionMatcherFactory {
    override val type = "httpMethod"
    override fun create(configuration: Configuration): ActionMatcher {
        val method = configuration.getConfigValue("method", String::class.java)
        return HttpMethodActionMatcher(method)
    }
}

步骤 3:通过 META-INF/services 注册

文件META-INF/services/me.ahoo.cosec.policy.action.ActionMatcherFactory

com.example.HttpMethodActionMatcherFactory

步骤 4:在策略 JSON 中使用

json
{
  "effect": "ALLOW",
  "action": {
    "type": "httpMethod",
    "method": "GET"
  }
}

创建自定义条件匹配器

相同的模式适用于 ConditionMatcherFactory。实现 ConditionMatcher 接口,创建工厂,然后注册即可。

参考资料

相关页面

基于 Apache License 2.0 发布