diff --git a/forgeboot-security/forgeboot-security-authenticate/api/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/api/config/SecurityAuthenticateProperties.kt b/forgeboot-security/forgeboot-security-authenticate/api/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/api/config/SecurityAuthenticateProperties.kt index fee4c05..edf328e 100644 --- a/forgeboot-security/forgeboot-security-authenticate/api/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/api/config/SecurityAuthenticateProperties.kt +++ b/forgeboot-security/forgeboot-security-authenticate/api/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/api/config/SecurityAuthenticateProperties.kt @@ -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 + } } \ No newline at end of file diff --git a/forgeboot-security/forgeboot-security-authenticate/api/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/api/customizer/OrderedLoginFilterCustomizer.kt b/forgeboot-security/forgeboot-security-authenticate/api/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/api/customizer/OrderedLoginFilterCustomizer.kt new file mode 100644 index 0000000..e8cba01 --- /dev/null +++ b/forgeboot-security/forgeboot-security-authenticate/api/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/api/customizer/OrderedLoginFilterCustomizer.kt @@ -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 +} \ No newline at end of file diff --git a/forgeboot-security/forgeboot-security-authenticate/api/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/api/registry/LoginRequestTypeRegistry.kt b/forgeboot-security/forgeboot-security-authenticate/api/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/api/registry/LoginRequestTypeRegistry.kt index 46f8ca0..61075b7 100644 --- a/forgeboot-security/forgeboot-security-authenticate/api/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/api/registry/LoginRequestTypeRegistry.kt +++ b/forgeboot-security/forgeboot-security-authenticate/api/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/api/registry/LoginRequestTypeRegistry.kt @@ -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>() +interface LoginRequestTypeRegistry { /** - * 注册指定登录类型对应的请求类 + * 注册一个新的登录类型及其对应的请求类。 * * @param loginType 登录类型的标识字符串 - * @param clazz 继承自LoginRequest的具体请求类 + * @param clazz 继承自LoginRequest的具体请求类 */ - fun register(loginType: String, clazz: Class) { - mapping[loginType] = clazz - } + fun register(loginType: String, clazz: Class): LoginRequestTypeRegistry /** - * 根据登录类型获取对应的请求类 + * 根据登录类型获取对应的请求类。 * * @param loginType 登录类型的标识字符串 - * @return 返回对应的LoginRequest子类,若未找到则返回null + * @return 返回与登录类型关联的请求类,如果未找到则返回null */ - fun getTypeForLoginType(loginType: String): Class? { - return mapping[loginType] - } + fun getTypeForLoginType(loginType: String): Class? } \ No newline at end of file diff --git a/forgeboot-security/forgeboot-security-authenticate/api/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/api/service/DualTokenAuthenticationService.kt b/forgeboot-security/forgeboot-security-authenticate/api/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/api/service/DualTokenAuthenticationService.kt new file mode 100644 index 0000000..8afa854 --- /dev/null +++ b/forgeboot-security/forgeboot-security-authenticate/api/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/api/service/DualTokenAuthenticationService.kt @@ -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 +} \ No newline at end of file diff --git a/forgeboot-security/forgeboot-security-authenticate/api/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/api/service/UserDetailsService.kt b/forgeboot-security/forgeboot-security-authenticate/api/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/api/service/UserDetailsService.kt deleted file mode 100644 index 23de456..0000000 --- a/forgeboot-security/forgeboot-security-authenticate/api/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/api/service/UserDetailsService.kt +++ /dev/null @@ -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 -} diff --git a/forgeboot-security/forgeboot-security-authenticate/api/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/api/spec/DualTokenAuthenticationControllerSpec.kt b/forgeboot-security/forgeboot-security-authenticate/api/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/api/spec/DualTokenAuthenticationControllerSpec.kt new file mode 100644 index 0000000..9cf729e --- /dev/null +++ b/forgeboot-security/forgeboot-security-authenticate/api/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/api/spec/DualTokenAuthenticationControllerSpec.kt @@ -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 +} \ No newline at end of file diff --git a/forgeboot-security/forgeboot-security-authenticate/api/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/api/strategy/AuthenticationHandlerSupportStrategy.kt b/forgeboot-security/forgeboot-security-authenticate/api/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/api/strategy/AuthenticationHandlerSupportStrategy.kt index 26ec537..57fc0ac 100644 --- a/forgeboot-security/forgeboot-security-authenticate/api/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/api/strategy/AuthenticationHandlerSupportStrategy.kt +++ b/forgeboot-security/forgeboot-security-authenticate/api/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/api/strategy/AuthenticationHandlerSupportStrategy.kt @@ -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 } \ No newline at end of file diff --git a/forgeboot-security/forgeboot-security-authenticate/autoconfigure/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/autoconfigure/SecurityAuthenticateAutoConfiguration.kt b/forgeboot-security/forgeboot-security-authenticate/autoconfigure/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/autoconfigure/SecurityAuthenticateAutoConfiguration.kt index 6efa583..bdc0559 100644 --- a/forgeboot-security/forgeboot-security-authenticate/autoconfigure/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/autoconfigure/SecurityAuthenticateAutoConfiguration.kt +++ b/forgeboot-security/forgeboot-security-authenticate/autoconfigure/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/autoconfigure/SecurityAuthenticateAutoConfiguration.kt @@ -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, - ) = CompositeLoginRequestResolver(resolvers) - - /** - * 创建并返回一个登出成功处理的上下文实例。 - * - * 用于根据注册的策略动态选择合适的 LogoutSuccessStrategy。 - * - * @param strategies 所有可用的 LogoutSuccessStrategy 实例列表 - * @return 初始化好的 LogoutSuccessHandlerContext 实例 - */ - @Bean - fun logoutSuccessHandlerContext( - strategies: List, - ) = 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, - ): AuthenticationManager = ProviderManager(authenticationProviders) - - /** - * 创建并返回一个认证成功处理的上下文。 - * - * 根据当前请求上下文动态选择合适的认证成功策略。 - * - * @param strategies 所有可用的 AuthenticationSuccessStrategy 实例列表 - * @return 初始化好的 AuthenticationSuccessHandlerContext 实例 - */ - @Bean - fun authenticationSuccessHandlerContext( - strategies: List, - ) = 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, - ) = 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 } \ No newline at end of file diff --git a/forgeboot-security/forgeboot-security-authenticate/autoconfigure/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/autoconfigure/SecurityCoreAutoConfiguration.kt b/forgeboot-security/forgeboot-security-authenticate/autoconfigure/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/autoconfigure/SecurityCoreAutoConfiguration.kt new file mode 100644 index 0000000..04f6cb1 --- /dev/null +++ b/forgeboot-security/forgeboot-security-authenticate/autoconfigure/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/autoconfigure/SecurityCoreAutoConfiguration.kt @@ -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, + ) = CompositeLoginRequestResolver(resolvers) + + /** + * 创建并返回一个登出成功处理的上下文实例。 + * + * 用于根据注册的策略动态选择合适的 LogoutSuccessStrategy。 + * + * @param strategies 所有可用的 LogoutSuccessStrategy 实例列表 + * @return 初始化好的 LogoutSuccessHandlerContext 实例 + */ + @Bean + fun logoutSuccessHandlerContext( + strategies: List, + ) = 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, + ): AuthenticationManager = ProviderManager(authenticationProviders) + + /** + * 创建并返回一个认证成功处理的上下文。 + * + * 根据当前请求上下文动态选择合适的认证成功策略。 + * + * @param strategies 所有可用的 AuthenticationSuccessStrategy 实例列表 + * @return 初始化好的 AuthenticationSuccessHandlerContext 实例 + */ + @Bean + fun authenticationSuccessHandlerContext( + strategies: List, + ) = 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, + ) = 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 + ) +} \ No newline at end of file diff --git a/forgeboot-security/forgeboot-security-authenticate/autoconfigure/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/autoconfigure/SecurityProviderAutoConfiguration.kt b/forgeboot-security/forgeboot-security-authenticate/autoconfigure/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/autoconfigure/SecurityProviderAutoConfiguration.kt new file mode 100644 index 0000000..7ba3687 --- /dev/null +++ b/forgeboot-security/forgeboot-security-authenticate/autoconfigure/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/autoconfigure/SecurityProviderAutoConfiguration.kt @@ -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 + ) + } + +} \ No newline at end of file diff --git a/forgeboot-security/forgeboot-security-authenticate/autoconfigure/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/autoconfigure/SecurityStrategyAutoConfiguration.kt b/forgeboot-security/forgeboot-security-authenticate/autoconfigure/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/autoconfigure/SecurityStrategyAutoConfiguration.kt new file mode 100644 index 0000000..36105ab --- /dev/null +++ b/forgeboot-security/forgeboot-security-authenticate/autoconfigure/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/autoconfigure/SecurityStrategyAutoConfiguration.kt @@ -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() + } +} \ No newline at end of file diff --git a/forgeboot-security/forgeboot-security-authenticate/autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/forgeboot-security/forgeboot-security-authenticate/autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports index c152b86..345f939 100644 --- a/forgeboot-security/forgeboot-security-authenticate/autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ b/forgeboot-security/forgeboot-security-authenticate/autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -1 +1,4 @@ -com.gewuyou.forgeboot.security.authenticate.autoconfigure.SecurityAuthenticateAutoConfiguration \ No newline at end of file +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 \ No newline at end of file diff --git a/forgeboot-security/forgeboot-security-authenticate/impl/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/impl/controller/DualTokenAuthenticationController.kt b/forgeboot-security/forgeboot-security-authenticate/impl/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/impl/controller/DualTokenAuthenticationController.kt new file mode 100644 index 0000000..ce87257 --- /dev/null +++ b/forgeboot-security/forgeboot-security-authenticate/impl/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/impl/controller/DualTokenAuthenticationController.kt @@ -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 { + return R.success(dualTokenAuthenticationService.refreshTokenPair(accessToken, refreshToken)) + } +} \ No newline at end of file diff --git a/forgeboot-security/forgeboot-security-authenticate/impl/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/impl/provider/AbstractPrincipalCredentialsAuthenticationProvider.kt b/forgeboot-security/forgeboot-security-authenticate/impl/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/impl/provider/AbstractPrincipalCredentialsAuthenticationProvider.kt index 94ee6a4..ad0dfa3 100644 --- a/forgeboot-security/forgeboot-security-authenticate/impl/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/impl/provider/AbstractPrincipalCredentialsAuthenticationProvider.kt +++ b/forgeboot-security/forgeboot-security-authenticate/impl/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/impl/provider/AbstractPrincipalCredentialsAuthenticationProvider.kt @@ -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 } diff --git a/forgeboot-security/forgeboot-security-authenticate/impl/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/impl/provider/impl/UsernamePasswordAuthenticationProvider.kt b/forgeboot-security/forgeboot-security-authenticate/impl/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/impl/provider/impl/UsernamePasswordAuthenticationProvider.kt index 67c67a3..a1fb41e 100644 --- a/forgeboot-security/forgeboot-security-authenticate/impl/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/impl/provider/impl/UsernamePasswordAuthenticationProvider.kt +++ b/forgeboot-security/forgeboot-security-authenticate/impl/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/impl/provider/impl/UsernamePasswordAuthenticationProvider.kt @@ -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 + ) + } + } } \ No newline at end of file diff --git a/forgeboot-security/forgeboot-security-authenticate/impl/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/impl/registry/SimpleLoginRequestTypeRegistry.kt b/forgeboot-security/forgeboot-security-authenticate/impl/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/impl/registry/SimpleLoginRequestTypeRegistry.kt new file mode 100644 index 0000000..d34d9ff --- /dev/null +++ b/forgeboot-security/forgeboot-security-authenticate/impl/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/impl/registry/SimpleLoginRequestTypeRegistry.kt @@ -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>() + + /** + * 注册指定登录类型对应的请求类 + * + * 此方法允许将特定的登录类型字符串与相应的LoginRequest实现类进行绑定, + * 以便后续可以通过登录类型标识符动态解析出对应的请求类。 + * + * @param loginType 登录类型的标识字符串 + * @param clazz 继承自LoginRequest的具体请求类 + * @return 返回当前注册表实例,以支持链式调用 + */ + override fun register(loginType: String, clazz: Class): LoginRequestTypeRegistry { + mapping[loginType] = clazz + return this + } + + /** + * 根据登录类型获取对应的请求类 + * + * 此方法用于查找之前通过register方法注册的登录类型所对应的LoginRequest子类。 + * 如果未找到匹配的登录类型,则返回null。 + * + * @param loginType 登录类型的标识字符串 + * @return 返回对应的LoginRequest子类,若未找到则返回null + */ + override fun getTypeForLoginType(loginType: String): Class? { + return mapping[loginType] + } +} \ No newline at end of file diff --git a/forgeboot-security/forgeboot-security-authenticate/impl/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/impl/strategy/context/AbstractHandlerContext.kt b/forgeboot-security/forgeboot-security-authenticate/impl/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/impl/strategy/context/AbstractHandlerContext.kt index 9b713c8..84c0d34 100644 --- a/forgeboot-security/forgeboot-security-authenticate/impl/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/impl/strategy/context/AbstractHandlerContext.kt +++ b/forgeboot-security/forgeboot-security-authenticate/impl/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/impl/strategy/context/AbstractHandlerContext.kt @@ -22,7 +22,7 @@ abstract class AbstractHandlerContext( /** * 提取策略对应类型的函数,用于确定每个策略的标识 */ - extractType: (T) -> String, + extractType: (T) -> Set, /** * 提取策略对应处理器的函数,用于获取实际可执行的处理器逻辑 */ @@ -41,22 +41,21 @@ abstract class AbstractHandlerContext( val map = mutableMapOf() 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() diff --git a/forgeboot-security/forgeboot-security-authenticate/impl/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/impl/strategy/context/AuthenticationFailureHandlerContext.kt b/forgeboot-security/forgeboot-security-authenticate/impl/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/impl/strategy/context/AuthenticationFailureHandlerContext.kt index 19d0ccd..6d62c84 100644 --- a/forgeboot-security/forgeboot-security-authenticate/impl/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/impl/strategy/context/AuthenticationFailureHandlerContext.kt +++ b/forgeboot-security/forgeboot-security-authenticate/impl/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/impl/strategy/context/AuthenticationFailureHandlerContext.kt @@ -14,6 +14,6 @@ class AuthenticationFailureHandlerContext( ) : AbstractHandlerContext( strategies, "认证失败处理器", - { it.supportedLoginType() }, + { it.supportedLoginTypes() }, { it } ) \ No newline at end of file diff --git a/forgeboot-security/forgeboot-security-authenticate/impl/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/impl/strategy/context/AuthenticationSuccessHandlerContext.kt b/forgeboot-security/forgeboot-security-authenticate/impl/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/impl/strategy/context/AuthenticationSuccessHandlerContext.kt index 3b5c3df..9cfa1bf 100644 --- a/forgeboot-security/forgeboot-security-authenticate/impl/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/impl/strategy/context/AuthenticationSuccessHandlerContext.kt +++ b/forgeboot-security/forgeboot-security-authenticate/impl/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/impl/strategy/context/AuthenticationSuccessHandlerContext.kt @@ -15,6 +15,6 @@ class AuthenticationSuccessHandlerContext( strategies, "认证成功处理器" , - { it.supportedLoginType() }, + { it.supportedLoginTypes() }, { it } ) \ No newline at end of file diff --git a/forgeboot-security/forgeboot-security-authenticate/impl/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/impl/strategy/context/LogoutSuccessHandlerContext.kt b/forgeboot-security/forgeboot-security-authenticate/impl/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/impl/strategy/context/LogoutSuccessHandlerContext.kt index bc3e8f7..250edab 100644 --- a/forgeboot-security/forgeboot-security-authenticate/impl/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/impl/strategy/context/LogoutSuccessHandlerContext.kt +++ b/forgeboot-security/forgeboot-security-authenticate/impl/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/impl/strategy/context/LogoutSuccessHandlerContext.kt @@ -14,6 +14,6 @@ class LogoutSuccessHandlerContext( ) : AbstractHandlerContext( strategies, "登出处理器", - { it.supportedLoginType() }, + { it.supportedLoginTypes() }, { it } ) \ No newline at end of file diff --git a/forgeboot-security/forgeboot-security-authenticate/impl/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/impl/strategy/impl/DefaultAuthenticationFailureStrategy.kt b/forgeboot-security/forgeboot-security-authenticate/impl/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/impl/strategy/impl/DefaultAuthenticationFailureStrategy.kt index 0e60663..9eb7794 100644 --- a/forgeboot-security/forgeboot-security-authenticate/impl/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/impl/strategy/impl/DefaultAuthenticationFailureStrategy.kt +++ b/forgeboot-security/forgeboot-security-authenticate/impl/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/impl/strategy/impl/DefaultAuthenticationFailureStrategy.kt @@ -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 { + return setOf(LoginTypes.DEFAULT) } } \ No newline at end of file diff --git a/forgeboot-security/forgeboot-security-authenticate/impl/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/impl/strategy/impl/DefaultAuthenticationSuccessStrategy.kt b/forgeboot-security/forgeboot-security-authenticate/impl/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/impl/strategy/impl/DefaultAuthenticationSuccessStrategy.kt index 9b86234..7406155 100644 --- a/forgeboot-security/forgeboot-security-authenticate/impl/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/impl/strategy/impl/DefaultAuthenticationSuccessStrategy.kt +++ b/forgeboot-security/forgeboot-security-authenticate/impl/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/impl/strategy/impl/DefaultAuthenticationSuccessStrategy.kt @@ -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 { + return setOf(LoginTypes.DEFAULT) + } } \ No newline at end of file diff --git a/forgeboot-security/forgeboot-security-authenticate/impl/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/impl/strategy/impl/DefaultLogoutSuccessStrategy.kt b/forgeboot-security/forgeboot-security-authenticate/impl/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/impl/strategy/impl/DefaultLogoutSuccessStrategy.kt index 80faba1..a06c5cc 100644 --- a/forgeboot-security/forgeboot-security-authenticate/impl/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/impl/strategy/impl/DefaultLogoutSuccessStrategy.kt +++ b/forgeboot-security/forgeboot-security-authenticate/impl/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/impl/strategy/impl/DefaultLogoutSuccessStrategy.kt @@ -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 { + return setOf(LoginTypes.DEFAULT) } - } \ No newline at end of file diff --git a/forgeboot-security/forgeboot-security-authenticate/impl/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/impl/strategy/impl/UsernamePasswordLoginRequestConverterStrategy.kt b/forgeboot-security/forgeboot-security-authenticate/impl/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/impl/strategy/impl/UsernamePasswordLoginRequestConverterStrategy.kt index 97dc324..2d449ac 100644 --- a/forgeboot-security/forgeboot-security-authenticate/impl/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/impl/strategy/impl/UsernamePasswordLoginRequestConverterStrategy.kt +++ b/forgeboot-security/forgeboot-security-authenticate/impl/src/main/kotlin/com/gewuyou/forgeboot/security/authenticate/impl/strategy/impl/UsernamePasswordLoginRequestConverterStrategy.kt @@ -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}") } diff --git a/forgeboot-security/forgeboot-security-core/src/main/kotlin/com/gewuyou/forgeboot/security/core/common/entities/TokenPair.kt b/forgeboot-security/forgeboot-security-core/src/main/kotlin/com/gewuyou/forgeboot/security/core/common/entities/TokenPair.kt new file mode 100644 index 0000000..6233489 --- /dev/null +++ b/forgeboot-security/forgeboot-security-core/src/main/kotlin/com/gewuyou/forgeboot/security/core/common/entities/TokenPair.kt @@ -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 +) \ No newline at end of file