feat(security): 实现 API密钥安全控制并重构授权模块

- 新增 API 密钥安全核心配置和自动配置
- 重构授权模块,支持动态授权管理
- 更新权限解析器、授权策略和访问管理器的实现
- 新增 API 密钥认证过滤器和异常处理器
- 改进安全过滤链的构建和管理
This commit is contained in:
gewuyou 2025-06-25 23:07:54 +08:00
parent 5f3ae7a5cd
commit ec326e5a1d
40 changed files with 860 additions and 101 deletions

View File

@ -1,14 +0,0 @@
package com.gewuyou.forgeboot.security.authorize.api.config
import org.springframework.boot.context.properties.ConfigurationProperties
/**
*security 授权属性
*
* @since 2025-06-15 19:26:20
* @author gewuyou
*/
@ConfigurationProperties(prefix = "forgeboot.security.authorize")
class SecurityAuthorizeProperties {
var defaultExceptionResponse: String = "Sorry, you don't have access to the resource!"
}

View File

@ -1,4 +1,4 @@
package com.gewuyou.forgeboot.security.authorize.api.annotations package com.gewuyou.forgeboot.security.authorize.api.core.annotations
/** /**
* 权限校验注解用于标记需要特定权限才能访问的方法 * 权限校验注解用于标记需要特定权限才能访问的方法

View File

@ -0,0 +1,42 @@
package com.gewuyou.forgeboot.security.authorize.api.core.config
import org.springframework.boot.context.properties.ConfigurationProperties
/**
* Security 授权配置属性类用于定义安全相关的可配置项
*
* 该类通过@ConfigurationProperties绑定配置前缀"forgeboot.security.authorize"
* 提供了默认异常响应消息和API密钥启用状态的配置支持
*
* @property defaultExceptionResponse 当访问被拒绝时返回的默认提示信息
* @property apiKey API密钥相关配置属性对象
*
* @since 2025-06-15 19:26:20
* @author gewuyou
*/
@ConfigurationProperties(prefix = "forgeboot.security.authorize")
class SecurityAuthorizeProperties {
/**
* 默认的访问拒绝响应消息用于在未授权访问时返回给客户端
*/
var defaultExceptionResponse: String = "Sorry, you don't have access to the resource!"
/**
* API密钥相关配置属性对象包含是否启用API密钥验证的开关
*/
var apiKey: ApiKeyProperties = ApiKeyProperties()
/**
* API密钥功能的子配置类用于控制API密钥验证的启用状态
*
* @property enabled 是否启用API密钥验证功能默认为false
*/
class ApiKeyProperties {
/**
* 控制是否启用API密钥验证功能默认值为false
*/
var enabled: Boolean = false
var pathPatterns: List<String> = listOf("/api/**")
var useAuthorizationManager: Boolean = true
}
}

View File

@ -1,4 +1,4 @@
package com.gewuyou.forgeboot.security.authorize.api.manager package com.gewuyou.forgeboot.security.authorize.api.core.manager
import org.springframework.security.core.Authentication import org.springframework.security.core.Authentication
@ -17,4 +17,4 @@ fun interface AccessManager {
* @return Boolean 返回是否有权限的布尔值 * @return Boolean 返回是否有权限的布尔值
*/ */
fun hasPermission(authentication: Authentication, permission: String): Boolean fun hasPermission(authentication: Authentication, permission: String): Boolean
} }

View File

@ -1,4 +1,4 @@
package com.gewuyou.forgeboot.security.authorize.api.provider package com.gewuyou.forgeboot.security.authorize.api.core.provider
import org.springframework.security.core.Authentication import org.springframework.security.core.Authentication

View File

@ -1,4 +1,4 @@
package com.gewuyou.forgeboot.security.authorize.api.resolver package com.gewuyou.forgeboot.security.authorize.api.core.resolver
/** /**
* 权限解析程序接口用于将请求路径和HTTP方法转换为具体的权限标识符 * 权限解析程序接口用于将请求路径和HTTP方法转换为具体的权限标识符

View File

@ -0,0 +1,13 @@
package com.gewuyou.forgeboot.security.authorize.api.core.service
import com.gewuyou.forgeboot.security.core.authorize.entities.ApiKeyPrincipal
/**
*API 密钥服务
*
* @since 2025-06-25 13:10:38
* @author gewuyou
*/
fun interface ApiKeyService {
fun validate(apiKey: String): ApiKeyPrincipal // 负责验证与解析
}

View File

@ -1,6 +1,6 @@
package com.gewuyou.forgeboot.security.authorize.api.strategy package com.gewuyou.forgeboot.security.authorize.api.core.strategy
import com.gewuyou.forgeboot.security.authorize.api.provider.PermissionProvider import com.gewuyou.forgeboot.security.authorize.api.core.provider.PermissionProvider
import org.springframework.security.core.Authentication import org.springframework.security.core.Authentication
/** /**

View File

@ -1,16 +1,16 @@
package com.gewuyou.forgeboot.security.authorize.api.manager package com.gewuyou.forgeboot.security.authorize.api.servlet.manager
import org.springframework.security.authorization.AuthorizationManager import org.springframework.security.authorization.AuthorizationManager
/** /**
* 动态授权管理器接口 * 动态授权管理器接口
* *
* 该接口用于处理请求级别的动态权限控制逻辑基于Spring Security的AuthorizationManager接口进行扩展 * 该接口用于处理请求级别的动态权限控制逻辑基于Spring Security的AuthorizationManager接口进行扩展
* 通过泛型类型T定义需要处理的授权上下文类型例如Web请求或方法调用等 * 通过泛型类型T定义需要处理的授权上下文类型例如Web请求或方法调用等
* *
* @param <T> 授权操作涉及的具体上下文类型如RequestAuthorizationContext或其他自定义上下文对象 * @param <T> 授权操作涉及的具体上下文类型如RequestAuthorizationContext或其他自定义上下文对象
* *
* @since 2025-06-24 15:52:01 * @since 2025-06-24 15:52:01
* @author gewuyou * @author gewuyou
*/ */
interface DynamicAuthorizationManager<T> : AuthorizationManager<T> interface DynamicAuthorizationManager<T> : AuthorizationManager<T>

View File

@ -1,4 +1,4 @@
package com.gewuyou.forgeboot.security.authorize.api.manager package com.gewuyou.forgeboot.security.authorize.api.webflux.manager
import org.springframework.security.authorization.ReactiveAuthorizationManager import org.springframework.security.authorization.ReactiveAuthorizationManager

View File

@ -1,6 +1,6 @@
package com.gewuyou.forgeboot.security.authorize.autoconfigure package com.gewuyou.forgeboot.security.authorize.autoconfigure
import com.gewuyou.forgeboot.security.authorize.api.config.SecurityAuthorizeProperties import com.gewuyou.forgeboot.security.authorize.api.core.config.SecurityAuthorizeProperties
import org.springframework.boot.context.properties.EnableConfigurationProperties import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.context.annotation.Configuration import org.springframework.context.annotation.Configuration

View File

