mirror of
https://github.moeyy.xyz/https://github.com/GeWuYou/forgeboot
synced 2025-10-27 16:14:32 +08:00
feat(security): 实现双 token 认证机制并优化安全配置
- 在 SecurityAuthenticateProperties 中添加双 token 认证相关配置- 新增 DualTokenAuthenticationService接口和实现类,支持双 token 认证 - 添加 DualTokenAuthenticationController 实现双 token认证控制器 - 重构 SecurityAuthenticateAutoConfiguration,拆分为多个更细粒度的配置类 - 新增 SecurityCoreAutoConfiguration,集中处理安全核心配置 - 添加 SecurityProviderAutoConfiguration,自动配置认证提供者 - 新增 SecurityStrategyAutoConfiguration,自动配置安全策略 - 更新 UsernamePasswordAuthenticationProvider,支持多用户详情服务
This commit is contained in:
parent
3eb5ba6239
commit
b9da8bf395
@ -28,6 +28,7 @@ class SecurityAuthenticateProperties {
|
||||
* 默认认证失败响应内容,当认证失败时返回此字符串
|
||||
*/
|
||||
var defaultAuthenticationFailureResponse = "If the authentication fails, please report the request ID for more information!"
|
||||
|
||||
/**
|
||||
* 认证模块的基础URL前缀
|
||||
*/
|
||||
@ -42,4 +43,33 @@ class SecurityAuthenticateProperties {
|
||||
* 登出接口的URL路径
|
||||
*/
|
||||
var logoutUrl = "/logout"
|
||||
|
||||
/**
|
||||
* 是否启用单 token 登录认证(如登录接口、token 生成器)
|
||||
*/
|
||||
var singleToken: SingleTokenAuthenticationProperties = SingleTokenAuthenticationProperties()
|
||||
|
||||
/**
|
||||
* 配置单 Token 认证相关属性
|
||||
*
|
||||
* 提供一个嵌套类来管理单 Token 认证的启用状态,这种设计模式允许在不改变主配置类的情况下,
|
||||
* 独立扩展单 Token 相关的更多配置项。
|
||||
*/
|
||||
class SingleTokenAuthenticationProperties {
|
||||
var enabled: Boolean = false
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否启用双 token 登录认证
|
||||
*/
|
||||
var dualToken: DualTokenAuthenticationProperties = DualTokenAuthenticationProperties()
|
||||
|
||||
/**
|
||||
* 配置双 Token 认证相关属性
|
||||
*
|
||||
* 嵌套类用于封装双 Token 认证机制的启用状态,保持配置结构清晰并支持未来扩展。
|
||||
*/
|
||||
class DualTokenAuthenticationProperties {
|
||||
var enabled: Boolean = false
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
package com.gewuyou.forgeboot.security.authenticate.api.customizer
|
||||
|
||||
|
||||
/**
|
||||
* 接口用于支持登录过滤器扩展器的排序功能。
|
||||
*
|
||||
* 此接口继承自 [LoginFilterCustomizer],通过提供一个 order 属性来定义实现类的执行顺序,
|
||||
* 确保多个 [LoginFilterCustomizer] 实现类能够按照预期的顺序被调用。
|
||||
*
|
||||
* @since 2025-06-27 07:58:46
|
||||
* @author gewuyou
|
||||
*/
|
||||
interface OrderedLoginFilterCustomizer : LoginFilterCustomizer {
|
||||
/**
|
||||
* 定义当前定制器的执行顺序。
|
||||
*
|
||||
* 数值越小,优先级越高,即会越早被执行。
|
||||
*/
|
||||
val order: Int
|
||||
}
|
||||
@ -5,43 +5,26 @@ import com.gewuyou.forgeboot.security.core.authenticate.entities.request.LoginRe
|
||||
/**
|
||||
* 登录请求类型注册表
|
||||
*
|
||||
* 用于管理不同登录类型的请求类映射关系,支持动态注册和获取登录请求类型。
|
||||
* 用于管理不同登录类型的请求类,支持注册和查询操作。
|
||||
*
|
||||
* ```kt
|
||||
* @Bean
|
||||
* fun loginRequestTypeRegistry(): LoginRequestTypeRegistry {
|
||||
* return LoginRequestTypeRegistry().apply {
|
||||
* register("default", DefaultLoginRequest::class.java)
|
||||
* register("sms", SmsLoginRequest::class.java)
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
* @since 2025-06-10 16:33:43
|
||||
* @since 2025-06-26 22:06:00
|
||||
* @author gewuyou
|
||||
*/
|
||||
class LoginRequestTypeRegistry {
|
||||
/**
|
||||
* 内部使用可变Map保存登录类型与对应LoginRequest子类的映射关系
|
||||
*/
|
||||
private val mapping = mutableMapOf<String, Class<out LoginRequest>>()
|
||||
interface LoginRequestTypeRegistry {
|
||||
|
||||
/**
|
||||
* 注册指定登录类型对应的请求类
|
||||
* 注册一个新的登录类型及其对应的请求类。
|
||||
*
|
||||
* @param loginType 登录类型的标识字符串
|
||||
* @param clazz 继承自LoginRequest的具体请求类
|
||||
* @param clazz 继承自LoginRequest的具体请求类
|
||||
*/
|
||||
fun register(loginType: String, clazz: Class<out LoginRequest>) {
|
||||
mapping[loginType] = clazz
|
||||
}
|
||||
fun register(loginType: String, clazz: Class<out LoginRequest>): LoginRequestTypeRegistry
|
||||
|
||||
/**
|
||||
* 根据登录类型获取对应的请求类
|
||||
* 根据登录类型获取对应的请求类。
|
||||
*
|
||||
* @param loginType 登录类型的标识字符串
|
||||
* @return 返回对应的LoginRequest子类,若未找到则返回null
|
||||
* @return 返回与登录类型关联的请求类,如果未找到则返回null
|
||||
*/
|
||||
fun getTypeForLoginType(loginType: String): Class<out LoginRequest>? {
|
||||
return mapping[loginType]
|
||||
}
|
||||
fun getTypeForLoginType(loginType: String): Class<out LoginRequest>?
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
package com.gewuyou.forgeboot.security.authenticate.api.service
|
||||
|
||||
import com.gewuyou.forgeboot.security.core.common.entities.TokenPair
|
||||
|
||||
/**
|
||||
* 双令牌认证服务
|
||||
*
|
||||
* 提供基于访问令牌和刷新令牌的认证机制相关功能接口,包含令牌生成与刷新逻辑。
|
||||
*
|
||||
* @since 2025-06-26 20:43:14
|
||||
* @author gewuyou
|
||||
*/
|
||||
interface DualTokenAuthenticationService {
|
||||
|
||||
/**
|
||||
* 刷新令牌并生成新的一对令牌
|
||||
*
|
||||
* 使用旧访问令牌(可能已过期)和有效刷新令牌生成新的 TokenPair。
|
||||
* 刷新过程中会验证刷新令牌的有效性,并作废旧的令牌组合。
|
||||
*
|
||||
* @param accessToken 旧访问令牌(可能已过期)
|
||||
* @param refreshToken 有效刷新令牌
|
||||
* @return 新的 TokenPair(accessToken + refreshToken)
|
||||
*/
|
||||
fun refreshTokenPair(accessToken: String, refreshToken: String): TokenPair
|
||||
|
||||
/**
|
||||
* 生成新刷新令牌
|
||||
*
|
||||
* 根据系统策略生成一个安全的、唯一的刷新令牌字符串。
|
||||
* 该令牌通常具有较长的有效期且用于获取新访问令牌。
|
||||
*
|
||||
* @return 生成的刷新令牌字符串
|
||||
*/
|
||||
fun generateRefreshToken(): String
|
||||
|
||||
/**
|
||||
* 生成访问令牌
|
||||
*
|
||||
* 基于用户详细信息生成一个访问令牌,用于临时认证请求。
|
||||
* 该令牌通常具有较短的有效期,且不能直接用于刷新操作。
|
||||
*
|
||||
* @param userDetails 用户详细信息对象
|
||||
* @return 生成的访问令牌字符串
|
||||
*/
|
||||
fun generateAccessToken(userDetails: Any): String
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
package com.gewuyou.forgeboot.security.authenticate.api.service
|
||||
|
||||
import org.springframework.security.core.userdetails.UserDetails
|
||||
|
||||
|
||||
/**
|
||||
* 用户详情服务
|
||||
*
|
||||
* @author gewuyou
|
||||
* @since 2024-11-05 19:34:50
|
||||
*/
|
||||
fun interface UserDetailsService {
|
||||
/**
|
||||
* 根据用户身份标识获取用户
|
||||
* @param principal 用户身份标识 通常为用户名 手机号 邮箱等
|
||||
* @return 用户详情 不能为空
|
||||
*/
|
||||
fun loadUserByPrincipal(principal: Any): UserDetails
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
package com.gewuyou.forgeboot.security.authenticate.api.spec
|
||||
|
||||
import com.gewuyou.forgeboot.security.core.common.entities.TokenPair
|
||||
import com.gewuyou.forgeboot.webmvc.dto.R
|
||||
|
||||
/**
|
||||
* 双令牌身份验证控制器规格
|
||||
*
|
||||
* 定义了基于双令牌(访问令牌和刷新令牌)的身份验证机制操作规范。
|
||||
* 主要用于处理令牌刷新等核心安全认证交互流程。
|
||||
*
|
||||
* @since 2025-06-26 20:24:40
|
||||
* @author gewuyou
|
||||
*/
|
||||
fun interface DualTokenAuthenticationControllerSpec {
|
||||
/**
|
||||
* 刷新访问令牌
|
||||
*
|
||||
* 当访问令牌过期时,通过有效刷新令牌获取一组新的令牌对。
|
||||
* 此方法应校验刷新令牌的有效性,并生成新访问令牌。
|
||||
* 根据实现策略,刷新令牌也可能被更新并返回。
|
||||
*
|
||||
* @param accessToken 过期的访问令牌(通常通过 Authorization 头或请求体传入)
|
||||
* @param refreshToken 有效刷新令牌(用于验证并生成新令牌)
|
||||
* @return 包含新令牌对的响应对象,通常包括新访问令牌和可能更新刷新令牌
|
||||
*/
|
||||
fun refresh(accessToken: String, refreshToken: String): R<TokenPair>
|
||||
}
|
||||
@ -1,16 +1,23 @@
|
||||
package com.gewuyou.forgeboot.security.authenticate.api.strategy
|
||||
|
||||
/**
|
||||
*身份验证处理程序支持策略
|
||||
* 身份验证处理程序支持策略
|
||||
*
|
||||
* 该函数式接口定义了身份验证策略需要实现的基本规范,用于标识当前策略支持的登录类型。
|
||||
* 实现类应当通过返回特定的登录类型集合来表明该策略的应用范围。
|
||||
*
|
||||
* @since 2025-06-11 00:03:28
|
||||
* @author gewuyou
|
||||
*/
|
||||
fun interface AuthenticationHandlerSupportStrategy{
|
||||
fun interface AuthenticationHandlerSupportStrategy {
|
||||
/**
|
||||
* 获取当前策略支持的登录类型标识符。
|
||||
*
|
||||
* @return 返回当前策略支持的登录类型字符串
|
||||
* 此方法用于判断当前身份验证策略能够处理的登录请求类型。
|
||||
* 例如:可以基于不同的认证方式(如密码、短信验证码、OAuth等)进行区分。
|
||||
*
|
||||
* @return 返回当前策略支持的登录类型字符串集合
|
||||
* 集合中的每个字符串代表一种支持的登录类型标识符
|
||||
*/
|
||||
fun supportedLoginType(): String
|
||||
fun supportedLoginTypes(): Set<String>
|
||||
}
|
||||
@ -1,39 +1,19 @@
|
||||
package com.gewuyou.forgeboot.security.authenticate.autoconfigure
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.gewuyou.forgeboot.security.authenticate.api.config.SecurityAuthenticateProperties
|
||||
import com.gewuyou.forgeboot.security.authenticate.api.customizer.LoginFilterCustomizer
|
||||
import com.gewuyou.forgeboot.security.authenticate.api.resolver.LoginRequestResolver
|
||||
import com.gewuyou.forgeboot.security.authenticate.api.strategy.AuthenticationFailureStrategy
|
||||
import com.gewuyou.forgeboot.security.authenticate.api.strategy.AuthenticationSuccessStrategy
|
||||
import com.gewuyou.forgeboot.security.authenticate.api.strategy.LogoutSuccessStrategy
|
||||
import com.gewuyou.forgeboot.security.core.common.extension.cleanUnNeedConfig
|
||||
import com.gewuyou.forgeboot.security.authenticate.api.customizer.OrderedLoginFilterCustomizer
|
||||
import com.gewuyou.forgeboot.security.authenticate.impl.filter.UnifiedAuthenticationFilter
|
||||
import com.gewuyou.forgeboot.security.authenticate.impl.handler.AuthenticationExceptionHandler
|
||||
import com.gewuyou.forgeboot.security.authenticate.impl.handler.CompositeAuthenticationFailureHandler
|
||||
import com.gewuyou.forgeboot.security.authenticate.impl.handler.CompositeAuthenticationSuccessHandler
|
||||
import com.gewuyou.forgeboot.security.authenticate.impl.handler.CompositeLogoutSuccessHandler
|
||||
import com.gewuyou.forgeboot.security.authenticate.impl.resolver.CompositeLoginRequestResolver
|
||||
import com.gewuyou.forgeboot.security.authenticate.impl.strategy.context.AuthenticationFailureHandlerContext
|
||||
import com.gewuyou.forgeboot.security.authenticate.impl.strategy.context.AuthenticationSuccessHandlerContext
|
||||
import com.gewuyou.forgeboot.security.authenticate.impl.strategy.context.LoginRequestConverterContext
|
||||
import com.gewuyou.forgeboot.security.authenticate.impl.strategy.context.LogoutSuccessHandlerContext
|
||||
import com.gewuyou.forgeboot.security.core.common.extension.cleanUnNeedConfig
|
||||
import org.springframework.beans.factory.ObjectProvider
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties
|
||||
import org.springframework.context.ApplicationContext
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.ComponentScan
|
||||
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.config.annotation.web.builders.HttpSecurity
|
||||
import org.springframework.security.web.AuthenticationEntryPoint
|
||||
import org.springframework.security.web.SecurityFilterChain
|
||||
import org.springframework.security.web.authentication.AuthenticationFailureHandler
|
||||
import org.springframework.security.web.authentication.AuthenticationSuccessHandler
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher
|
||||
|
||||
@ -45,7 +25,7 @@ import org.springframework.security.web.util.matcher.AntPathRequestMatcher
|
||||
* @since 2025-06-11 15:04:58
|
||||
* @author gewuyou
|
||||
*/
|
||||
@Configuration
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableConfigurationProperties(SecurityAuthenticateProperties::class)
|
||||
class SecurityAuthenticateAutoConfiguration {
|
||||
|
||||
@ -106,204 +86,4 @@ class SecurityAuthenticateAutoConfiguration {
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ForgeBoot安全组件的自动配置类。
|
||||
*
|
||||
* 负责注册多个用于处理身份验证流程的组合式组件,如解析器、上下文、处理器等。
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
class ForgeBootSecurityAuthenticateAutoConfiguration {
|
||||
|
||||
/**
|
||||
* 创建并返回一个组合式的登录请求解析器。
|
||||
*
|
||||
* 将多个 LoginRequestResolver 实现组合成一个统一的接口调用入口。
|
||||
*
|
||||
* @param resolvers 所有可用的 LoginRequestResolver 实例列表
|
||||
* @return 组合后的 CompositeLoginRequestResolver 实例
|
||||
*/
|
||||
@Bean
|
||||
fun compositeLoginRequestResolver(
|
||||
resolvers: List<LoginRequestResolver>,
|
||||
) = CompositeLoginRequestResolver(resolvers)
|
||||
|
||||
/**
|
||||
* 创建并返回一个登出成功处理的上下文实例。
|
||||
*
|
||||
* 用于根据注册的策略动态选择合适的 LogoutSuccessStrategy。
|
||||
*
|
||||
* @param strategies 所有可用的 LogoutSuccessStrategy 实例列表
|
||||
* @return 初始化好的 LogoutSuccessHandlerContext 实例
|
||||
*/
|
||||
@Bean
|
||||
fun logoutSuccessHandlerContext(
|
||||
strategies: List<LogoutSuccessStrategy>,
|
||||
) = LogoutSuccessHandlerContext(strategies)
|
||||
|
||||
/**
|
||||
* 创建并返回一个组合式的登出成功处理器。
|
||||
*
|
||||
* 使用解析器和上下文来决定最终使用的登出成功策略。
|
||||
*
|
||||
* @param resolver 登录请求解析器
|
||||
* @param context 登出成功处理上下文
|
||||
* @return 初始化好的 CompositeLogoutSuccessHandler 实例
|
||||
*/
|
||||
@Bean(name = ["logoutSuccessHandler"])
|
||||
fun compositeLogoutSuccessHandler(
|
||||
resolver: CompositeLoginRequestResolver,
|
||||
context: LogoutSuccessHandlerContext,
|
||||
) = CompositeLogoutSuccessHandler(resolver, context)
|
||||
|
||||
/**
|
||||
* 创建并返回一个认证异常处理器。
|
||||
*
|
||||
* 当用户未认证或认证失败时,通过此处理器响应客户端。
|
||||
*
|
||||
* @param objectMapper JSON 序列化工具
|
||||
* @param properties 安全认证属性配置
|
||||
* @return 初始化好的 AuthenticationExceptionHandler 实例
|
||||
*/
|
||||
@Bean
|
||||
fun authenticationExceptionHandler(
|
||||
objectMapper: ObjectMapper,
|
||||
properties: SecurityAuthenticateProperties,
|
||||
): AuthenticationEntryPoint = AuthenticationExceptionHandler(objectMapper, properties)
|
||||
|
||||
/**
|
||||
* 创建并返回一个认证管理器。
|
||||
*
|
||||
* 使用一组 AuthenticationProvider 来支持多种认证方式。
|
||||
*
|
||||
* @param authenticationProviders 所有可用的认证提供者
|
||||
* @return 初始化好的 ProviderManager 实例
|
||||
*/
|
||||
@Bean(name = ["authenticationManager"])
|
||||
@Primary
|
||||
fun authenticationManager(
|
||||
authenticationProviders: List<AuthenticationProvider>,
|
||||
): AuthenticationManager = ProviderManager(authenticationProviders)
|
||||
|
||||
/**
|
||||
* 创建并返回一个认证成功处理的上下文。
|
||||
*
|
||||
* 根据当前请求上下文动态选择合适的认证成功策略。
|
||||
*
|
||||
* @param strategies 所有可用的 AuthenticationSuccessStrategy 实例列表
|
||||
* @return 初始化好的 AuthenticationSuccessHandlerContext 实例
|
||||
*/
|
||||
@Bean
|
||||
fun authenticationSuccessHandlerContext(
|
||||
strategies: List<AuthenticationSuccessStrategy>,
|
||||
) = AuthenticationSuccessHandlerContext(strategies)
|
||||
|
||||
/**
|
||||
* 创建并返回一个组合式的认证成功处理器。
|
||||
*
|
||||
* 委托给具体的策略实现来进行响应。
|
||||
*
|
||||
* @param resolver 登录请求解析器
|
||||
* @param context 认证成功处理上下文
|
||||
* @return 初始化好的 CompositeAuthenticationSuccessHandler 实例
|
||||
*/
|
||||
@Bean(name = ["authenticationSuccessHandler"])
|
||||
fun authenticationSuccessHandler(
|
||||
resolver: CompositeLoginRequestResolver,
|
||||
context: AuthenticationSuccessHandlerContext,
|
||||
): AuthenticationSuccessHandler = CompositeAuthenticationSuccessHandler(resolver, context)
|
||||
|
||||
/**
|
||||
* 创建并返回一个认证失败处理的上下文。
|
||||
*
|
||||
* 根据当前请求上下文动态选择合适的认证失败策略。
|
||||
*
|
||||
* @param strategies 所有可用的 AuthenticationFailureStrategy 实例列表
|
||||
* @return 初始化好的 AuthenticationFailureHandlerContext 实例
|
||||
*/
|
||||
@Bean
|
||||
fun authenticationFailureHandlerContext(
|
||||
strategies: List<AuthenticationFailureStrategy>,
|
||||
) = AuthenticationFailureHandlerContext(strategies)
|
||||
|
||||
/**
|
||||
* 创建并返回一个组合式的认证失败处理器。
|
||||
*
|
||||
* 委托给具体的策略实现来进行响应。
|
||||
*
|
||||
* @param resolver 登录请求解析器
|
||||
* @param context 认证失败处理上下文
|
||||
* @return 初始化好的 CompositeAuthenticationFailureHandler 实例
|
||||
*/
|
||||
@Bean(name = ["authenticationFailureHandler"])
|
||||
fun authenticationFailureHandler(
|
||||
resolver: CompositeLoginRequestResolver,
|
||||
context: AuthenticationFailureHandlerContext,
|
||||
): AuthenticationFailureHandler = CompositeAuthenticationFailureHandler(resolver, context)
|
||||
|
||||
/**
|
||||
* 创建并返回一个登录请求转换上下文。
|
||||
*
|
||||
* 用于根据当前请求上下文动态选择合适的登录请求转换逻辑。
|
||||
*
|
||||
* @param applicationContext Spring 应用上下文
|
||||
* @return 初始化好的 LoginRequestConverterContext 实例
|
||||
*/
|
||||
@Bean
|
||||
fun loginRequestConverterContext(
|
||||
applicationContext: ApplicationContext,
|
||||
) = LoginRequestConverterContext(applicationContext)
|
||||
|
||||
/**
|
||||
* 创建并返回一个统一的身份验证过滤器。
|
||||
*
|
||||
* 该过滤器是整个认证流程的核心,处理登录请求并触发相应的成功/失败处理器。
|
||||
*
|
||||
* @param properties 安全认证属性配置
|
||||
* @param authenticationManager 认证管理器
|
||||
* @param authenticationSuccessHandler 成功认证处理器
|
||||
* @param authenticationFailureHandler 失败认证处理器
|
||||
* @param compositeLoginRequestResolver 组合登录请求解析器
|
||||
* @param loginRequestConverterContext 登录请求转换上下文
|
||||
* @return 初始化好的 UnifiedAuthenticationFilter 实例
|
||||
*/
|
||||
@Bean
|
||||
fun unifiedAuthenticationFilter(
|
||||
properties: SecurityAuthenticateProperties,
|
||||
authenticationManager: AuthenticationManager,
|
||||
authenticationSuccessHandler: AuthenticationSuccessHandler,
|
||||
authenticationFailureHandler: AuthenticationFailureHandler,
|
||||
compositeLoginRequestResolver: CompositeLoginRequestResolver,
|
||||
loginRequestConverterContext: LoginRequestConverterContext,
|
||||
): UnifiedAuthenticationFilter =
|
||||
UnifiedAuthenticationFilter(
|
||||
AntPathRequestMatcher(
|
||||
properties.baseUrl + properties.loginUrl,
|
||||
properties.loginHttpMethod
|
||||
),
|
||||
authenticationManager,
|
||||
authenticationSuccessHandler,
|
||||
authenticationFailureHandler,
|
||||
compositeLoginRequestResolver,
|
||||
loginRequestConverterContext
|
||||
)
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ComponentScan(
|
||||
basePackages = [
|
||||
"com.gewuyou.forgeboot.security.authenticate.impl.strategy.impl",
|
||||
"com.gewuyou.forgeboot.security.authenticate.impl.provider.impl",
|
||||
]
|
||||
)
|
||||
class ForgeBootDefaultSecurityAuthenticateAutoConfiguration
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于支持登录过滤器扩展器排序
|
||||
*
|
||||
* 通过 order 属性为 LoginFilterCustomizer 提供排序能力,确保其按预期顺序执行。
|
||||
*/
|
||||
interface OrderedLoginFilterCustomizer : LoginFilterCustomizer {
|
||||
val order: Int
|
||||
}
|
||||
@ -0,0 +1,256 @@
|
||||
package com.gewuyou.forgeboot.security.authenticate.autoconfigure
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.gewuyou.forgeboot.security.authenticate.api.config.SecurityAuthenticateProperties
|
||||
import com.gewuyou.forgeboot.security.authenticate.api.registry.LoginRequestTypeRegistry
|
||||
import com.gewuyou.forgeboot.security.authenticate.api.resolver.LoginRequestResolver
|
||||
import com.gewuyou.forgeboot.security.authenticate.api.service.UserCacheService
|
||||
import com.gewuyou.forgeboot.security.authenticate.api.strategy.AuthenticationFailureStrategy
|
||||
import com.gewuyou.forgeboot.security.authenticate.api.strategy.AuthenticationSuccessStrategy
|
||||
import com.gewuyou.forgeboot.security.authenticate.api.strategy.LogoutSuccessStrategy
|
||||
import com.gewuyou.forgeboot.security.authenticate.impl.filter.UnifiedAuthenticationFilter
|
||||
import com.gewuyou.forgeboot.security.authenticate.impl.handler.AuthenticationExceptionHandler
|
||||
import com.gewuyou.forgeboot.security.authenticate.impl.handler.CompositeAuthenticationFailureHandler
|
||||
import com.gewuyou.forgeboot.security.authenticate.impl.handler.CompositeAuthenticationSuccessHandler
|
||||
import com.gewuyou.forgeboot.security.authenticate.impl.handler.CompositeLogoutSuccessHandler
|
||||
import com.gewuyou.forgeboot.security.authenticate.impl.registry.SimpleLoginRequestTypeRegistry
|
||||
import com.gewuyou.forgeboot.security.authenticate.impl.resolver.CompositeLoginRequestResolver
|
||||
import com.gewuyou.forgeboot.security.authenticate.impl.strategy.context.AuthenticationFailureHandlerContext
|
||||
import com.gewuyou.forgeboot.security.authenticate.impl.strategy.context.AuthenticationSuccessHandlerContext
|
||||
import com.gewuyou.forgeboot.security.authenticate.impl.strategy.context.LoginRequestConverterContext
|
||||
import com.gewuyou.forgeboot.security.authenticate.impl.strategy.context.LogoutSuccessHandlerContext
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
|
||||
import org.springframework.context.ApplicationContext
|
||||
import org.springframework.context.annotation.Bean
|
||||
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.core.userdetails.UserDetails
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
|
||||
import org.springframework.security.crypto.password.PasswordEncoder
|
||||
import org.springframework.security.web.AuthenticationEntryPoint
|
||||
import org.springframework.security.web.authentication.AuthenticationFailureHandler
|
||||
import org.springframework.security.web.authentication.AuthenticationSuccessHandler
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher
|
||||
|
||||
/**
|
||||
*安全核心自动配置
|
||||
*
|
||||
* @since 2025-06-27 07:54:04
|
||||
* @author gewuyou
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
class SecurityCoreAutoConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
fun bCryptPasswordEncoder(): PasswordEncoder {
|
||||
return BCryptPasswordEncoder()
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
fun nullUserCacheService(): UserCacheService {
|
||||
return object : UserCacheService {
|
||||
override fun getUserFromCache(principal: String): UserDetails? {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun putUserToCache(userDetails: UserDetails) {
|
||||
//ignore
|
||||
}
|
||||
|
||||
override fun removeUserFromCache(principal: String) {
|
||||
//ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建并返回一个登录请求类型注册器。
|
||||
*
|
||||
* 用于注册和管理不同类型的登录请求,确保系统中所有登录方式能够被统一识别和处理。
|
||||
* 如果上下文中不存在该类型的 Bean,则会使用默认实现 SimpleLoginRequestTypeRegistry。
|
||||
*
|
||||
* @return 实现 LoginRequestTypeRegistry 接口的 Bean 实例
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
fun loginRequestTypeRegistry(): LoginRequestTypeRegistry {
|
||||
return SimpleLoginRequestTypeRegistry()
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建并返回一个组合式的登录请求解析器。
|
||||
*
|
||||
* 将多个 LoginRequestResolver 实现组合成一个统一的接口调用入口。
|
||||
*
|
||||
* @param resolvers 所有可用的 LoginRequestResolver 实例列表
|
||||
* @return 组合后的 CompositeLoginRequestResolver 实例
|
||||
*/
|
||||
@Bean
|
||||
fun compositeLoginRequestResolver(
|
||||
resolvers: List<LoginRequestResolver>,
|
||||
) = CompositeLoginRequestResolver(resolvers)
|
||||
|
||||
/**
|
||||
* 创建并返回一个登出成功处理的上下文实例。
|
||||
*
|
||||
* 用于根据注册的策略动态选择合适的 LogoutSuccessStrategy。
|
||||
*
|
||||
* @param strategies 所有可用的 LogoutSuccessStrategy 实例列表
|
||||
* @return 初始化好的 LogoutSuccessHandlerContext 实例
|
||||
*/
|
||||
@Bean
|
||||
fun logoutSuccessHandlerContext(
|
||||
strategies: List<LogoutSuccessStrategy>,
|
||||
) = LogoutSuccessHandlerContext(strategies)
|
||||
|
||||
/**
|
||||
* 创建并返回一个组合式的登出成功处理器。
|
||||
*
|
||||
* 使用解析器和上下文来决定最终使用的登出成功策略。
|
||||
*
|
||||
* @param resolver 登录请求解析器
|
||||
* @param context 登出成功处理上下文
|
||||
* @return 初始化好的 CompositeLogoutSuccessHandler 实例
|
||||
*/
|
||||
@Bean(name = ["logoutSuccessHandler"])
|
||||
fun compositeLogoutSuccessHandler(
|
||||
resolver: CompositeLoginRequestResolver,
|
||||
context: LogoutSuccessHandlerContext,
|
||||
) = CompositeLogoutSuccessHandler(resolver, context)
|
||||
|
||||
/**
|
||||
* 创建并返回一个认证异常处理器。
|
||||
*
|
||||
* 当用户未认证或认证失败时,通过此处理器响应客户端。
|
||||
*
|
||||
* @param objectMapper JSON 序列化工具
|
||||
* @param properties 安全认证属性配置
|
||||
* @return 初始化好的 AuthenticationExceptionHandler 实例
|
||||
*/
|
||||
@Bean
|
||||
fun authenticationExceptionHandler(
|
||||
objectMapper: ObjectMapper,
|
||||
properties: SecurityAuthenticateProperties,
|
||||
): AuthenticationEntryPoint = AuthenticationExceptionHandler(objectMapper, properties)
|
||||
|
||||
/**
|
||||
* 创建并返回一个认证管理器。
|
||||
*
|
||||
* 使用一组 AuthenticationProvider 来支持多种认证方式。
|
||||
*
|
||||
* @param authenticationProviders 所有可用的认证提供者
|
||||
* @return 初始化好的 ProviderManager 实例
|
||||
*/
|
||||
@Bean(name = ["authenticationManager"])
|
||||
@Primary
|
||||
fun authenticationManager(
|
||||
authenticationProviders: List<AuthenticationProvider>,
|
||||
): AuthenticationManager = ProviderManager(authenticationProviders)
|
||||
|
||||
/**
|
||||
* 创建并返回一个认证成功处理的上下文。
|
||||
*
|
||||
* 根据当前请求上下文动态选择合适的认证成功策略。
|
||||
*
|
||||
* @param strategies 所有可用的 AuthenticationSuccessStrategy 实例列表
|
||||
* @return 初始化好的 AuthenticationSuccessHandlerContext 实例
|
||||
*/
|
||||
@Bean
|
||||
fun authenticationSuccessHandlerContext(
|
||||
strategies: List<AuthenticationSuccessStrategy>,
|
||||
) = AuthenticationSuccessHandlerContext(strategies)
|
||||
|
||||
/**
|
||||
* 创建并返回一个组合式的认证成功处理器。
|
||||
*
|
||||
* 委托给具体的策略实现来进行响应。
|
||||
*
|
||||
* @param resolver 登录请求解析器
|
||||
* @param context 认证成功处理上下文
|
||||
* @return 初始化好的 CompositeAuthenticationSuccessHandler 实例
|
||||
*/
|
||||
@Bean(name = ["authenticationSuccessHandler"])
|
||||
fun authenticationSuccessHandler(
|
||||
resolver: CompositeLoginRequestResolver,
|
||||
context: AuthenticationSuccessHandlerContext,
|
||||
): AuthenticationSuccessHandler = CompositeAuthenticationSuccessHandler(resolver, context)
|
||||
|
||||
/**
|
||||
* 创建并返回一个认证失败处理的上下文。
|
||||
*
|
||||
* 根据当前请求上下文动态选择合适的认证失败策略。
|
||||
*
|
||||
* @param strategies 所有可用的 AuthenticationFailureStrategy 实例列表
|
||||
* @return 初始化好的 AuthenticationFailureHandlerContext 实例
|
||||
*/
|
||||
@Bean
|
||||
fun authenticationFailureHandlerContext(
|
||||
strategies: List<AuthenticationFailureStrategy>,
|
||||
) = AuthenticationFailureHandlerContext(strategies)
|
||||
|
||||
/**
|
||||
* 创建并返回一个组合式的认证失败处理器。
|
||||
*
|
||||
* 委托给具体的策略实现来进行响应。
|
||||
*
|
||||
* @param resolver 登录请求解析器
|
||||
* @param context 认证失败处理上下文
|
||||
* @return 初始化好的 CompositeAuthenticationFailureHandler 实例
|
||||
*/
|
||||
@Bean(name = ["authenticationFailureHandler"])
|
||||
fun authenticationFailureHandler(
|
||||
resolver: CompositeLoginRequestResolver,
|
||||
context: AuthenticationFailureHandlerContext,
|
||||
): AuthenticationFailureHandler = CompositeAuthenticationFailureHandler(resolver, context)
|
||||
|
||||
/**
|
||||
* 创建并返回一个登录请求转换上下文。
|
||||
*
|
||||
* 用于根据当前请求上下文动态选择合适的登录请求转换逻辑。
|
||||
*
|
||||
* @param applicationContext Spring 应用上下文
|
||||
* @return 初始化好的 LoginRequestConverterContext 实例
|
||||
*/
|
||||
@Bean
|
||||
fun loginRequestConverterContext(
|
||||
applicationContext: ApplicationContext,
|
||||
) = LoginRequestConverterContext(applicationContext)
|
||||
|
||||
/**
|
||||
* 创建并返回一个统一的身份验证过滤器。
|
||||
*
|
||||
* 该过滤器是整个认证流程的核心,处理登录请求并触发相应的成功/失败处理器。
|
||||
*
|
||||
* @param properties 安全认证属性配置
|
||||
* @param authenticationManager 认证管理器
|
||||
* @param authenticationSuccessHandler 成功认证处理器
|
||||
* @param authenticationFailureHandler 失败认证处理器
|
||||
* @param compositeLoginRequestResolver 组合登录请求解析器
|
||||
* @param loginRequestConverterContext 登录请求转换上下文
|
||||
* @return 初始化好的 UnifiedAuthenticationFilter 实例
|
||||
*/
|
||||
@Bean
|
||||
fun unifiedAuthenticationFilter(
|
||||
properties: SecurityAuthenticateProperties,
|
||||
authenticationManager: AuthenticationManager,
|
||||
authenticationSuccessHandler: AuthenticationSuccessHandler,
|
||||
authenticationFailureHandler: AuthenticationFailureHandler,
|
||||
compositeLoginRequestResolver: CompositeLoginRequestResolver,
|
||||
loginRequestConverterContext: LoginRequestConverterContext,
|
||||
): UnifiedAuthenticationFilter =
|
||||
UnifiedAuthenticationFilter(
|
||||
AntPathRequestMatcher(
|
||||
properties.baseUrl + properties.loginUrl,
|
||||
properties.loginHttpMethod
|
||||
),
|
||||
authenticationManager,
|
||||
authenticationSuccessHandler,
|
||||
authenticationFailureHandler,
|
||||
compositeLoginRequestResolver,
|
||||
loginRequestConverterContext
|
||||
)
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
package com.gewuyou.forgeboot.security.authenticate.autoconfigure
|
||||
|
||||
import com.gewuyou.forgeboot.security.authenticate.api.service.UserCacheService
|
||||
import com.gewuyou.forgeboot.security.authenticate.impl.provider.impl.UsernamePasswordAuthenticationProvider
|
||||
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
|
||||
import org.springframework.security.core.userdetails.UserDetailsService
|
||||
import org.springframework.security.crypto.password.PasswordEncoder
|
||||
|
||||
/**
|
||||
*安全提供程序自动配置
|
||||
*
|
||||
* @since 2025-06-26 22:33:53
|
||||
* @author gewuyou
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
class SecurityProviderAutoConfiguration {
|
||||
@Bean("usernamePasswordAuthenticationProvider")
|
||||
@ConditionalOnMissingBean
|
||||
fun usernamePasswordAuthenticationProvider(
|
||||
userCacheService: UserCacheService,
|
||||
userDetailsService: UserDetailsService,
|
||||
passwordEncoder: PasswordEncoder
|
||||
): AuthenticationProvider {
|
||||
return UsernamePasswordAuthenticationProvider(
|
||||
userCacheService,
|
||||
userDetailsService,
|
||||
passwordEncoder
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,91 @@
|
||||
package com.gewuyou.forgeboot.security.authenticate.autoconfigure
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.gewuyou.forgeboot.security.authenticate.api.config.SecurityAuthenticateProperties
|
||||
import com.gewuyou.forgeboot.security.authenticate.api.strategy.AuthenticationFailureStrategy
|
||||
import com.gewuyou.forgeboot.security.authenticate.api.strategy.AuthenticationSuccessStrategy
|
||||
import com.gewuyou.forgeboot.security.authenticate.api.strategy.LoginRequestConverterStrategy
|
||||
import com.gewuyou.forgeboot.security.authenticate.api.strategy.LogoutSuccessStrategy
|
||||
import com.gewuyou.forgeboot.security.authenticate.impl.strategy.impl.DefaultAuthenticationFailureStrategy
|
||||
import com.gewuyou.forgeboot.security.authenticate.impl.strategy.impl.DefaultAuthenticationSuccessStrategy
|
||||
import com.gewuyou.forgeboot.security.authenticate.impl.strategy.impl.DefaultLogoutSuccessStrategy
|
||||
import com.gewuyou.forgeboot.security.authenticate.impl.strategy.impl.UsernamePasswordLoginRequestConverterStrategy
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
|
||||
/**
|
||||
* 安全策略自动配置类
|
||||
*
|
||||
* 该类定义了多个Bean用于注册认证相关的策略实现,确保系统中存在默认的安全策略处理逻辑。
|
||||
* 所有Bean都使用@ConditionalOnMissingBean注解,表示只有在没有手动定义相应Bean时才会创建默认实例。
|
||||
*
|
||||
* @since 2025-06-27 08:02:26
|
||||
* @author gewuyou
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
class SecurityStrategyAutoConfiguration {
|
||||
|
||||
/**
|
||||
* 创建默认的认证成功策略Bean
|
||||
*
|
||||
* 如果上下文中不存在AuthenticationSuccessStrategy类型的Bean,则注册一个默认的实现。
|
||||
* 依赖于ObjectMapper用于序列化/反序列化操作。
|
||||
*
|
||||
* @param objectMapper Jackson的ObjectMapper实例,用于处理JSON数据
|
||||
* @return 默认的认证成功策略实例
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
fun defaultAuthenticationSuccessStrategy(objectMapper: ObjectMapper): AuthenticationSuccessStrategy {
|
||||
return DefaultAuthenticationSuccessStrategy(objectMapper)
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建默认的认证失败策略Bean
|
||||
*
|
||||
* 如果上下文中不存在AuthenticationFailureStrategy类型的Bean,则注册一个默认的实现。
|
||||
* 依赖于ObjectMapper和SecurityAuthenticateProperties,用于定制失败响应和配置参数。
|
||||
*
|
||||
* @param objectMapper Jackson的ObjectMapper实例,用于处理JSON数据
|
||||
* @param properties 安全认证相关配置属性,用于定制行为
|
||||
* @return 默认的认证失败策略实例
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
fun defaultAuthenticationFailureStrategy(
|
||||
objectMapper: ObjectMapper,
|
||||
properties: SecurityAuthenticateProperties
|
||||
): AuthenticationFailureStrategy {
|
||||
return DefaultAuthenticationFailureStrategy(objectMapper, properties)
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建默认的登出成功策略Bean
|
||||
*
|
||||
* 如果上下文中不存在LogoutSuccessStrategy类型的Bean,则注册一个默认的实现。
|
||||
* 依赖于ObjectMapper用于序列化/反序列化操作。
|
||||
*
|
||||
* @param objectMapper Jackson的ObjectMapper实例,用于处理JSON数据
|
||||
* @return 默认的登出成功策略实例
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
fun defaultLogoutSuccessStrategy(objectMapper: ObjectMapper): LogoutSuccessStrategy {
|
||||
return DefaultLogoutSuccessStrategy(objectMapper)
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建默认的登录请求转换策略Bean
|
||||
*
|
||||
* 如果上下文中不存在LoginRequestConverterStrategy类型的Bean,则注册一个基于用户名密码的默认实现。
|
||||
* 该Bean指定了名称"usernamePasswordLoginRequestConverterStrategy",以便通过名称引用。
|
||||
*
|
||||
* @return 默认的登录请求转换策略实例
|
||||
*/
|
||||
@Bean("usernamePasswordLoginRequestConverterStrategy")
|
||||
@ConditionalOnMissingBean
|
||||
fun defaultLoginRequestConverterStrategy(): LoginRequestConverterStrategy {
|
||||
return UsernamePasswordLoginRequestConverterStrategy()
|
||||
}
|
||||
}
|
||||
@ -1 +1,4 @@
|
||||
com.gewuyou.forgeboot.security.authenticate.autoconfigure.SecurityAuthenticateAutoConfiguration
|
||||
com.gewuyou.forgeboot.security.authenticate.autoconfigure.SecurityProviderAutoConfiguration
|
||||
com.gewuyou.forgeboot.security.authenticate.autoconfigure.SecurityStrategyAutoConfiguration
|
||||
com.gewuyou.forgeboot.security.authenticate.autoconfigure.SecurityCoreAutoConfiguration
|
||||
@ -0,0 +1,42 @@
|
||||
package com.gewuyou.forgeboot.security.authenticate.impl.controller
|
||||
|
||||
import com.gewuyou.forgeboot.security.authenticate.api.service.DualTokenAuthenticationService
|
||||
import com.gewuyou.forgeboot.security.authenticate.api.spec.DualTokenAuthenticationControllerSpec
|
||||
import com.gewuyou.forgeboot.security.core.common.constants.SecurityConstants
|
||||
import com.gewuyou.forgeboot.security.core.common.entities.TokenPair
|
||||
import com.gewuyou.forgeboot.webmvc.dto.R
|
||||
import org.springframework.web.bind.annotation.PostMapping
|
||||
import org.springframework.web.bind.annotation.RequestHeader
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
|
||||
/**
|
||||
*双令牌身份验证控制器
|
||||
*
|
||||
* @since 2025-06-26 20:40:12
|
||||
* @author gewuyou
|
||||
*/
|
||||
@RestController
|
||||
class DualTokenAuthenticationController(
|
||||
private val dualTokenAuthenticationService: DualTokenAuthenticationService,
|
||||
): DualTokenAuthenticationControllerSpec {
|
||||
/**
|
||||
* 刷新访问令牌
|
||||
*
|
||||
* 当访问令牌过期时,通过有效刷新令牌获取一组新的令牌对。
|
||||
* 此方法应校验刷新令牌的有效性,并生成新访问令牌。
|
||||
* 根据实现策略,刷新令牌也可能被更新并返回。
|
||||
*
|
||||
* @param accessToken 过期的访问令牌(通常通过 Authorization 头或请求体传入)
|
||||
* @param refreshToken 有效刷新令牌(用于验证并生成新令牌)
|
||||
* @return 包含新令牌对的响应对象,通常包括新访问令牌和可能更新刷新令牌
|
||||
*/
|
||||
@PostMapping("/auth/refresh")
|
||||
override fun refresh(
|
||||
@RequestHeader(SecurityConstants.AUTHORIZATION_HEADER)
|
||||
accessToken: String,
|
||||
@RequestHeader(SecurityConstants.REFRESH_TOKEN_HEADER)
|
||||
refreshToken: String,
|
||||
): R<TokenPair> {
|
||||
return R.success(dualTokenAuthenticationService.refreshTokenPair(accessToken, refreshToken))
|
||||
}
|
||||
}
|
||||
@ -3,12 +3,10 @@ package com.gewuyou.forgeboot.security.authenticate.impl.provider
|
||||
|
||||
import com.gewuyou.forgeboot.security.authenticate.api.exception.ForgeBootAuthenticationException
|
||||
import com.gewuyou.forgeboot.security.authenticate.api.service.UserCacheService
|
||||
import com.gewuyou.forgeboot.security.authenticate.api.service.UserDetailsService
|
||||
import com.gewuyou.forgeboot.security.authenticate.impl.constants.ForgeBootSecurityAuthenticationResponseInformation
|
||||
import org.springframework.security.authentication.AuthenticationProvider
|
||||
import org.springframework.security.core.Authentication
|
||||
import org.springframework.security.core.AuthenticationException
|
||||
|
||||
import org.springframework.security.core.userdetails.UserDetails
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
|
||||
@ -21,7 +19,6 @@ import java.util.concurrent.atomic.AtomicBoolean
|
||||
*/
|
||||
abstract class AbstractPrincipalCredentialsAuthenticationProvider(
|
||||
private val userCacheService: UserCacheService,
|
||||
private val userDetailsService: UserDetailsService
|
||||
) : AuthenticationProvider {
|
||||
|
||||
/**
|
||||
@ -79,19 +76,7 @@ abstract class AbstractPrincipalCredentialsAuthenticationProvider(
|
||||
* @return UserDetails 用户详细信息
|
||||
* @throws ForgeBootAuthenticationException 当 principal 为空或加载失败时抛出异常
|
||||
*/
|
||||
protected open fun retrieveUser(principal: String): UserDetails {
|
||||
if (principal.isBlank()) {
|
||||
ForgeBootAuthenticationException(ForgeBootSecurityAuthenticationResponseInformation.PRINCIPAL_NOT_PROVIDED)
|
||||
}
|
||||
return try {
|
||||
userDetailsService.loadUserByPrincipal(principal)
|
||||
} catch (e: Exception) {
|
||||
throw ForgeBootAuthenticationException(
|
||||
ForgeBootSecurityAuthenticationResponseInformation.INTERNAL_SERVER_ERROR,
|
||||
e
|
||||
)
|
||||
}
|
||||
}
|
||||
abstract fun retrieveUser(principal: String): UserDetails
|
||||
|
||||
/**
|
||||
* 在验证凭据前进行账户状态检查
|
||||
@ -127,7 +112,8 @@ abstract class AbstractPrincipalCredentialsAuthenticationProvider(
|
||||
* @throws ForgeBootAuthenticationException 当凭证为 null 时抛出异常
|
||||
*/
|
||||
protected fun checkCredentialsNotNull(credentials: Any?) {
|
||||
credentials ?: ForgeBootAuthenticationException(ForgeBootSecurityAuthenticationResponseInformation.PASSWORD_NOT_PROVIDED)
|
||||
credentials
|
||||
?: ForgeBootAuthenticationException(ForgeBootSecurityAuthenticationResponseInformation.PASSWORD_NOT_PROVIDED)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -157,6 +143,6 @@ abstract class AbstractPrincipalCredentialsAuthenticationProvider(
|
||||
*/
|
||||
protected abstract fun createSuccessAuthentication(
|
||||
authentication: Authentication,
|
||||
user: UserDetails
|
||||
user: UserDetails,
|
||||
): Authentication
|
||||
}
|
||||
|
||||
@ -2,12 +2,12 @@ package com.gewuyou.forgeboot.security.authenticate.impl.provider.impl
|
||||
|
||||
import com.gewuyou.forgeboot.security.authenticate.api.exception.ForgeBootAuthenticationException
|
||||
import com.gewuyou.forgeboot.security.authenticate.api.service.UserCacheService
|
||||
import com.gewuyou.forgeboot.security.authenticate.api.service.UserDetailsService
|
||||
import com.gewuyou.forgeboot.security.authenticate.impl.constants.ForgeBootSecurityAuthenticationResponseInformation
|
||||
import com.gewuyou.forgeboot.security.authenticate.impl.provider.AbstractPrincipalCredentialsAuthenticationProvider
|
||||
import com.gewuyou.forgeboot.security.core.common.token.UsernamePasswordAuthenticationToken
|
||||
import org.springframework.security.core.Authentication
|
||||
import org.springframework.security.core.userdetails.UserDetails
|
||||
import org.springframework.security.core.userdetails.UserDetailsService
|
||||
import org.springframework.security.crypto.password.PasswordEncoder
|
||||
|
||||
/**
|
||||
@ -25,9 +25,9 @@ import org.springframework.security.crypto.password.PasswordEncoder
|
||||
*/
|
||||
class UsernamePasswordAuthenticationProvider(
|
||||
userCacheService: UserCacheService,
|
||||
userDetailsService: UserDetailsService,
|
||||
private val userDetailsService: UserDetailsService,
|
||||
private val passwordEncoder: PasswordEncoder
|
||||
) : AbstractPrincipalCredentialsAuthenticationProvider(userCacheService, userDetailsService) {
|
||||
) : AbstractPrincipalCredentialsAuthenticationProvider(userCacheService) {
|
||||
|
||||
/**
|
||||
* 验证用户提供的凭证是否有效。
|
||||
@ -74,4 +74,25 @@ class UsernamePasswordAuthenticationProvider(
|
||||
override fun supports(authentication: Class<*>): Boolean {
|
||||
return UsernamePasswordAuthenticationToken::class.java.isAssignableFrom(authentication)
|
||||
}
|
||||
|
||||
/**
|
||||
* 从数据源获取用户信息
|
||||
*
|
||||
* @param principal 用户标识
|
||||
* @return UserDetails 用户详细信息
|
||||
* @throws ForgeBootAuthenticationException 当 principal 为空或加载失败时抛出异常
|
||||
*/
|
||||
override fun retrieveUser(principal: String): UserDetails {
|
||||
if (principal.isBlank()) {
|
||||
ForgeBootAuthenticationException(ForgeBootSecurityAuthenticationResponseInformation.PRINCIPAL_NOT_PROVIDED)
|
||||
}
|
||||
return try {
|
||||
userDetailsService.loadUserByUsername(principal)
|
||||
} catch (e: Exception) {
|
||||
throw ForgeBootAuthenticationException(
|
||||
ForgeBootSecurityAuthenticationResponseInformation.INTERNAL_SERVER_ERROR,
|
||||
e
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,69 @@
|
||||
package com.gewuyou.forgeboot.security.authenticate.impl.registry
|
||||
|
||||
import com.gewuyou.forgeboot.security.authenticate.api.registry.LoginRequestTypeRegistry
|
||||
import com.gewuyou.forgeboot.security.core.authenticate.entities.request.LoginRequest
|
||||
|
||||
/**
|
||||
* 简单登录请求类型注册表
|
||||
*
|
||||
* 用于管理不同登录类型的请求类映射关系,支持动态注册和获取登录请求类型。
|
||||
*
|
||||
* 示例代码(Kotlin):
|
||||
* ```kt
|
||||
* @Bean
|
||||
* fun loginRequestTypeRegistry(): LoginRequestTypeRegistry {
|
||||
* return LoginRequestTypeRegistry().apply {
|
||||
* register("default", DefaultLoginRequest::class.java)
|
||||
* register("sms", SmsLoginRequest::class.java)
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* 示例代码(Java):
|
||||
* ```java
|
||||
* @Bean
|
||||
* public LoginRequestTypeRegistry loginRequestTypeRegistry() {
|
||||
* return new DefaultLoginRequestTypeRegistry()
|
||||
* .register("default", DefaultLoginRequest.class)
|
||||
* .register("sms", SmsLoginRequest.class);
|
||||
* }
|
||||
* ```
|
||||
* ⚠️ 注意:此注册表不是线程安全的,建议仅用于应用启动期间进行注册,不适合运行时动态变更
|
||||
* @since 2025-06-10 16:33:43
|
||||
* @author gewuyou
|
||||
*/
|
||||
class SimpleLoginRequestTypeRegistry : LoginRequestTypeRegistry {
|
||||
|
||||
/**
|
||||
* 内部使用可变Map保存登录类型与对应LoginRequest子类的映射关系
|
||||
*/
|
||||
private val mapping = mutableMapOf<String, Class<out LoginRequest>>()
|
||||
|
||||
/**
|
||||
* 注册指定登录类型对应的请求类
|
||||
*
|
||||
* 此方法允许将特定的登录类型字符串与相应的LoginRequest实现类进行绑定,
|
||||
* 以便后续可以通过登录类型标识符动态解析出对应的请求类。
|
||||
*
|
||||
* @param loginType 登录类型的标识字符串
|
||||
* @param clazz 继承自LoginRequest的具体请求类
|
||||
* @return 返回当前注册表实例,以支持链式调用
|
||||
*/
|
||||
override fun register(loginType: String, clazz: Class<out LoginRequest>): LoginRequestTypeRegistry {
|
||||
mapping[loginType] = clazz
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据登录类型获取对应的请求类
|
||||
*
|
||||
* 此方法用于查找之前通过register方法注册的登录类型所对应的LoginRequest子类。
|
||||
* 如果未找到匹配的登录类型,则返回null。
|
||||
*
|
||||
* @param loginType 登录类型的标识字符串
|
||||
* @return 返回对应的LoginRequest子类,若未找到则返回null
|
||||
*/
|
||||
override fun getTypeForLoginType(loginType: String): Class<out LoginRequest>? {
|
||||
return mapping[loginType]
|
||||
}
|
||||
}
|
||||
@ -22,7 +22,7 @@ abstract class AbstractHandlerContext<T : Any, H : Any>(
|
||||
/**
|
||||
* 提取策略对应类型的函数,用于确定每个策略的标识
|
||||
*/
|
||||
extractType: (T) -> String,
|
||||
extractType: (T) -> Set<String>,
|
||||
/**
|
||||
* 提取策略对应处理器的函数,用于获取实际可执行的处理器逻辑
|
||||
*/
|
||||
@ -41,22 +41,21 @@ abstract class AbstractHandlerContext<T : Any, H : Any>(
|
||||
val map = mutableMapOf<String, H>()
|
||||
for (strategy in strategies) {
|
||||
// 提取当前策略的登录类型标识
|
||||
val loginType = extractType(strategy)
|
||||
if (loginType == LoginTypes.DEFAULT) {
|
||||
val loginTypes = extractType(strategy)
|
||||
if (loginTypes.contains(LoginTypes.DEFAULT)) {
|
||||
defaultStrategy = strategy
|
||||
continue
|
||||
}
|
||||
// 获取当前策略对应的处理器实例
|
||||
val handler = extractHandler(strategy)
|
||||
// 检查是否已存在相同类型的处理器
|
||||
val existingHandlerName = map[loginType]?.javaClass?.name
|
||||
existingHandlerName?.let {
|
||||
log.warn("重复注册登录类型 [$loginType] 的$typeName,已存在 $existingHandlerName,被 ${strategy::class.java.name} 覆盖")
|
||||
}?.run {
|
||||
log.info("注册${typeName}策略: $loginType -> ${strategy::class.java.name}")
|
||||
log.info("注册${typeName}策略: $loginTypes -> ${strategy::class.java.name}")
|
||||
loginTypes.forEach { loginType ->
|
||||
if (map.containsKey(loginType)) {
|
||||
log.warn("已存在 loginType 为 [$loginType] 的$typeName,将覆盖")
|
||||
}
|
||||
// 注册或覆盖处理器映射
|
||||
map[loginType] = handler
|
||||
}
|
||||
// 注册或覆盖处理器映射
|
||||
map[loginType] = handler
|
||||
}
|
||||
// 不可变化处理器映射表
|
||||
this.handlerMap = map.toMap()
|
||||
|
||||
@ -14,6 +14,6 @@ class AuthenticationFailureHandlerContext(
|
||||
) : AbstractHandlerContext<AuthenticationFailureStrategy, AuthenticationFailureHandler>(
|
||||
strategies,
|
||||
"认证失败处理器",
|
||||
{ it.supportedLoginType() },
|
||||
{ it.supportedLoginTypes() },
|
||||
{ it }
|
||||
)
|
||||
@ -15,6 +15,6 @@ class AuthenticationSuccessHandlerContext(
|
||||
strategies,
|
||||
"认证成功处理器"
|
||||
,
|
||||
{ it.supportedLoginType() },
|
||||
{ it.supportedLoginTypes() },
|
||||
{ it }
|
||||
)
|
||||
@ -14,6 +14,6 @@ class LogoutSuccessHandlerContext(
|
||||
) : AbstractHandlerContext<LogoutSuccessStrategy, LogoutSuccessHandler>(
|
||||
strategies,
|
||||
"登出处理器",
|
||||
{ it.supportedLoginType() },
|
||||
{ it.supportedLoginTypes() },
|
||||
{ it }
|
||||
)
|
||||
@ -4,7 +4,6 @@ import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.gewuyou.forgeboot.security.authenticate.api.config.SecurityAuthenticateProperties
|
||||
import com.gewuyou.forgeboot.security.authenticate.api.enums.LoginTypes
|
||||
import com.gewuyou.forgeboot.security.authenticate.impl.strategy.AbstractAuthenticationFailureStrategy
|
||||
import org.springframework.stereotype.Component
|
||||
|
||||
/**
|
||||
*默认身份验证失败策略
|
||||
@ -12,7 +11,6 @@ import org.springframework.stereotype.Component
|
||||
* @since 2025-06-14 20:26:46
|
||||
* @author gewuyou
|
||||
*/
|
||||
@Component("defaultAuthenticationFailureStrategy")
|
||||
class DefaultAuthenticationFailureStrategy(
|
||||
objectMapper: ObjectMapper,
|
||||
properties: SecurityAuthenticateProperties
|
||||
@ -20,9 +18,13 @@ class DefaultAuthenticationFailureStrategy(
|
||||
/**
|
||||
* 获取当前策略支持的登录类型标识符。
|
||||
*
|
||||
* @return 返回当前策略支持的登录类型字符串
|
||||
* 此方法用于判断当前身份验证策略能够处理的登录请求类型。
|
||||
* 例如:可以基于不同的认证方式(如密码、短信验证码、OAuth等)进行区分。
|
||||
*
|
||||
* @return 返回当前策略支持的登录类型字符串集合
|
||||
* 集合中的每个字符串代表一种支持的登录类型标识符
|
||||
*/
|
||||
override fun supportedLoginType(): String {
|
||||
return LoginTypes.DEFAULT
|
||||
override fun supportedLoginTypes(): Set<String> {
|
||||
return setOf(LoginTypes.DEFAULT)
|
||||
}
|
||||
}
|
||||
@ -3,7 +3,6 @@ package com.gewuyou.forgeboot.security.authenticate.impl.strategy.impl
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.gewuyou.forgeboot.security.authenticate.api.enums.LoginTypes
|
||||
import com.gewuyou.forgeboot.security.authenticate.impl.strategy.AbstractAuthenticationSuccessStrategy
|
||||
import org.springframework.stereotype.Component
|
||||
|
||||
/**
|
||||
* 默认身份验证成功策略
|
||||
@ -15,17 +14,15 @@ import org.springframework.stereotype.Component
|
||||
* @since 2025-06-12 22:13:42
|
||||
* @author gewuyou
|
||||
*/
|
||||
@Component("defaultAuthenticationSuccessStrategy")
|
||||
class DefaultAuthenticationSuccessStrategy(
|
||||
objectMapper: ObjectMapper,
|
||||
) : AbstractAuthenticationSuccessStrategy(objectMapper) {
|
||||
/**
|
||||
* 获取当前策略支持的登录类型标识
|
||||
* 获取当前策略支持的登录类型标识符。
|
||||
*
|
||||
* 此方法返回 "default" 字符串,表示该策略适用于默认登录类型。
|
||||
* 在多策略环境下,通过此标识来匹配相应的处理逻辑。
|
||||
*
|
||||
* @return 返回支持的登录类型标识字符串
|
||||
* @return 返回当前策略支持的登录类型字符串
|
||||
*/
|
||||
override fun supportedLoginType(): String = LoginTypes.DEFAULT
|
||||
override fun supportedLoginTypes(): Set<String> {
|
||||
return setOf(LoginTypes.DEFAULT)
|
||||
}
|
||||
}
|
||||
@ -3,25 +3,30 @@ package com.gewuyou.forgeboot.security.authenticate.impl.strategy.impl
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.gewuyou.forgeboot.security.authenticate.api.enums.LoginTypes
|
||||
import com.gewuyou.forgeboot.security.authenticate.impl.strategy.AbstractLogoutSuccessStrategy
|
||||
import org.springframework.stereotype.Component
|
||||
|
||||
/**
|
||||
*默认注销成功策略
|
||||
* 默认注销成功策略
|
||||
*
|
||||
* 该类实现了一个默认的注销成功处理策略,用于在用户成功注销时执行相关逻辑。
|
||||
* 继承自 [AbstractLogoutSuccessStrategy],并使用 [objectMapper] 进行 JSON 处理。
|
||||
*
|
||||
* @property objectMapper 用于序列化/反序列化的 Jackson ObjectMapper 实例
|
||||
* @since 2025-06-14 20:38:16
|
||||
* @author gewuyou
|
||||
*/
|
||||
@Component("defaultLogoutSuccessStrategy")
|
||||
class DefaultLogoutSuccessStrategy(
|
||||
objectMapper: ObjectMapper
|
||||
): AbstractLogoutSuccessStrategy(objectMapper) {
|
||||
) : AbstractLogoutSuccessStrategy(objectMapper) {
|
||||
/**
|
||||
* 获取当前策略支持的登录类型标识符。
|
||||
*
|
||||
* @return 返回当前策略支持的登录类型字符串
|
||||
* 此方法用于判断当前身份验证策略能够处理的登录请求类型。
|
||||
* 例如:可以基于不同的认证方式(如密码、短信验证码、OAuth等)进行区分。
|
||||
*
|
||||
* @return 返回当前策略支持的登录类型字符串集合
|
||||
* 集合中的每个字符串代表一种支持的登录类型标识符
|
||||
*/
|
||||
override fun supportedLoginType(): String {
|
||||
return LoginTypes.DEFAULT
|
||||
override fun supportedLoginTypes(): Set<String> {
|
||||
return setOf(LoginTypes.DEFAULT)
|
||||
}
|
||||
|
||||
}
|
||||
@ -6,14 +6,12 @@ import com.gewuyou.forgeboot.security.core.authenticate.entities.request.LoginRe
|
||||
import com.gewuyou.forgeboot.security.core.authenticate.entities.request.UsernamePasswordAuthenticationRequest
|
||||
import com.gewuyou.forgeboot.security.core.common.token.UsernamePasswordAuthenticationToken
|
||||
import org.springframework.security.core.Authentication
|
||||
import org.springframework.stereotype.Component
|
||||
|
||||
/**
|
||||
* 用户名 密码 认证 Token 转换器策略
|
||||
* @since 2025-02-15 03:25:14
|
||||
* @author gewuyou
|
||||
*/
|
||||
@Component("usernamePasswordLoginRequestConverterStrategy")
|
||||
class UsernamePasswordLoginRequestConverterStrategy : LoginRequestConverterStrategy {
|
||||
/**
|
||||
* 转换登录请求为认证对象
|
||||
@ -22,7 +20,7 @@ class UsernamePasswordLoginRequestConverterStrategy : LoginRequestConverterStrat
|
||||
*/
|
||||
override fun convert(loginRequest: LoginRequest): Authentication {
|
||||
if (loginRequest is UsernamePasswordAuthenticationRequest) {
|
||||
return UsernamePasswordAuthenticationToken.Companion.unauthenticated(loginRequest.username, loginRequest.password)
|
||||
return UsernamePasswordAuthenticationToken.unauthenticated(loginRequest.username, loginRequest.password)
|
||||
}
|
||||
throw IllegalArgumentException("Unsupported login request type: ${loginRequest.javaClass.name}")
|
||||
}
|
||||
|
||||
@ -0,0 +1,19 @@
|
||||
package com.gewuyou.forgeboot.security.core.common.entities
|
||||
|
||||
/**
|
||||
* 令牌对
|
||||
*
|
||||
* 该类用于封装访问令牌和刷新令牌及其有效期
|
||||
*
|
||||
* @property accessToken 访问令牌,用于身份验证
|
||||
* @property refreshToken 刷新令牌,用于获取新访问令牌
|
||||
* @property expiresIn 访问令牌的有效期,单位为秒
|
||||
*
|
||||
* @since 2025-06-16 13:28:33
|
||||
* @author gewuyou
|
||||
*/
|
||||
data class TokenPair(
|
||||
val accessToken: String,
|
||||
val refreshToken: String,
|
||||
val expiresIn: Long
|
||||
)
|
||||
Loading…
x
Reference in New Issue
Block a user