Compare commits

..

4 Commits

Author SHA1 Message Date
8042b45cea refactor(security): 更新单令牌认证链路标识
- 将 API_KEY_CHAIN_ID 重命名为 SINGLE_TOKEN_CHAIN_ID
- 修改相关配置和定制器以使用新的链路标识
- 更新 SecurityConstants 中的相应常量定义
2025-06-26 16:09:20 +08:00
21542adfcc refactor(security): 重构单令牌认证体系
- 重构 SingleTokenService 为 SingleTokenValidator,优化令牌验证流程
- 新增 TokenValidator 接口,用于定义通用令牌验证逻辑
- 更新 SingleTokenSecurityCoreAutoConfiguration,适配新的验证器
- 重构 SingleTokenAuthenticationProvider,使用新的验证器进行令牌验证
- 更新过滤器和认证令牌类,以适应新的认证流程
2025-06-26 16:07:07 +08:00
aa9bd66259 feat(security): 实现 Single Token 认证机制
- 重构了原有的 ApiKey 认证体系,改为支持 Single Token 认证
- 更新了相关的配置类、服务接口、过滤器和自定义器
- 优化了认证流程,支持在请求头中提取 Token 并进行验证
-调整了安全配置,确保 Token 认证与现有安全体系兼容
2025-06-26 11:36:02 +08:00
ec326e5a1d feat(security): 实现 API密钥安全控制并重构授权模块
- 新增 API 密钥安全核心配置和自动配置
- 重构授权模块,支持动态授权管理
- 更新权限解析器、授权策略和访问管理器的实现
- 新增 API 密钥认证过滤器和异常处理器
- 改进安全过滤链的构建和管理
2025-06-25 23:07:54 +08:00
41 changed files with 960 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,49 @@
package com.gewuyou.forgeboot.security.authorize.api.core.config
import org.springframework.boot.context.properties.ConfigurationProperties
/**
* Security 授权配置属性类用于定义安全相关的可配置项
*
* 该类通过@ConfigurationProperties绑定配置前缀"forgeboot.security.authorize"
* 提供了默认异常响应消息单Token控制及相关路径模式的配置支持
*
* @property defaultExceptionResponse 当访问被拒绝时返回的默认提示信息
* @property singleToken 单Token配置属性对象包含启用状态匹配路径及是否使用授权管理器
*
* @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!"
/**
* 单Token配置属性实例用于定义Token相关的行为和路径匹配规则
*/
var singleToken: SingleTokenProperties = SingleTokenProperties()
/**
* 单Token配置内部类封装与Token验证行为相关的配置项
*
* 用于控制特定路径下的Token验证行为包括启用状态路径匹配模式以及是否使用授权管理器
*/
class SingleTokenProperties {
/**
* 控制是否启用API密钥验证功能默认值为false
*/
var enabled: Boolean = false
/**
* 指定是否通过Spring Security的AuthorizationManager进行权限决策默认为true
*/
var useAuthorizationManager: Boolean = true
/**
* 定义需要应用Token验证的请求路径模式列表
*/
var pathPatterns: List<String> = listOf("/api/**")
}
}

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

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

@ -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

@ -0,0 +1,9 @@
package com.gewuyou.forgeboot.security.authorize.api.core.validator
/**
*单令牌验证器
*
* @since 2025-06-26 15:55:34
* @author gewuyou
*/
interface SingleTokenValidator<SingleTokenPrincipal>: TokenValidator<SingleTokenPrincipal>

View File

@ -0,0 +1,21 @@
package com.gewuyou.forgeboot.security.authorize.api.core.validator
/**
* 令牌验证器接口用于定义通用的令牌验证逻辑
*
* 该接口设计为泛型接口支持不同类型的令牌验证结果
*
* @since 2025-06-26 15:54:14
* @author gewuyou
*/
fun interface TokenValidator<T> {
/**
* 验证指定的令牌字符串并返回解析后的结果对象
*
* @param token 待验证的令牌字符串通常由客户端在请求头中提供
* @return 返回解析后的泛型对象 T可能是用户信息权限列表或其他业务相关的数据结构
* @throws IllegalArgumentException 如果令牌格式不正确或为空
* @throws SecurityException 如果令牌无效或已过期
*/
fun validate(token: String): T
}