@ -0,0 +1,58 @@
package com.gewuyou.forgeboot.security.authorize.autoconfigure.core
import com.gewuyou.forgeboot.security.authorize.api.core.service.ApiKeyService
import com.gewuyou.forgeboot.security.authorize.impl.core.provider.ApiKeyAuthenticationProvider
import com.gewuyou.forgeboot.security.core.authorize.entities.ApiKeyPrincipal
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.security.authentication.AuthenticationProvider
/**
* API 密钥安全核心自动配置类
*
* 该配置类用于注册与 API 密钥相关的 Bean确保在 Spring 容器中存在必要的服务和认证提供者
* 主要作用包括
* - 提供默认的 ApiKeyService Bean未实现时
* - 提供 ApiKeyAuthenticationProvider Bean 以支持基于 API 密钥的身份验证
*
* @since 2025-06-25 15:49:50
* @author gewuyou
*/
@Configuration(proxyBeanMethods = false)
class ApiKeySecurityCoreAutoConfiguration {
/**
* 提供一个默认的 ApiKeyService Bean 实现
*
* 如果容器中不存在 ApiKeyService 的实现则会使用此默认 Bean
* 默认实现的 validate 方法始终抛出 UnsupportedOperationException
* 提示用户需要自定义并注册自己的 ApiKeyService 实现
*
* @return 返回一个未实现的 ApiKeyService 对象
*/
@Bean
@ConditionalOnMissingBean
fun apiKeyService(): ApiKeyService {
return object : ApiKeyService {
override fun validate(apiKey: String): ApiKeyPrincipal {
throw UnsupportedOperationException("请提供 ApiKeyService 实现")
}
}
}
/**
* 提供一个用于认证的 ApiKeyAuthenticationProvider Bean
*
* 如果容器中尚不存在同名 Bean则创建并返回 ApiKeyAuthenticationProvider 实例
* Provider 使用传入的 apiKeyService 来处理具体的 API 密钥验证逻辑
*
* @param apiKeyService 用于处理 API 密钥逻辑的服务实现
* @return AuthenticationProvider 的具体实现对象
*/
@Bean("apiKeyAuthenticationProvider")
@ConditionalOnMissingBean
fun apiKeyAuthenticationProvider(apiKeyService: ApiKeyService): AuthenticationProvider {
return ApiKeyAuthenticationProvider(apiKeyService)
}
}

View File

@ -1,12 +1,12 @@
package com.gewuyou.forgeboot.security.authorize.autoconfigure package com.gewuyou.forgeboot.security.authorize.autoconfigure.core
import com.gewuyou.forgeboot.security.authorize.api.manager.AccessManager import com.gewuyou.forgeboot.security.authorize.api.core.manager.AccessManager
import com.gewuyou.forgeboot.security.authorize.api.provider.PermissionProvider import com.gewuyou.forgeboot.security.authorize.api.core.provider.PermissionProvider
import com.gewuyou.forgeboot.security.authorize.api.resolver.PermissionResolver import com.gewuyou.forgeboot.security.authorize.api.core.resolver.PermissionResolver
import com.gewuyou.forgeboot.security.authorize.api.strategy.AuthorizationStrategy import com.gewuyou.forgeboot.security.authorize.api.core.strategy.AuthorizationStrategy
import com.gewuyou.forgeboot.security.authorize.impl.manager.DefaultAccessManager import com.gewuyou.forgeboot.security.authorize.impl.core.manager.DefaultAccessManager
import com.gewuyou.forgeboot.security.authorize.impl.resolver.DefaultPermissionResolver import com.gewuyou.forgeboot.security.authorize.impl.core.resolver.DefaultPermissionResolver
import com.gewuyou.forgeboot.security.authorize.impl.strategy.AnyMatchStrategy import com.gewuyou.forgeboot.security.authorize.impl.core.strategy.AnyMatchStrategy
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean import org.springframework.boot.autoconfigure.condition.ConditionalOnBean
import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration import org.springframework.context.annotation.Configuration
@ -20,7 +20,7 @@ import org.springframework.context.annotation.Configuration
* @since 2025-06-24 16:49:37 * @since 2025-06-24 16:49:37
* @author gewuyou * @author gewuyou
*/ */
@Configuration @Configuration(proxyBeanMethods = false)
class ForgeSecurityAuthorizeCoreConfiguration { class ForgeSecurityAuthorizeCoreConfiguration {
/** /**
* 权限解析器Bean用于将权限表达式解析为具体的权限对象 * 权限解析器Bean用于将权限表达式解析为具体的权限对象

View File

@ -0,0 +1,127 @@
package com.gewuyou.forgeboot.security.authorize.autoconfigure.servlet
import com.gewuyou.forgeboot.security.authorize.api.core.config.SecurityAuthorizeProperties
import com.gewuyou.forgeboot.security.authorize.impl.servlet.customizer.ApiKeyHttpSecurityCustomizer
import com.gewuyou.forgeboot.security.authorize.impl.servlet.filter.ApiKeyAuthenticationFilter
import com.gewuyou.forgeboot.security.core.common.constants.SecurityConstants
import com.gewuyou.forgeboot.security.core.common.customizer.HttpSecurityCustomizer
import com.gewuyou.forgeboot.security.core.common.registrar.SecurityFilterChainRegistrar
import jakarta.servlet.Filter
import org.springframework.beans.factory.annotation.Qualifier
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.security.authentication.AuthenticationManager
import org.springframework.security.authorization.AuthorizationManager
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.web.SecurityFilterChain
import org.springframework.security.web.access.intercept.RequestAuthorizationContext
import org.springframework.security.web.util.matcher.AntPathRequestMatcher
import org.springframework.security.web.util.matcher.OrRequestMatcher
/**
* API 密钥安全自动配置类用于在 Servlet Web 应用中自动装配与 API 密钥相关的安全组件
*
* 此配置仅在以下条件下生效
* 1. 应用类型为 Servlet
* 2. 配置项 "forgeboot.security.authorize.api-key.enabled" true
*
* @property securityAuthorizeProperties 安全授权配置属性用于获取 API 密钥相关路径等信息
* @since 2025-06-25 13:41:56
* @author gewuyou
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@ConditionalOnProperty(
prefix = "forgeboot.security.authorize.api-key",
name = ["enabled"],
havingValue = "true",
matchIfMissing = false
)
class ServletApiKeySecurityAutoConfiguration(
private val securityAuthorizeProperties: SecurityAuthorizeProperties,
) {
/**
* 创建 API 密钥认证过滤器 Bean
*
* 该方法在 Spring 容器中尚不存在同名 Bean 的情况下
* 构建一个使用指定认证管理器的 ApiKeyAuthenticationFilter 实例
*
* @param authenticationManager 认证管理器用于执行认证逻辑
* @return 返回构建完成的 ApiKeyAuthenticationFilter 实例
*/
@Bean
@ConditionalOnMissingBean(name = ["apiKeyAuthenticationFilter"])
fun apiKeyAuthenticationFilter(
authenticationManager: AuthenticationManager,
): Filter {
return ApiKeyAuthenticationFilter(authenticationManager)
}
/**
* 提供一个用于自定义 HTTP 安全配置的 API 密钥安全自定义器 Bean
*
* 如果容器中尚不存在同名 Bean则创建并返回 ApiKeyHttpSecurityCustomizer 实例
* 此自定义器将注入的认证提供者和过滤器用于构建定制化的安全配置
*
* @param apiKeyAuthenticationProvider 注入已配置的认证提供者用于安全链构建
* @param apiKeyAuthenticationFilter 注入已配置的认证过滤器用于请求处理
* @return 返回 HttpSecurityCustomizer 的具体实现对象
*/
@Bean
@ConditionalOnMissingBean
fun apiKeyHttpSecurityCustomizer(
@Qualifier("apiKeyAuthenticationFilter")
apiKeyAuthenticationFilter: Filter,
): HttpSecurityCustomizer {
return ApiKeyHttpSecurityCustomizer(apiKeyAuthenticationFilter)
}
/**
* 创建默认的安全过滤链适用于 Servlet 编程模型
*
* 此方法基于配置的路径模式构建一个复合请求匹配器并通过注册器创建对应的安全过滤链
* 过滤链根据配置决定是否使用授权管理器进行访问控制
*
* @param registrar 安全过滤链注册器用于构建和管理过滤链
* @param http Spring Security HttpSecurity 配置对象
* @param authorizeManager 授权管理器用于在启用授权管理时定义访问策略
* @return 构建完成的安全过滤链实例
*/
@Bean(name = ["defaultApiKeySecurityFilterChain"])
fun defaultApiKeySecurityFilterChain(
registrar: SecurityFilterChainRegistrar,
http: HttpSecurity,
authorizeManager: AuthorizationManager<RequestAuthorizationContext>
): SecurityFilterChain {
// 从配置中获取 API 密钥适用的路径模式(如:["/api/**", "/open/**"]
val patterns = securityAuthorizeProperties.apiKey.pathPatterns
// 将每个路径模式转换为 AntPathRequestMatcher 实例
val matchers = patterns.map { AntPathRequestMatcher(it) }
// 使用 OrRequestMatcher 组合所有路径匹配规则,实现多路径匹配支持
val combinedMatcher = OrRequestMatcher(matchers)
// 调用注册器构建安全链,指定链 ID、HttpSecurity 对象和请求匹配器
return registrar.buildChain(
SecurityConstants.API_KEY_CHAIN_ID,
http,
combinedMatcher
) { config ->
if (securityAuthorizeProperties.apiKey.useAuthorizationManager) {
// 启用授权管理器时,配置请求通过指定的 authorizeManager 进行访问控制
config.authorizeHttpRequests {
it.anyRequest().access(authorizeManager)
}
} else {
// 禁用授权管理器时,要求所有请求必须经过身份验证
config.authorizeHttpRequests {
it.anyRequest().authenticated()
}
}
}
}
}

View File

@ -1,19 +1,24 @@
package com.gewuyou.forgeboot.security.authorize.autoconfigure package com.gewuyou.forgeboot.security.authorize.autoconfigure.servlet
import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.ObjectMapper
import com.gewuyou.forgeboot.security.authorize.api.config.SecurityAuthorizeProperties import com.gewuyou.forgeboot.security.authorize.api.core.config.SecurityAuthorizeProperties
import com.gewuyou.forgeboot.security.authorize.api.manager.AccessManager import com.gewuyou.forgeboot.security.authorize.api.core.manager.AccessManager
import com.gewuyou.forgeboot.security.authorize.api.resolver.PermissionResolver import com.gewuyou.forgeboot.security.authorize.api.core.resolver.PermissionResolver
import com.gewuyou.forgeboot.security.authorize.impl.adapter.DynamicAuthorizationManagerAdapter import com.gewuyou.forgeboot.security.authorize.impl.servlet.adapter.DynamicAuthorizationManagerAdapter
import com.gewuyou.forgeboot.security.authorize.impl.builder.StatelessSecurityFilterChainRegistrar import com.gewuyou.forgeboot.security.authorize.impl.servlet.handler.AuthorizationExceptionHandler
import com.gewuyou.forgeboot.security.authorize.impl.handler.AuthorizationExceptionHandler import com.gewuyou.forgeboot.security.authorize.impl.servlet.registrar.StatelessSecurityFilterChainRegistrar
import com.gewuyou.forgeboot.security.core.common.builder.SecurityFilterChainRegistrar import com.gewuyou.forgeboot.security.core.common.constants.SecurityConstants
import com.gewuyou.forgeboot.security.core.common.customizer.HttpSecurityCustomizer import com.gewuyou.forgeboot.security.core.common.customizer.HttpSecurityCustomizer
import com.gewuyou.forgeboot.security.core.common.registrar.SecurityFilterChainRegistrar
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean import org.springframework.boot.autoconfigure.condition.ConditionalOnBean
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass import org.springframework.boot.autoconfigure.condition.ConditionalOnClass
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication
import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.Primary
import org.springframework.security.authentication.AuthenticationManager
import org.springframework.security.authentication.AuthenticationProvider
import org.springframework.security.authentication.ProviderManager
import org.springframework.security.authorization.AuthorizationManager import org.springframework.security.authorization.AuthorizationManager
import org.springframework.security.config.annotation.web.builders.HttpSecurity import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.web.SecurityFilterChain import org.springframework.security.web.SecurityFilterChain
@ -28,11 +33,26 @@ import org.springframework.security.web.util.matcher.AnyRequestMatcher
* @author gewuyou * @author gewuyou
*/ */
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(name = ["spring.main.web-application-type"], havingValue = "servlet", matchIfMissing = true) @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
class ServletAuthorizeSecurityConfiguration( class ServletAuthorizeSecurityConfiguration(
private val accessManager: AccessManager, private val accessManager: AccessManager,
private val permissionResolver: PermissionResolver, private val permissionResolver: PermissionResolver,
) { ) {
/**
* 创建并返回一个认证管理器
*
* 初始化一个基于提供的认证提供者的认证管理器用于支持多种认证方式
*
* @param authenticationProviders 所有可用的认证提供者列表
* @return 返回初始化好的 AuthenticationManager 实例具体实现为 ProviderManager
*/
@Bean
@Primary
@ConditionalOnBean
fun authenticationManager(
authenticationProviders: List<AuthenticationProvider>,
): AuthenticationManager = ProviderManager(authenticationProviders)
/** /**
* 创建默认的安全过滤链适用于 Servlet 编程模型 * 创建默认的安全过滤链适用于 Servlet 编程模型
* *
@ -42,13 +62,13 @@ class ServletAuthorizeSecurityConfiguration(
* @throws Exception 构建过程中可能抛出的异常 * @throws Exception 构建过程中可能抛出的异常
*/ */
@Bean(name = ["defaultSecurityFilterChain"]) @Bean(name = ["defaultSecurityFilterChain"])
@ConditionalOnBean(SecurityFilterChainRegistrar::class) @ConditionalOnBean
@Throws(Exception::class) @Throws(Exception::class)
fun defaultSecurityFilterChain( fun defaultSecurityFilterChain(
registrar: SecurityFilterChainRegistrar, registrar: SecurityFilterChainRegistrar,
http: HttpSecurity, http: HttpSecurity,
): SecurityFilterChain = registrar.buildChain( ): SecurityFilterChain = registrar.buildChain(
"default", SecurityConstants.DEFAULT_CHAIN_ID,
http, http,
AnyRequestMatcher.INSTANCE AnyRequestMatcher.INSTANCE
) { config -> ) { config ->

View File

@ -0,0 +1,133 @@
package com.gewuyou.forgeboot.security.authorize.autoconfigure.webflux
import com.gewuyou.forgeboot.security.authorize.api.core.config.SecurityAuthorizeProperties
import com.gewuyou.forgeboot.security.authorize.impl.webflux.customizer.ApiKeyServerHttpSecurityCustomizer
import com.gewuyou.forgeboot.security.authorize.impl.webflux.filter.ApiKeyReactiveAuthenticationFilter
import com.gewuyou.forgeboot.security.core.common.constants.SecurityConstants
import com.gewuyou.forgeboot.security.core.common.customizer.ServerHttpSecurityCustomizer
import com.gewuyou.forgeboot.security.core.common.registrar.SecurityWebFilterChainRegistrar
import org.springframework.beans.factory.annotation.Qualifier
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.security.authentication.ReactiveAuthenticationManager
import org.springframework.security.authorization.ReactiveAuthorizationManager
import org.springframework.security.config.web.server.ServerHttpSecurity
import org.springframework.security.web.server.SecurityWebFilterChain
import org.springframework.security.web.server.authorization.AuthorizationContext
import org.springframework.security.web.server.util.matcher.PathPatternParserServerWebExchangeMatcher
import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher
import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatchers
import org.springframework.web.server.WebFilter
/**
* 反应式 API 密钥安全自动配置
*
* 该配置类负责在 WebFlux 环境下启用 API Key 认证机制
* 仅在满足以下条件时生效
* - 应用类型为 REACTIVE反应式应用
* - 配置项 `forgeboot.security.authorize.api-key.enabled` 被设置为 true
*
* @property securityAuthorizeProperties 安全授权配置属性用于获取 API Key 的路径匹配规则等信息
* @since 2025-06-25 21:04:37
* @author gewuyou
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
@ConditionalOnProperty(
prefix = "forgeboot.security.authorize.api-key",
name = ["enabled"],
havingValue = "true",
matchIfMissing = false
)
class ReactiveApiKeySecurityAutoConfiguration(
private val securityAuthorizeProperties: SecurityAuthorizeProperties
) {
/**
* 创建 API Key 反应式认证过滤器 Bean
*
* 该过滤器用于处理传入请求的 API Key 认证逻辑
* 如果容器中尚未定义名为 "apiKeyReactiveAuthenticationFilter" Bean则创建此 Bean
*
* @param reactiveAuthenticationManager 反应式认证管理器用于执行认证操作
* @return 构建完成的 WebFilter 实例
*/
@Bean
@ConditionalOnMissingBean(name = ["apiKeyReactiveAuthenticationFilter"])
fun apiKeyAuthenticationFilter(
reactiveAuthenticationManager: ReactiveAuthenticationManager
): WebFilter {
return ApiKeyReactiveAuthenticationFilter(reactiveAuthenticationManager)
}
/**
* 创建并注册 ServerHttpSecurityCustomizer Bean用于定制 API Key 安全配置
*
* 此方法定义了一个用于构建 Spring Security 过滤器链时插入 API Key 认证逻辑的自定义器
* 仅当容器中尚未存在相同类型的 Bean 才会创建此 Bean
*
* @param apiKeyReactiveAuthenticationFilter 使用指定名称从 Spring 容器中注入的 API Key 反应式认证过滤器 Bean
* 该过滤器负责处理实际的 API Key 认证逻辑
*
* @return 构建完成的 ApiKeyServerHttpSecurityCustomizer 实例用于在安全配置中添加 API Key 相关逻辑
*/
@Bean
@ConditionalOnMissingBean
fun apiKeyServerHttpSecurityCustomizer(
@Qualifier("apiKeyReactiveAuthenticationFilter")
apiKeyReactiveAuthenticationFilter: WebFilter,
): ServerHttpSecurityCustomizer {
return ApiKeyServerHttpSecurityCustomizer(apiKeyReactiveAuthenticationFilter)
}
/**
* 创建并注册基于 API Key 认证的 WebFlux 安全过滤器链
*
* 该方法利用 SecurityWebFilterChainRegistrar 注册一个具有路径匹配规则的安全过滤器链
* 仅对符合配置中指定路径模式的请求生效并要求通过 API Key 认证
*
* @param registrar 用于注册和构建安全过滤器链的核心工具类负责链的组装过程
* @param http Spring Security 提供的 ServerHttpSecurity 实例用于构建 HTTP 安全配置
* @param reactiveAuthorizationManager 反应式授权管理器用于在使用授权管理逻辑时提供访问控制
* @return 构建完成的 SecurityWebFilterChain 实例表示定义好的安全过滤器链
*
* 重要逻辑说明
* 1. patterns: 从配置中获取 API Key 的路径匹配规则
* 2. matchers: 将每个路径转换为 ServerWebExchangeMatcher 实例
* 3. combinedMatcher: 综合所有 matcher生成复合的匹配规则
* 4. buildChain: 利用 registrar 构建过滤器链并根据 useAuthorizationManager 配置决定采用何种认证方式
* - 若启用 authorizationManager则通过 access 方法设置自定义的授权逻辑
* - 否则直接要求请求必须经过认证
*/
@Bean(name = ["defaultApiKeySecurityWebFilterChain"])
fun defaultApiKeySecurityWebFilterChain(
registrar: SecurityWebFilterChainRegistrar,
http: ServerHttpSecurity,
reactiveAuthorizationManager: ReactiveAuthorizationManager<AuthorizationContext>
): SecurityWebFilterChain {
val patterns = securityAuthorizeProperties.apiKey.pathPatterns
val matchers = patterns.map { PathPatternParserServerWebExchangeMatcher(it) }
val combinedMatcher: ServerWebExchangeMatcher =
ServerWebExchangeMatchers.matchers(*matchers.toTypedArray())
return registrar.buildChain(
SecurityConstants.API_KEY_CHAIN_ID,
http,
combinedMatcher
) { config ->
if (securityAuthorizeProperties.apiKey.useAuthorizationManager) {
config.authorizeExchange {
it.anyExchange().access(reactiveAuthorizationManager)
}
} else {
config.authorizeExchange {
it.anyExchange().authenticated()
}
}
}
}
}

View File

@ -1,26 +1,32 @@
package com.gewuyou.forgeboot.security.authorize.autoconfigure package com.gewuyou.forgeboot.security.authorize.autoconfigure.webflux
import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.ObjectMapper
import com.gewuyou.forgeboot.security.authorize.api.config.SecurityAuthorizeProperties import com.gewuyou.forgeboot.security.authorize.api.core.config.SecurityAuthorizeProperties
import com.gewuyou.forgeboot.security.authorize.api.manager.AccessManager import com.gewuyou.forgeboot.security.authorize.api.core.manager.AccessManager
import com.gewuyou.forgeboot.security.authorize.api.resolver.PermissionResolver import com.gewuyou.forgeboot.security.authorize.api.core.resolver.PermissionResolver
import com.gewuyou.forgeboot.security.authorize.impl.adapter.DynamicReactiveAuthorizationManagerAdapter import com.gewuyou.forgeboot.security.authorize.impl.webflux.adapter.DynamicReactiveAuthorizationManagerAdapter
import com.gewuyou.forgeboot.security.authorize.impl.builder.StatelessSecurityWebFilterChainRegistrar import com.gewuyou.forgeboot.security.authorize.impl.webflux.handler.ReactiveAuthorizationExceptionHandler
import com.gewuyou.forgeboot.security.authorize.impl.handler.ReactiveAuthorizationExceptionHandler import com.gewuyou.forgeboot.security.authorize.impl.webflux.registrar.StatelessSecurityWebFilterChainRegistrar
import com.gewuyou.forgeboot.security.core.common.builder.SecurityWebFilterChainRegistrar import com.gewuyou.forgeboot.security.core.common.constants.SecurityConstants
import com.gewuyou.forgeboot.security.core.common.customizer.ServerHttpSecurityCustomizer import com.gewuyou.forgeboot.security.core.common.customizer.ServerHttpSecurityCustomizer
import com.gewuyou.forgeboot.security.core.common.registrar.SecurityWebFilterChainRegistrar
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean import org.springframework.boot.autoconfigure.condition.ConditionalOnBean
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass import org.springframework.boot.autoconfigure.condition.ConditionalOnClass
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication
import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.Primary
import org.springframework.security.authentication.AuthenticationProvider
import org.springframework.security.authentication.ProviderManager
import org.springframework.security.authentication.ReactiveAuthenticationManager
import org.springframework.security.authentication.ReactiveAuthenticationManagerAdapter
import org.springframework.security.authorization.ReactiveAuthorizationManager import org.springframework.security.authorization.ReactiveAuthorizationManager
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity
import org.springframework.security.config.web.server.ServerHttpSecurity import org.springframework.security.config.web.server.ServerHttpSecurity
import org.springframework.security.web.server.SecurityWebFilterChain import org.springframework.security.web.server.SecurityWebFilterChain
import org.springframework.security.web.server.authorization.AuthorizationContext import org.springframework.security.web.server.authorization.AuthorizationContext
import org.springframework.security.web.server.authorization.ServerAccessDeniedHandler import org.springframework.security.web.server.authorization.ServerAccessDeniedHandler
import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatchers.anyExchange import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatchers
/** /**
* 反应式授权配置 * 反应式授权配置
@ -31,7 +37,7 @@ import org.springframework.security.web.server.util.matcher.ServerWebExchangeMat
*/ */
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@EnableWebFluxSecurity @EnableWebFluxSecurity
@ConditionalOnProperty(name = ["spring.main.web-application-type"], havingValue = "reactive") @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
class ReactiveAuthorizeSecurityConfiguration( class ReactiveAuthorizeSecurityConfiguration(
private val accessManager: AccessManager, private val accessManager: AccessManager,
private val permissionResolver: PermissionResolver, private val permissionResolver: PermissionResolver,
@ -54,9 +60,9 @@ class ReactiveAuthorizeSecurityConfiguration(
http: ServerHttpSecurity, http: ServerHttpSecurity,
): SecurityWebFilterChain = registrar ): SecurityWebFilterChain = registrar
.buildChain( .buildChain(
"default", SecurityConstants.DEFAULT_CHAIN_ID,
http, http,
anyExchange() ServerWebExchangeMatchers.anyExchange()
) { it: ServerHttpSecurity -> ) { it: ServerHttpSecurity ->
it.authorizeExchange { it.authorizeExchange {
it.anyExchange().denyAll() it.anyExchange().denyAll()
@ -93,6 +99,31 @@ class ReactiveAuthorizeSecurityConfiguration(
return DynamicReactiveAuthorizationManagerAdapter(accessManager, permissionResolver) return DynamicReactiveAuthorizationManagerAdapter(accessManager, permissionResolver)
} }
/**
* 反应式认证管理器
* 创建并返回一个主认证管理器实例用于处理响应式编程环境中的身份验证请求
* 该管理器基于提供的认证提供者列表进行初始化
*
* 此方法通过将传统的 ProviderManager 包装在 ReactiveAuthenticationManagerAdapter
* 实现了对响应式编程模型的支持ProviderManager 被构造为使用给定的认证提供者列表
* 并作为适配器的一部分来完成异步的身份验证逻辑
*
* @param authenticationProviders 认证提供者列表用于执行具体的身份验证逻辑
* 每个提供者负责特定类型的身份验证机制
* @return 初始化后的 ReactiveAuthenticationManager 实例用于响应式环境下的身份验证流程
* 返回的对象是 ReactiveAuthenticationManagerAdapter 的实例其内部封装了同步的 ProviderManager
*/
@Bean
@Primary
@ConditionalOnBean
fun reactiveAuthenticationManager(
authenticationProviders: List<AuthenticationProvider>
): ReactiveAuthenticationManager {
return ReactiveAuthenticationManagerAdapter(
ProviderManager(authenticationProviders)
)
}
/** /**
* 无状态安全过滤链注册器 * 无状态安全过滤链注册器
* 创建并返回一个无状态的安全过滤链注册器用于注册需要无状态处理的安全过滤链 * 创建并返回一个无状态的安全过滤链注册器用于注册需要无状态处理的安全过滤链

View File

@ -1,4 +1,7 @@
com.gewuyou.forgeboot.security.authorize.autoconfigure.ForgeSecurityAuthorizeCoreConfiguration
com.gewuyou.forgeboot.security.authorize.autoconfigure.ReactiveAuthorizeSecurityConfiguration
com.gewuyou.forgeboot.security.authorize.autoconfigure.ForgeSecurityAuthorizeAutoConfiguration com.gewuyou.forgeboot.security.authorize.autoconfigure.ForgeSecurityAuthorizeAutoConfiguration
com.gewuyou.forgeboot.security.authorize.autoconfigure.ServletAuthorizeSecurityConfiguration com.gewuyou.forgeboot.security.authorize.autoconfigure.core.ForgeSecurityAuthorizeCoreConfiguration
com.gewuyou.forgeboot.security.authorize.autoconfigure.core.ApiKeySecurityCoreAutoConfiguration
com.gewuyou.forgeboot.security.authorize.autoconfigure.webflux.ReactiveAuthorizeSecurityConfiguration
com.gewuyou.forgeboot.security.authorize.autoconfigure.webflux.ReactiveApiKeySecurityAutoConfiguration
com.gewuyou.forgeboot.security.authorize.autoconfigure.servlet.ServletAuthorizeSecurityConfiguration
com.gewuyou.forgeboot.security.authorize.autoconfigure.servlet.ServletApiKeySecurityAutoConfiguration

View File

@ -1,9 +1,9 @@
package com.gewuyou.forgeboot.security.authorize.impl.aspect package com.gewuyou.forgeboot.security.authorize.impl.core.aspect
import com.gewuyou.forgeboot.security.authorize.api.annotations.RequiresPermission import com.gewuyou.forgeboot.security.authorize.api.core.annotations.RequiresPermission
import com.gewuyou.forgeboot.security.authorize.api.manager.AccessManager import com.gewuyou.forgeboot.security.authorize.api.core.manager.AccessManager
import com.gewuyou.forgeboot.security.authorize.api.strategy.AuthorizationStrategy import com.gewuyou.forgeboot.security.authorize.api.core.strategy.AuthorizationStrategy
import com.gewuyou.forgeboot.security.authorize.impl.resolver.SpELResolver import com.gewuyou.forgeboot.security.authorize.impl.core.resolver.SpELResolver
import org.aspectj.lang.ProceedingJoinPoint import org.aspectj.lang.ProceedingJoinPoint
import org.aspectj.lang.annotation.Around import org.aspectj.lang.annotation.Around
import org.aspectj.lang.annotation.Aspect import org.aspectj.lang.annotation.Aspect

View File

@ -1,8 +1,8 @@
package com.gewuyou.forgeboot.security.authorize.impl.manager package com.gewuyou.forgeboot.security.authorize.impl.core.manager
import com.gewuyou.forgeboot.security.authorize.api.manager.AccessManager import com.gewuyou.forgeboot.security.authorize.api.core.manager.AccessManager
import com.gewuyou.forgeboot.security.authorize.api.provider.PermissionProvider import com.gewuyou.forgeboot.security.authorize.api.core.provider.PermissionProvider
import com.gewuyou.forgeboot.security.authorize.api.strategy.AuthorizationStrategy import com.gewuyou.forgeboot.security.authorize.api.core.strategy.AuthorizationStrategy
import org.springframework.security.core.Authentication import org.springframework.security.core.Authentication
/** /**

View File

@ -1,7 +1,7 @@
package com.gewuyou.forgeboot.security.authorize.impl.provider package com.gewuyou.forgeboot.security.authorize.impl.core.provider
import com.gewuyou.forgeboot.core.extension.log import com.gewuyou.forgeboot.core.extension.log
import com.gewuyou.forgeboot.security.authorize.api.provider.PermissionProvider import com.gewuyou.forgeboot.security.authorize.api.core.provider.PermissionProvider
import org.springframework.security.core.Authentication import org.springframework.security.core.Authentication
/** /**

View File

@ -0,0 +1,57 @@
package com.gewuyou.forgeboot.security.authorize.impl.core.provider
import com.gewuyou.forgeboot.security.authorize.api.core.service.ApiKeyService
import com.gewuyou.forgeboot.security.core.common.token.ApiKeyAuthenticationToken
import org.springframework.security.authentication.AuthenticationProvider
import org.springframework.security.core.Authentication
/**
* API 密钥身份验证提供程序
*
* 该类实现 Spring Security AuthenticationProvider 接口用于处理基于 API Key 的身份验证流程
*
* @property apiKeyService 用于校验 API Key 并获取用户信息和权限的服务组件
* @constructor 创建一个 ApiKeyAuthenticationProvider 实例
*
* @since 2025-06-25 13:09:43
* @author gewuyou
*/
class ApiKeyAuthenticationProvider(
private val apiKeyService: ApiKeyService
) : AuthenticationProvider {
/**
* 执行身份验证操作
*
* 将传入的 Authentication 对象转换为 ApiKeyAuthenticationToken
* 然后使用 apiKeyService 校验 API Key 并获取相关用户信息和权限
*
* @param authentication 包含 API Key 的身份验证请求对象
* @return 返回已认证的 Authentication 对象
*/
override fun authenticate(authentication: Authentication): Authentication {
val token = authentication as ApiKeyAuthenticationToken
val keyInfo = apiKeyService.validate(token.apiKey)
return ApiKeyAuthenticationToken(
token.apiKey,
keyInfo.principal,
keyInfo.authorities
).apply {
isAuthenticated = true
}
}
/**
* 判断此 Provider 是否支持给定的身份验证类型
*
* 用于确定当前 Provider 是否可以处理指定的 Authentication 类型
* 此方法被调用时会检查是否为 ApiKeyAuthenticationToken 或其子类
*
* @param authentication 要检查的身份验证类
* @return 如果支持则返回 true否则返回 false
*/
override fun supports(authentication: Class<*>): Boolean {
return ApiKeyAuthenticationToken::class.java.isAssignableFrom(authentication)
}
}

View File

@ -1,6 +1,6 @@
package com.gewuyou.forgeboot.security.authorize.impl.resolver package com.gewuyou.forgeboot.security.authorize.impl.core.resolver
import com.gewuyou.forgeboot.security.authorize.api.resolver.PermissionResolver import com.gewuyou.forgeboot.security.authorize.api.core.resolver.PermissionResolver
/** /**
* 默认权限解析程序 * 默认权限解析程序

View File

@ -1,4 +1,4 @@
package com.gewuyou.forgeboot.security.authorize.impl.resolver package com.gewuyou.forgeboot.security.authorize.impl.core.resolver
import org.springframework.beans.factory.config.ConfigurableBeanFactory import org.springframework.beans.factory.config.ConfigurableBeanFactory
import org.springframework.context.expression.BeanFactoryResolver import org.springframework.context.expression.BeanFactoryResolver

View File

@ -1,7 +1,7 @@
package com.gewuyou.forgeboot.security.authorize.impl.strategy package com.gewuyou.forgeboot.security.authorize.impl.core.strategy
import com.gewuyou.forgeboot.security.authorize.api.provider.PermissionProvider import com.gewuyou.forgeboot.security.authorize.api.core.provider.PermissionProvider
import com.gewuyou.forgeboot.security.authorize.api.strategy.AuthorizationStrategy import com.gewuyou.forgeboot.security.authorize.api.core.strategy.AuthorizationStrategy
import org.springframework.security.core.Authentication import org.springframework.security.core.Authentication
/** /**

View File

@ -1,10 +1,10 @@
package com.gewuyou.forgeboot.security.authorize.impl.adapter package com.gewuyou.forgeboot.security.authorize.impl.servlet.adapter
import com.gewuyou.forgeboot.core.extension.log import com.gewuyou.forgeboot.core.extension.log
import com.gewuyou.forgeboot.security.authorize.api.manager.AccessManager import com.gewuyou.forgeboot.security.authorize.api.core.manager.AccessManager
import com.gewuyou.forgeboot.security.authorize.api.resolver.PermissionResolver import com.gewuyou.forgeboot.security.authorize.api.core.resolver.PermissionResolver
import com.gewuyou.forgeboot.security.authorize.api.servlet.manager.DynamicAuthorizationManager
import org.springframework.security.authorization.AuthorizationDecision import org.springframework.security.authorization.AuthorizationDecision
import org.springframework.security.authorization.AuthorizationManager
import org.springframework.security.core.Authentication import org.springframework.security.core.Authentication
import org.springframework.security.web.access.intercept.RequestAuthorizationContext import org.springframework.security.web.access.intercept.RequestAuthorizationContext
import java.util.function.Supplier import java.util.function.Supplier
@ -20,7 +20,7 @@ import java.util.function.Supplier
class DynamicAuthorizationManagerAdapter( class DynamicAuthorizationManagerAdapter(
private val accessManager: AccessManager, private val accessManager: AccessManager,
private val permissionResolver: PermissionResolver, private val permissionResolver: PermissionResolver,
) : AuthorizationManager<RequestAuthorizationContext> { ) : DynamicAuthorizationManager<RequestAuthorizationContext> {
/** /**
* 执行权限校验的核心方法 * 执行权限校验的核心方法

View File

@ -0,0 +1,55 @@
package com.gewuyou.forgeboot.security.authorize.impl.servlet.customizer
import com.gewuyou.forgeboot.security.core.common.constants.SecurityConstants
import com.gewuyou.forgeboot.security.core.common.customizer.HttpSecurityCustomizer
import jakarta.servlet.Filter
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter
/**
* API 密钥 HTTP 安全定制器
*
* 用于为基于 API 密钥的身份验证机制定制 Spring Security HTTP 安全配置
* 该类实现了 HttpSecurityCustomizer 接口能够根据指定的安全链 ID 决定是否启用当前的认证逻辑
* 并负责将 API 密钥身份验证过滤器和提供者注入到安全配置中
*
* @property apiKeyAuthenticationProvider 提供 API 密钥身份验证逻辑的认证提供者
* @property apiKeyAuthenticationFilter 处理 API 密钥身份验证请求的过滤器实例
* @since 2025-06-25 16:09:38
* @author gewuyou
*/
class ApiKeyHttpSecurityCustomizer(
private val apiKeyAuthenticationFilter: Filter
) : HttpSecurityCustomizer {
/**
* 判断当前定制器是否支持处理指定的安全链配置
*
* 此方法用于标识该定制器是否适用于特定的安全链配置
* 实现类应根据 chainId 参数决定是否启用此定制器的逻辑
*
* @param chainId 安全链的唯一标识符用于区分不同的安全配置场景
* @return Boolean 返回 true 表示支持该 chainId否则不支持
*/
override fun supports(chainId: String): Boolean {
return SecurityConstants.API_KEY_CHAIN_ID == chainId
}
/**
* 执行安全配置的定制逻辑
*
* API 密钥身份验证相关的组件注册到 Spring Security 流程中
* 包括
* - 注册认证提供者apiKeyAuthenticationProvider
* - 在请求处理流程中插入 ApiKeyAuthenticationFilter 过滤器
* 该过滤器会在 UsernamePasswordAuthenticationFilter 前执行
*
* @param http 用于构建 HTTP 安全策略的 HttpSecurity 实例
* 通过此参数可添加或修改安全规则如认证授权等
*/
override fun customize(http: HttpSecurity) {
// 配置安全逻辑:注册认证提供者并将 API 密钥过滤器插入到过滤器链中的合适位置
http
.addFilterBefore(apiKeyAuthenticationFilter, UsernamePasswordAuthenticationFilter::class.java)
}
}

View File

@ -0,0 +1,51 @@
package com.gewuyou.forgeboot.security.authorize.impl.servlet.filter
import com.gewuyou.forgeboot.security.core.common.constants.SecurityConstants
import com.gewuyou.forgeboot.security.core.common.token.ApiKeyAuthenticationToken
import jakarta.servlet.FilterChain
import jakarta.servlet.http.HttpServletRequest
import jakarta.servlet.http.HttpServletResponse
import org.springframework.security.authentication.AuthenticationManager
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.web.filter.OncePerRequestFilter
/**
* API 密钥身份验证筛选器
* 用于处理基于API密钥的身份验证流程继承自OncePerRequestFilter以确保每个请求只被过滤一次
*
* @param authenticationManager 身份验证管理器用于执行实际的身份验证操作
* @since 2025-06-25 13:34:47
* @author gewuyou
*/
class ApiKeyAuthenticationFilter(
private val authenticationManager: AuthenticationManager
) : OncePerRequestFilter() {
/**
* 执行内部过滤逻辑
* 从请求头中提取API密钥并进行身份验证
*
* @param request 当前HTTP请求
* @param response 当前HTTP响应
* @param chain 过滤器链
*/
override fun doFilterInternal(request: HttpServletRequest, response: HttpServletResponse, chain: FilterChain) {
// 从请求头中获取Authorization字段
val header = request.getHeader(SecurityConstants.AUTHORIZATION_HEADER)
// 检查是否为Bearer类型认证信息
if (header?.startsWith(SecurityConstants.BEARER_PREFIX) == true) {
// 提取并清理API密钥
val apiKey = header.removePrefix(SecurityConstants.BEARER_PREFIX).trim()
// 创建认证令牌
val token = ApiKeyAuthenticationToken(apiKey, null)
// 执行认证并存储认证结果到安全上下文中
val authResult = authenticationManager.authenticate(token)
SecurityContextHolder.getContext().authentication = authResult
}
// 继续执行过滤器链
chain.doFilter(request, response)
}
}

View File

@ -1,8 +1,8 @@
package com.gewuyou.forgeboot.security.authorize.impl.handler package com.gewuyou.forgeboot.security.authorize.impl.servlet.handler
import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.ObjectMapper
import com.gewuyou.forgeboot.core.extension.log import com.gewuyou.forgeboot.core.extension.log
import com.gewuyou.forgeboot.security.authorize.api.config.SecurityAuthorizeProperties import com.gewuyou.forgeboot.security.authorize.api.core.config.SecurityAuthorizeProperties
import com.gewuyou.forgeboot.webmvc.dto.R import com.gewuyou.forgeboot.webmvc.dto.R
import jakarta.servlet.http.HttpServletRequest import jakarta.servlet.http.HttpServletRequest
import jakarta.servlet.http.HttpServletResponse import jakarta.servlet.http.HttpServletResponse

View File

@ -1,8 +1,8 @@
package com.gewuyou.forgeboot.security.authorize.impl.builder package com.gewuyou.forgeboot.security.authorize.impl.servlet.registrar
import com.gewuyou.forgeboot.security.core.common.builder.SecurityFilterChainRegistrar
import com.gewuyou.forgeboot.security.core.common.customizer.HttpSecurityCustomizer import com.gewuyou.forgeboot.security.core.common.customizer.HttpSecurityCustomizer
import com.gewuyou.forgeboot.security.core.common.extension.cleanUnNeedConfig import com.gewuyou.forgeboot.security.core.common.extension.cleanUnNeedConfig
import com.gewuyou.forgeboot.security.core.common.registrar.SecurityFilterChainRegistrar
import com.gewuyou.forgeboot.security.core.common.wrapper.SecurityFilterChainWrapper import com.gewuyou.forgeboot.security.core.common.wrapper.SecurityFilterChainWrapper
import org.springframework.http.HttpMethod import org.springframework.http.HttpMethod
import org.springframework.security.authorization.AuthorizationManager import org.springframework.security.authorization.AuthorizationManager
@ -45,7 +45,7 @@ class StatelessSecurityFilterChainRegistrar(
matcher: RequestMatcher, matcher: RequestMatcher,
config: (HttpSecurity) -> Unit, config: (HttpSecurity) -> Unit,
): SecurityFilterChainWrapper { ): SecurityFilterChainWrapper {
// 清除不必要默认安全配置,优化无状态场景下的行为 // 清除不必要默认安全配置,优化无状态场景下的行为
// 设置请求匹配器以确定过滤器链适用范围 // 设置请求匹配器以确定过滤器链适用范围
// 配置 HTTP 请求的授权规则: // 配置 HTTP 请求的授权规则:
// - 允许所有 OPTIONS 请求(通常用于跨域预检) // - 允许所有 OPTIONS 请求(通常用于跨域预检)

View File

@ -1,8 +1,8 @@
package com.gewuyou.forgeboot.security.authorize.impl.adapter package com.gewuyou.forgeboot.security.authorize.impl.webflux.adapter
import com.gewuyou.forgeboot.security.authorize.api.manager.AccessManager import com.gewuyou.forgeboot.security.authorize.api.core.manager.AccessManager
import com.gewuyou.forgeboot.security.authorize.api.manager.DynamicReactiveAuthorizationManager import com.gewuyou.forgeboot.security.authorize.api.webflux.manager.DynamicReactiveAuthorizationManager
import com.gewuyou.forgeboot.security.authorize.api.resolver.PermissionResolver import com.gewuyou.forgeboot.security.authorize.api.core.resolver.PermissionResolver
import org.springframework.security.authorization.AuthorizationDecision import org.springframework.security.authorization.AuthorizationDecision
import org.springframework.security.core.Authentication import org.springframework.security.core.Authentication
import org.springframework.security.web.server.authorization.AuthorizationContext import org.springframework.security.web.server.authorization.AuthorizationContext

View File

@ -0,0 +1,46 @@
package com.gewuyou.forgeboot.security.authorize.impl.webflux.customizer
import com.gewuyou.forgeboot.security.core.common.constants.SecurityConstants
import com.gewuyou.forgeboot.security.core.common.customizer.ServerHttpSecurityCustomizer
import org.springframework.security.config.web.server.SecurityWebFiltersOrder
import org.springframework.security.config.web.server.ServerHttpSecurity
import org.springframework.web.server.WebFilter
/**
* API 密钥服务器 HTTP 安全定制器
*
* 该类用于在 Spring WebFlux 环境下基于 API 密钥进行认证的安全配置定制
* 它实现了 ServerHttpSecurityCustomizer 接口能将自定义的认证逻辑集成到安全链中
*
* @constructor
* @param apiKeyReactiveAuthenticationFilter 自定义的 WebFilter 实现用于执行 API 密钥认证逻辑
*/
class ApiKeyServerHttpSecurityCustomizer(
private val apiKeyReactiveAuthenticationFilter: WebFilter,
) : ServerHttpSecurityCustomizer {
/**
* 判断当前定制器是否支持处理指定的安全链配置
*
* 此方法用于标识该定制器是否适用于特定的安全链配置
* 实现类应根据 chainId 参数决定是否启用此定制器的逻辑
*
* @param chainId 安全链的唯一标识符用于区分不同的安全配置场景
* @return Boolean 返回 true 表示支持该 chainId否则不支持
*/
override fun supports(chainId: String): Boolean {
return SecurityConstants.API_KEY_CHAIN_ID == chainId
}
/**
* 自定义 ServerHttpSecurity 配置的方法
*
* 此方法由框架调用允许开发者插入自定义的安全配置逻辑
* 方法参数提供了 ServerHttpSecurity 实例可用于链式配置
*
* @param http ServerHttpSecurity 实例用于构建 WebFlux 安全配置
*/
override fun customize(http: ServerHttpSecurity) {
// 将过滤器添加到安全链中的认证位置
http.addFilterAt(apiKeyReactiveAuthenticationFilter, SecurityWebFiltersOrder.AUTHENTICATION)
}
}

View File

@ -0,0 +1,66 @@
package com.gewuyou.forgeboot.security.authorize.impl.webflux.filter
import com.gewuyou.forgeboot.security.core.common.constants.SecurityConstants
import com.gewuyou.forgeboot.security.core.common.token.ApiKeyAuthenticationToken
import org.springframework.http.HttpHeaders
import org.springframework.security.authentication.ReactiveAuthenticationManager
import org.springframework.security.core.Authentication
import org.springframework.security.web.server.authentication.AuthenticationWebFilter
import org.springframework.security.web.server.authentication.ServerAuthenticationConverter
import org.springframework.web.server.ServerWebExchange
import reactor.core.publisher.Mono
/**
* API 密钥反应式身份验证过滤器
*
* 用于在 WebFlux 环境下通过 API 密钥进行身份验证的过滤器
* 它继承自 [AuthenticationWebFilter]并使用 [ApiKeyServerAuthenticationConverter]
* 将请求中的 API 密钥转换为认证对象 [ApiKeyAuthenticationToken]
*
* @property authenticationManager 身份验证管理器用于处理身份验证请求
* @since 2025-06-25 16:46:13
* @author gewuyou
*/
class ApiKeyReactiveAuthenticationFilter(
authenticationManager: ReactiveAuthenticationManager
) : AuthenticationWebFilter(authenticationManager) {
/**
* 初始化代码块设置当前过滤器使用的身份验证转换器
*
* 此处将默认的转换逻辑替换为基于 API 密钥的身份验证转换器
* 该转换器负责从请求头中提取并解析 API 密钥
*/
init {
setServerAuthenticationConverter(ApiKeyServerAuthenticationConverter())
}
/**
* 基于 API 密钥的身份验证转换器
*
* 实现了 [ServerAuthenticationConverter] 接口负责从 [ServerWebExchange] 中提取 API 密钥
* 并将其转换为对应的认证对象 [ApiKeyAuthenticationToken]
*/
private class ApiKeyServerAuthenticationConverter : ServerAuthenticationConverter {
/**
* 将传入的请求上下文转换为认证对象
*
* 此方法尝试从请求头中获取 `Authorization` 字段并检查其是否以指定的前缀开头
* 如果匹配则移除前缀并提取出 API 密钥最终构造一个未认证的 [ApiKeyAuthenticationToken] 对象
*
* @param exchange 当前的服务器 Web 交换对象包含请求信息
* @return 返回一个 [Mono<Authentication>?] 类型的对象如果成功提取 API 密钥则返回包含认证对象的 Mono
* 否则返回空的 Mono
*/
override fun convert(exchange: ServerWebExchange): Mono<Authentication>? {
val headerValue = exchange.request.headers.getFirst(HttpHeaders.AUTHORIZATION)
return if (headerValue?.startsWith(SecurityConstants.BEARER_PREFIX, ignoreCase = true) == true) {
val apiKey = headerValue.removePrefix(SecurityConstants.BEARER_PREFIX).trim()
Mono.just(ApiKeyAuthenticationToken(apiKey, null))
} else {
Mono.empty()
}
}
}
}

View File

@ -1,8 +1,8 @@
package com.gewuyou.forgeboot.security.authorize.impl.handler package com.gewuyou.forgeboot.security.authorize.impl.webflux.handler
import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.ObjectMapper
import com.gewuyou.forgeboot.core.extension.log import com.gewuyou.forgeboot.core.extension.log
import com.gewuyou.forgeboot.security.authorize.api.config.SecurityAuthorizeProperties import com.gewuyou.forgeboot.security.authorize.api.core.config.SecurityAuthorizeProperties
import com.gewuyou.forgeboot.webmvc.dto.R import com.gewuyou.forgeboot.webmvc.dto.R
import org.springframework.http.HttpHeaders import org.springframework.http.HttpHeaders
import org.springframework.http.HttpStatus import org.springframework.http.HttpStatus

View File

@ -1,8 +1,8 @@
package com.gewuyou.forgeboot.security.authorize.impl.builder package com.gewuyou.forgeboot.security.authorize.impl.webflux.registrar
import com.gewuyou.forgeboot.security.core.common.builder.SecurityWebFilterChainRegistrar
import com.gewuyou.forgeboot.security.core.common.customizer.ServerHttpSecurityCustomizer import com.gewuyou.forgeboot.security.core.common.customizer.ServerHttpSecurityCustomizer
import com.gewuyou.forgeboot.security.core.common.extension.cleanUnNeedConfig import com.gewuyou.forgeboot.security.core.common.extension.cleanUnNeedConfig
import com.gewuyou.forgeboot.security.core.common.registrar.SecurityWebFilterChainRegistrar
import com.gewuyou.forgeboot.security.core.common.wrapper.SecurityWebFilterChainWrapper import com.gewuyou.forgeboot.security.core.common.wrapper.SecurityWebFilterChainWrapper
import org.springframework.http.HttpMethod import org.springframework.http.HttpMethod
import org.springframework.security.authorization.ReactiveAuthorizationManager import org.springframework.security.authorization.ReactiveAuthorizationManager

View File

@ -0,0 +1,17 @@
package com.gewuyou.forgeboot.security.core.authorize.entities
import org.springframework.security.core.GrantedAuthority
/**
* API 密钥主体用于存储认证后的API密钥相关信息
*
* @property principal 认证主体标识通常是API密钥字符串
* @property authorities 与此API密钥关联的权限列表
*
* @since 2025-06-25 13:11:37
* @author gewuyou
*/
data class ApiKeyPrincipal (
val principal: String,
val authorities: List<GrantedAuthority>
)

View File

@ -0,0 +1,31 @@
package com.gewuyou.forgeboot.security.core.common.constants
/**
* 安全相关常量定义
*
* 该对象存储与安全认证相关的通用常量便于统一管理和维护
*
* @since 2025-06-25 16:02:05
* @author gewuyou
*/
object SecurityConstants {
/**
* HTTP请求头中用于携带身份凭证的字段名称
*/
const val AUTHORIZATION_HEADER = "Authorization"
/**
* Bearer Token前缀用于在请求头中标识Token类型
*/
const val BEARER_PREFIX = "Bearer "
/**
* API密钥请求头字段名称用于在请求头中携带API认证标识
*/
const val API_KEY_CHAIN_ID = "apiKey"
/**
* 默认的API密钥标识
*/
const val DEFAULT_CHAIN_ID = "default"
}

View File

@ -1,4 +1,4 @@
package com.gewuyou.forgeboot.security.core.common.builder package com.gewuyou.forgeboot.security.core.common.registrar
import com.gewuyou.forgeboot.security.core.common.wrapper.SecurityFilterChainWrapper import com.gewuyou.forgeboot.security.core.common.wrapper.SecurityFilterChainWrapper
import org.springframework.security.config.annotation.web.builders.HttpSecurity import org.springframework.security.config.annotation.web.builders.HttpSecurity

View File

@ -1,4 +1,4 @@
package com.gewuyou.forgeboot.security.core.common.builder package com.gewuyou.forgeboot.security.core.common.registrar
import com.gewuyou.forgeboot.security.core.common.wrapper.SecurityWebFilterChainWrapper import com.gewuyou.forgeboot.security.core.common.wrapper.SecurityWebFilterChainWrapper
import org.springframework.security.config.web.server.ServerHttpSecurity import org.springframework.security.config.web.server.ServerHttpSecurity

View File

@ -0,0 +1,23 @@
package com.gewuyou.forgeboot.security.core.common.token
import org.springframework.security.authentication.AbstractAuthenticationToken
import org.springframework.security.core.GrantedAuthority
/**
*API 密钥认证令牌
*
* @since 2025-06-25 13:06:54
* @author gewuyou
*/
class ApiKeyAuthenticationToken(
val apiKey: String,
private val principal: Any?,
private val authorities: Collection<GrantedAuthority> = listOf()
) : AbstractAuthenticationToken(authorities) {
override fun getCredentials(): Any = apiKey
override fun getPrincipal(): Any? = principal
override fun isAuthenticated(): Boolean = super.isAuthenticated
}