View File

@ -1,4 +1,4 @@
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

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

@ -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,62 @@
package com.gewuyou.forgeboot.security.authorize.autoconfigure.core
import com.gewuyou.forgeboot.security.authorize.api.core.validator.SingleTokenValidator
import com.gewuyou.forgeboot.security.authorize.impl.core.provider.SingleTokenAuthenticationProvider
import com.gewuyou.forgeboot.security.core.authorize.entities.SingleTokenPrincipal
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
/**
* 配置类用于自动配置单点令牌Single Token认证相关的核心组件
*
* @since 2025-06-25 15:49:50
* @author gewuyou
*/
@Configuration(proxyBeanMethods = false)
class SingleTokenSecurityCoreAutoConfiguration {
/**
* 提供一个默认的 SingleTokenValidator Bean用于验证单点登录令牌
*
* 如果上下文中尚未定义此类 Bean则使用此默认实现
* 默认实现会在调用 validate 方法时抛出 UnsupportedOperationException
* 提示使用者应提供自定义的 SingleTokenValidator 实现
*
* @return 返回一个 SingleTokenValidator 接口的默认实现
*/
@Bean
@ConditionalOnMissingBean
fun singleTokenValidator(): SingleTokenValidator<SingleTokenPrincipal> {
return object : SingleTokenValidator<SingleTokenPrincipal> {
/**
* 验证给定的 token 并返回对应的用户主体信息
*
* @param token 要验证的令牌字符串
* @return 返回包含用户信息的 SingleTokenPrincipal 对象
* @throws UnsupportedOperationException 始终抛出异常提示需要自定义实现
*/
override fun validate(token: String): SingleTokenPrincipal {
throw UnsupportedOperationException("请提供 SingleTokenService 实现")
}
}
}
/**
* 注册 SingleTokenAuthenticationProvider Bean用于 Spring Security 的认证流程
*
* 该方法创建并返回一个 SingleTokenAuthenticationProvider 实例
* 用于在 Spring Security 框架中处理基于单点令牌的认证逻辑
* 如果上下文中尚未定义同名 Bean则进行注册
*
* @param singleTokenValidator 提供的 SingleTokenValidator 实例
* 用于执行具体的令牌验证逻辑
* @return 返回配置好的 AuthenticationProvider 实现类实例
*/
@Bean("singleTokenAuthenticationProvider")
@ConditionalOnMissingBean
fun singleTokenAuthenticationProvider(singleTokenValidator: SingleTokenValidator<SingleTokenPrincipal>): AuthenticationProvider {
return SingleTokenAuthenticationProvider(singleTokenValidator)
}
}

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,134 @@
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.SingleTokenHttpSecurityCustomizer
import com.gewuyou.forgeboot.security.authorize.impl.servlet.filter.SingleTokenAuthenticationFilter
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.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
/**
* Single Token安全自动配置类用于在 Servlet Web 应用中自动装配与 Single Token相关的安全组件
*
* 此配置仅在以下条件下生效
* 1. 应用类型为 Servlet
* 2. 配置项 "forgeboot.security.authorize.single-token.enabled" true
*
* @property securityAuthorizeProperties 安全授权配置属性用于获取 Single Token相关路径等信息
* @since 2025-06-25 13:41:56
* @author gewuyou
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@ConditionalOnProperty(
prefix = "forgeboot.security.authorize.single-token",
name = ["enabled"],
havingValue = "true",
matchIfMissing = false
)
class ServletSingleTokenSecurityAutoConfiguration(
private val securityAuthorizeProperties: SecurityAuthorizeProperties,
) {
/**
* 创建 Single Token认证过滤器 Bean
*
* 构建一个 SingleTokenAuthenticationFilter 实例作为 Spring Bean
* 该过滤器用于处理基于 Single Token 的身份验证逻辑
*
* @return 返回构建完成的 Filter 接口实现对象 SingleTokenAuthenticationFilter
*/
@Bean
@ConditionalOnMissingBean(name = ["singleTokenAuthenticationFilter"])
fun singleTokenAuthenticationFilter(): Filter {
return SingleTokenAuthenticationFilter()
}
/**
* 提供一个用于自定义 HTTP 安全配置的 Single Token安全自定义器 Bean
*
* 如果容器中尚不存在同名 Bean则创建并返回 SingleTokenHttpSecurityCustomizer 实例
* 此自定义器将注入的认证过滤器用于构建定制化的安全配置实现对 HttpSecurity 的扩展
*
* @param singleTokenAuthenticationFilter 注入已配置的认证过滤器用于请求处理
* @return 返回 HttpSecurityCustomizer 的具体实现对象
*/
@Bean
@ConditionalOnMissingBean
fun singleTokenHttpSecurityCustomizer(
@Qualifier("singleTokenAuthenticationFilter")
singleTokenAuthenticationFilter: Filter,
): HttpSecurityCustomizer {
return SingleTokenHttpSecurityCustomizer(singleTokenAuthenticationFilter)
}
/**
* 创建默认的安全过滤链适用于 Servlet 编程模型
*
* 此方法基于配置的路径模式构建一个复合请求匹配器并通过注册器创建对应的 SingleToken 安全过滤链
* 过滤链根据配置决定是否使用授权管理器进行访问控制提供两种模式
* - 使用授权管理器时所有请求通过指定的 authorizeManager 进行访问控制
* - 不使用授权管理器时要求所有请求必须经过身份验证
*
* @param registrar 安全过滤链注册器用于构建和管理过滤链
* @param http Spring Security HttpSecurity 配置对象
* @param authorizeManager 授权管理器用于在启用授权管理时定义访问策略
* @return 构建完成的安全过滤链实例
*/
@Bean(name = ["defaultSingleTokenSecurityFilterChain"])
fun defaultSingleTokenSecurityFilterChain(
registrar: SecurityFilterChainRegistrar,
http: HttpSecurity,
authorizeManager: AuthorizationManager<RequestAuthorizationContext>
): SecurityFilterChain {
// 从配置中获取 singleToken 适用的路径模式(如:["/api/**", "/open/**"]
val patterns = securityAuthorizeProperties.singleToken.pathPatterns
/**
* 将每个路径模式转换为 AntPathRequestMatcher 实例
*/
val matchers = patterns.map { AntPathRequestMatcher(it) }
/**
* 使用 OrRequestMatcher 组合所有路径匹配规则实现多路径匹配支持
*/
val combinedMatcher = OrRequestMatcher(matchers)
/**
* 调用注册器构建安全链指定链 IDHttpSecurity 对象和请求匹配器
*/
return registrar.buildChain(
SecurityConstants.SINGLE_TOKEN_CHAIN_ID,
http,
combinedMatcher
) { config ->
if (securityAuthorizeProperties.singleToken.useAuthorizationManager) {
/**
* 启用授权管理器时配置请求通过指定的 authorizeManager 进行访问控制
*/
config.authorizeHttpRequests {
it.anyRequest().access(authorizeManager)
}
} else {
/**
* 禁用授权管理器时要求所有请求必须经过身份验证
*/
config.authorizeHttpRequests {
it.anyRequest().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

@ -0,0 +1,132 @@
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.SingleTokenServerHttpSecurityCustomizer
import com.gewuyou.forgeboot.security.authorize.impl.webflux.filter.ReactiveSingleTokenAuthenticationFilter
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
/**
* 配置类用于在满足条件时自动配置基于 Single Token 的反应式安全机制
*
* 仅在满足以下条件时生效
* - 应用类型为 REACTIVE反应式应用
* - 配置项 `forgeboot.security.authorize.single-token.enabled` 被设置为 true
*
* @property securityAuthorizeProperties 安全授权配置属性用于获取 Single Token 的路径匹配规则等信息
* @since 2025-06-25 21:04:37
* @author gewuyou
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
@ConditionalOnProperty(
prefix = "forgeboot.security.authorize.single-token",
name = ["enabled"],
havingValue = "true",
matchIfMissing = false
)
class ReactiveSingleTokenSecurityAutoConfiguration(
private val securityAuthorizeProperties: SecurityAuthorizeProperties
) {
/**
* 创建并注册名为 reactiveSingleTokenAuthenticationFilter WebFilter Bean
*
* 该过滤器负责处理基于 Single Token 的认证逻辑确保请求携带有效的 Token
* 仅当容器中尚未存在同名的 Bean 时才会创建此实例
*
* @param reactiveAuthenticationManager 反应式认证管理器用于执行认证操作
* @return 构建完成的 WebFilter 实例
*/
@Bean
@ConditionalOnMissingBean(name = ["reactiveSingleTokenAuthenticationFilter"])
fun singleTokenAuthenticationFilter(
reactiveAuthenticationManager: ReactiveAuthenticationManager
): WebFilter {
return ReactiveSingleTokenAuthenticationFilter(reactiveAuthenticationManager)
}
/**
* 创建并注册 ServerHttpSecurityCustomizer Bean用于定制 Single Token 安全配置
*
* 此自定义器用于在构建 Spring Security 过滤器链时插入 Single Token 认证逻辑
* 仅当容器中尚未存在相同类型的 Bean 时才会创建此实例
*
* @param reactiveSingleTokenAuthenticationFilter 使用指定名称从 Spring 容器中注入的 Single Token 反应式认证过滤器 Bean
* 该过滤器负责处理实际的 Single Token 认证逻辑
*
* @return 构建完成的 ServerHttpSecurityCustomizer 实例用于在安全配置中添加 Single Token 相关逻辑
*/
@Bean
@ConditionalOnMissingBean
fun singleTokenServerHttpSecurityCustomizer(
@Qualifier("reactiveSingleTokenAuthenticationFilter")
reactiveSingleTokenAuthenticationFilter: WebFilter,
): ServerHttpSecurityCustomizer {
return SingleTokenServerHttpSecurityCustomizer(reactiveSingleTokenAuthenticationFilter)
}
/**
* 创建并注册基于 Single Token 认证的 WebFlux 安全过滤器链
*
* 该方法利用 SecurityWebFilterChainRegistrar 注册一个具有路径匹配规则的安全过滤器链
* 仅对符合配置中指定路径模式的请求生效并要求通过 Single Token 认证
*
* @param registrar 用于注册和构建安全过滤器链的核心工具类负责链的组装过程
* @param http Spring Security 提供的 ServerHttpSecurity 实例用于构建 HTTP 安全配置
* @param reactiveAuthorizationManager 反应式授权管理器用于在使用授权管理逻辑时提供访问控制
* @return 构建完成的 SecurityWebFilterChain 实例表示定义好的安全过滤器链
*
* 关键逻辑总结
* 1. 获取配置中的路径模式列表 patterns
* 2. 将每个路径转换为 ServerWebExchangeMatcher 实例形成 matchers 列表
* 3. 合并所有 matcher 形成 combinedMatcher 复合匹配规则
* 4. 利用 registrar 构建过滤器链并根据 useAuthorizationManager 配置决定采用何种认证方式
* - 若启用 authorizationManager则通过 access 方法设置自定义的授权逻辑
* - 否则直接要求请求必须经过认证
*/
@Bean(name = ["defaultSingleTokenSecurityWebFilterChain"])
fun defaultSingleTokenSecurityWebFilterChain(
registrar: SecurityWebFilterChainRegistrar,
http: ServerHttpSecurity,
reactiveAuthorizationManager: ReactiveAuthorizationManager<AuthorizationContext>
): SecurityWebFilterChain {
val patterns = securityAuthorizeProperties.singleToken.pathPatterns
val matchers = patterns.map { PathPatternParserServerWebExchangeMatcher(it) }
val combinedMatcher: ServerWebExchangeMatcher =
ServerWebExchangeMatchers.matchers(*matchers.toTypedArray())
return registrar.buildChain(
SecurityConstants.SINGLE_TOKEN_CHAIN_ID,
http,
combinedMatcher
) { config ->
if (securityAuthorizeProperties.singleToken.useAuthorizationManager) {
config.authorizeExchange {
it.anyExchange().access(reactiveAuthorizationManager)
}
} else {
config.authorizeExchange {
it.anyExchange().authenticated()
}
}
}
}
}

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.SingleTokenSecurityCoreAutoConfiguration
com.gewuyou.forgeboot.security.authorize.autoconfigure.webflux.ReactiveAuthorizeSecurityConfiguration
com.gewuyou.forgeboot.security.authorize.autoconfigure.webflux.ReactiveSingleTokenSecurityAutoConfiguration
com.gewuyou.forgeboot.security.authorize.autoconfigure.servlet.ServletAuthorizeSecurityConfiguration
com.gewuyou.forgeboot.security.authorize.autoconfigure.servlet.ServletSingleTokenSecurityAutoConfiguration

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,59 @@
package com.gewuyou.forgeboot.security.authorize.impl.core.provider
import com.gewuyou.forgeboot.security.authorize.api.core.validator.SingleTokenValidator
import com.gewuyou.forgeboot.security.core.authorize.entities.SingleTokenPrincipal
import com.gewuyou.forgeboot.security.core.common.token.SingleTokenAuthenticationToken
import org.springframework.security.authentication.AuthenticationProvider
import org.springframework.security.core.Authentication
/**
* 单例 Token 认证提供者实现 Spring Security AuthenticationProvider 接口
*
* 用于处理基于 SingleToken 的身份验证流程
*
* @property singleTokenValidator 用于执行 Token 校验的服务组件
* @author gewuyou
* @since 2025-06-25 13:09:43
*/
class SingleTokenAuthenticationProvider(
private val singleTokenValidator: SingleTokenValidator<SingleTokenPrincipal>
) : AuthenticationProvider {
/**
* 执行身份验证操作
*
* 将传入的身份验证对象转换为 SingleTokenAuthenticationToken 类型
* 然后通过 singleTokenService 验证 Token 的有效性并返回认证后的 Authentication 对象
*
* 该方法的主要流程包括
* 1. 强制类型转换输入的 Authentication 对象为 SingleTokenAuthenticationToken
* 2. 使用 Token principal 值调用 singleTokenService 进行 Token 校验
* 3. 构建并返回已认证的 Authentication 实例
*
* @param authentication 需要被验证的 Authentication 实例必须是 SingleTokenAuthenticationToken 类型
* @return 返回一个已认证的 Authentication 对象表示身份验证成功的结果
*/
override fun authenticate(authentication: Authentication): Authentication {
// 转换 Authentication 为 SingleTokenAuthenticationToken 类型
val token = authentication as SingleTokenAuthenticationToken
// 使用 Token 的 principal 值进行校验,获取 Token 信息
val tokenInfo = singleTokenValidator.validate(token.principal.toString())
// 创建已认证的 Authentication 实例并返回
return SingleTokenAuthenticationToken.authenticated(tokenInfo, tokenInfo.authorities)
}
/**
* 判断当前 Provider 是否支持给定的身份验证类型
*
* 此方法检查传入的身份验证类是否是 SingleTokenAuthenticationToken 或其子类
*
* @param authentication 要检查的身份验证类
* @return 如果支持该类型则返回 true否则返回 false
*/
override fun supports(authentication: Class<*>): Boolean {
// 检查传入的身份验证类是否是 SingleTokenAuthenticationToken 或其子类
return SingleTokenAuthenticationToken::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,50 @@
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
/**
* 基于单 Token 认证的安全配置定制器
*
* 该类用于在 Spring Security 的过滤器链中注册并配置 API 密钥身份验证逻辑
* 仅当当前安全链标识符匹配 SINGLE_TOKEN_CHAIN_ID 时生效
*
* @property singleTokenAuthenticationFilter 处理 API 密钥身份验证请求的过滤器实例
* @since 2025-06-25 16:09:38
* @author gewuyou
*/
class SingleTokenHttpSecurityCustomizer(
private val singleTokenAuthenticationFilter: Filter
) : HttpSecurityCustomizer {
/**
* 判断当前定制器是否支持处理指定的安全链配置
*
* 此方法用于标识该定制器是否适用于特定的安全链配置
* 实现类应根据 chainId 参数决定是否启用此定制器的逻辑
*
* @param chainId 安全链的唯一标识符用于区分不同的安全配置场景
* @return Boolean 返回 true 表示支持该 chainId否则不支持
*/
override fun supports(chainId: String): Boolean {
return SecurityConstants.SINGLE_TOKEN_CHAIN_ID == chainId
}
/**
* 执行安全配置的定制逻辑
*
* API 密钥身份验证过滤器添加到 Spring Security 的过滤器链中
* 置于 UsernamePasswordAuthenticationFilter 之前以确保优先处理 Token 请求
*
* @param http 用于构建 HTTP 安全策略的 HttpSecurity 实例
* 通过此参数可添加或修改安全规则如认证授权等
*/
override fun customize(http: HttpSecurity) {
// 配置安全逻辑:注册认证提供者并将 API 密钥过滤器插入到过滤器链中的合适位置
http
.addFilterBefore(singleTokenAuthenticationFilter, UsernamePasswordAuthenticationFilter::class.java)
}
}

View File

@ -0,0 +1,48 @@
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.SingleTokenAuthenticationToken
import jakarta.servlet.FilterChain
import jakarta.servlet.http.HttpServletRequest
import jakarta.servlet.http.HttpServletResponse
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.web.filter.OncePerRequestFilter
/**
* 单Token认证过滤器
*
* 用于在请求处理链中执行基于Token的身份验证逻辑
* 从请求头中提取指定格式的Token并构造未认证身份令牌放入安全上下文
*
* @since 2025-06-25 13:34:47
* @author gewuyou
*/
class SingleTokenAuthenticationFilter() : OncePerRequestFilter() {
/**
* 执行内部过滤逻辑
*
* 从请求头中提取API密钥解析出Token后构造未认证的SingleTokenAuthenticationToken
* 并将其设置到SecurityContextHolder上下文中若当前上下文已存在认证信息则直接跳过
*
* @param request 当前HTTP请求
* @param response 当前HTTP响应
* @param chain 过滤器链用于继续执行后续的过滤操作
*/
override fun doFilterInternal(request: HttpServletRequest, response: HttpServletResponse, chain: FilterChain) {
// 如果已有认证信息,跳过
if (SecurityContextHolder.getContext().authentication != null) {
chain.doFilter(request, response)
return
}
val header = request.getHeader(SecurityConstants.AUTHORIZATION_HEADER)
if (header?.startsWith(SecurityConstants.BEARER_PREFIX) == true) {
val token = header.removePrefix(SecurityConstants.BEARER_PREFIX).trim()
// 构造未认证的 token 放入上下文
val authentication = SingleTokenAuthenticationToken.unauthenticated(token)
SecurityContextHolder.getContext().authentication = authentication
}
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
/**
* 用于在 Spring WebFlux 环境下进行基于 Token 的认证安全配置定制
*
* 此类实现 ServerHttpSecurityCustomizer 接口负责将自定义的 Token 认证逻辑集成到安全链中
* 它通过 supports 方法判断是否适用于当前的安全链配置并通过 customize 方法插入过滤器
*
* @constructor
* @param reactiveSingleTokenAuthenticationFilter 自定义的 WebFilter 实现用于执行 Token 认证逻辑
*/
class SingleTokenServerHttpSecurityCustomizer(
private val reactiveSingleTokenAuthenticationFilter: WebFilter,
) : ServerHttpSecurityCustomizer {
/**
* 判断当前定制器是否支持处理指定的安全链配置
*
* 该方法用于标识此定制器是否适用于给定 chainId 所代表的安全配置场景
* 在本实现中仅当 chainId 与预定义的 SINGLE_TOKEN_CHAIN_ID 匹配时返回 true
*
* @param chainId 安全链的唯一标识符用于区分不同的安全配置场景
* @return Boolean 返回 true 表示支持该 chainId否则不支持
*/
override fun supports(chainId: String): Boolean {
return SecurityConstants.SINGLE_TOKEN_CHAIN_ID == chainId
}
/**
* 自定义 ServerHttpSecurity 配置的方法
*
* 此方法由框架调用允许开发者插入特定于该安全链的配置逻辑
* 参数提供了 ServerHttpSecurity 实例可以通过其添加修改或删除安全相关的组件
*
* @param http ServerHttpSecurity 实例用于构建 WebFlux 安全配置
*/
override fun customize(http: ServerHttpSecurity) {
// 将 Token 认证过滤器添加到 WebFlux 安全链中的认证位置
http.addFilterAt(reactiveSingleTokenAuthenticationFilter, 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.SingleTokenAuthenticationToken
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
/**
* 反应式单令牌身份验证过滤器
*
* 用于在 WebFlux 环境下通过单 Token 进行身份验证的过滤器
* 它继承自 [AuthenticationWebFilter]并使用 [SingleTokenServerAuthenticationConverter]
* 将请求中的 Token 转换为认证对象 [SingleTokenAuthenticationToken]
*
* @property authenticationManager 身份验证管理器用于处理身份验证请求
* @since 2025-06-25 16:46:13
* @author gewuyou
*/
class ReactiveSingleTokenAuthenticationFilter(
authenticationManager: ReactiveAuthenticationManager
) : AuthenticationWebFilter(authenticationManager) {
/**
* 初始化代码块设置当前过滤器使用的身份验证转换器
*
* 此处将默认的转换逻辑替换为基于 Token 的身份验证转换器
* 该转换器负责从请求头中提取并解析 Token
*/
init {
setServerAuthenticationConverter(SingleTokenServerAuthenticationConverter())
}
/**
* 基于 Token 的身份验证转换器实现类
*
* 实现了 [ServerAuthenticationConverter] 接口负责从 [ServerWebExchange] 中提取 Token
* 并将其转换为对应的认证对象 [SingleTokenAuthenticationToken]
*/
private class SingleTokenServerAuthenticationConverter : ServerAuthenticationConverter {
/**
* 将传入的请求上下文转换为认证对象
*
* 此方法尝试从请求头中获取 `Authorization` 字段并检查其是否以指定的前缀开头
* 如果匹配则移除前缀并提取出 Token最终构造一个未认证的 [SingleTokenAuthenticationToken] 对象
*
* @param exchange 当前的服务器 Web 交换对象包含请求信息
* @return 返回一个 [Mono<Authentication>?] 类型的对象如果成功提取 Token 则返回包含认证对象的 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 singleToken = headerValue.removePrefix(SecurityConstants.BEARER_PREFIX).trim()
Mono.just(SingleTokenAuthenticationToken(singleToken, 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 SingleTokenPrincipal (
val principal: String,
val authorities: List<GrantedAuthority>
)

View File

@ -0,0 +1,42 @@
package com.gewuyou.forgeboot.security.core.common.constants
/**
* 安全相关常量定义
*
* 该对象存储与安全认证相关的通用常量便于统一管理和维护
* 包含请求头字段名称令牌前缀及链路标识等关键信息
*
* @since 2025-06-25 16:02:05
* @author gewuyou
*/
object SecurityConstants {
/**
* HTTP请求头中用于携带身份凭证的字段名称
* 通常在请求头中使用格式为 "Authorization: Bearer <token>"
*/
const val AUTHORIZATION_HEADER = "Authorization"
/**
* HTTP请求头中用于携带刷新令牌的字段名称
* 用于获取新的访问令牌避免频繁登录
*/
const val REFRESH_TOKEN_HEADER = "X-Refresh-Token"
/**
* Bearer Token前缀用于在请求头中标识Token类型
* 避免与其他类型的令牌混淆 Basic Auth
*/
const val BEARER_PREFIX = "Bearer "
/**
* 单一令牌模式下的链路标识
* 用于区分不同认证模式或业务场景的令牌处理逻辑
*/
const val SINGLE_TOKEN_CHAIN_ID = "singleToken"
/**
* 默认的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,84 @@
package com.gewuyou.forgeboot.security.core.common.token
import org.springframework.security.authentication.AbstractAuthenticationToken
import org.springframework.security.core.GrantedAuthority
/**
* 用于单令牌认证的认证令牌实现类该类扩展了 Spring Security AbstractAuthenticationToken
* 用于表示基于单一令牌 API Key的认证请求
*
* @param principal 表示经过认证的主体可以是用户对象或其他形式的身份标识不可为 null
* @param authorities 用户所拥有的权限集合默认为空列表
*
* @author gewuyou
* @since 2025-06-25 13:06:54
*/
class SingleTokenAuthenticationToken(
private val principal: Any,
authorities: Collection<GrantedAuthority>? = null,
) : AbstractAuthenticationToken(authorities) {
/**
* 初始化方法根据是否提供权限信息设置认证状态
* 如果权限信息为 null则认证状态设为未认证否则设为已认证
*/
init {
if (authorities == null) {
super.setAuthenticated(false)
} else {
super.setAuthenticated(true)
}
}
companion object {
/**
* 创建一个未认证的 SingleTokenAuthenticationToken 实例
*
* @param token 认证凭据 API 密钥或令牌不可为 null
* @return 返回未认证的 SingleTokenAuthenticationToken 实例
*/
@JvmStatic
fun unauthenticated(token: String): SingleTokenAuthenticationToken {
return SingleTokenAuthenticationToken(token)
}
/**
* 创建一个已认证的 SingleTokenAuthenticationToken 实例
*
* @param principal 表示经过认证的主体不可为 null
* @param authorities 用户所拥有的权限集合不可为 null
* @return 返回已认证的 SingleTokenAuthenticationToken 实例
*/
@JvmStatic
fun authenticated(
principal: Any,
authorities: Collection<GrantedAuthority>,
): SingleTokenAuthenticationToken {
return SingleTokenAuthenticationToken(principal.toString(), authorities)
}
}
/**
* 获取认证凭据对于单令牌认证来说凭证通常不适用因此返回 null
*
* @return 始终返回 null
*/
override fun getCredentials(): Any? = null
/**
* 获取认证的主体信息
*
* @return 返回认证的主体对象
*/
override fun getPrincipal(): Any = principal
/**
* 禁止直接设置认证状态应使用工厂方法创建已认证或未认证的实例
*
* @param authenticated 认证状态此参数将被忽略
* @throws IllegalArgumentException 总是抛出此异常以防止直接修改认证状态
*/
override fun setAuthenticated(authenticated: Boolean) {
throw IllegalArgumentException("请使用 factory 方法设置认证状态")
}
}