diff --git a/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/config/AuthorizationServerConfiguration.java b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/config/AuthorizationServerConfiguration.java index 232cfd298..7ecb8f149 100644 --- a/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/config/AuthorizationServerConfiguration.java +++ b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/config/AuthorizationServerConfiguration.java @@ -33,7 +33,6 @@ import com.pig4cloud.pigx.common.core.constant.SecurityConstants; import com.pig4cloud.pigx.common.security.handler.FormAuthenticationFailureHandler; import com.pig4cloud.pigx.common.security.handler.SsoLogoutSuccessHandler; import lombok.RequiredArgsConstructor; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.Ordered; @@ -57,7 +56,6 @@ import org.springframework.security.web.authentication.AuthenticationFailureHand import org.springframework.security.web.authentication.DelegatingAuthenticationConverter; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; -import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import java.util.Arrays; @@ -79,38 +77,35 @@ public class AuthorizationServerConfiguration { @Bean @Order(Ordered.HIGHEST_PRECEDENCE) - @ConditionalOnProperty(value = "security.micro", matchIfMissing = true) public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http, PigxAuthenticationSuccessEventHandler successEventHandler, PigxAuthenticationFailureEventHandler failureEventHandler) throws Exception { + // 配置授权服务器的安全策略,只有/oauth2/**的请求才会走如下的配置 + http.securityMatcher("/oauth2/**"); + OAuth2AuthorizationServerConfigurer authorizationServerConfigurer = new OAuth2AuthorizationServerConfigurer(); + // 增加验证码过滤器 http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class); // 增加密码解密过滤器 http.addFilterBefore(passwordDecoderFilter, UsernamePasswordAuthenticationFilter.class); - OAuth2AuthorizationServerConfigurer authorizationServerConfigurer = new OAuth2AuthorizationServerConfigurer(); http.with(authorizationServerConfigurer.tokenEndpoint((tokenEndpoint) -> {// 个性化认证授权端点 - tokenEndpoint.accessTokenRequestConverter(accessTokenRequestConverter()) // 注入自定义的授权认证Converter - .accessTokenResponseHandler(successEventHandler) // 登录成功处理器 - .errorResponseHandler(failureEventHandler);// 登录失败处理器 - }).clientAuthentication(oAuth2ClientAuthenticationConfigurer -> // 个性化客户端认证 - oAuth2ClientAuthenticationConfigurer.errorResponseHandler(failureEventHandler))// 处理客户端认证异常 - .authorizationEndpoint(authorizationEndpoint -> authorizationEndpoint// 授权码端点个性化confirm页面 - .consentPage(SecurityConstants.CUSTOM_CONSENT_PAGE_URI)), Customizer.withDefaults()); + tokenEndpoint.accessTokenRequestConverter(accessTokenRequestConverter()) // 注入自定义的授权认证Converter + .accessTokenResponseHandler(successEventHandler) // 登录成功处理器 + .errorResponseHandler(failureEventHandler);// 登录失败处理器 + }).clientAuthentication(oAuth2ClientAuthenticationConfigurer -> // 个性化客户端认证 + oAuth2ClientAuthenticationConfigurer.errorResponseHandler(failureEventHandler))// 处理客户端认证异常 + .authorizationEndpoint(authorizationEndpoint -> authorizationEndpoint// 授权码端点个性化confirm页面 + .consentPage(SecurityConstants.CUSTOM_CONSENT_PAGE_URI)), Customizer.withDefaults()) + .authorizeHttpRequests(authorizeRequests -> authorizeRequests.anyRequest().authenticated()); - AntPathRequestMatcher[] requestMatchers = new AntPathRequestMatcher[]{ - AntPathRequestMatcher.antMatcher("/token/**"), AntPathRequestMatcher.antMatcher("/actuator/**"), - AntPathRequestMatcher.antMatcher("/code/**"), AntPathRequestMatcher.antMatcher("/css/**"), - AntPathRequestMatcher.antMatcher("/error")}; - - http.authorizeHttpRequests(authorizeRequests -> { - // 自定义接口、端点暴露 - authorizeRequests.requestMatchers(requestMatchers).permitAll(); - authorizeRequests.anyRequest().authenticated(); - }) - .with(authorizationServerConfigurer.authorizationService(authorizationService)// redis存储token的实现 + // 设置 Token 存储的策略 + http.with(authorizationServerConfigurer.authorizationService(authorizationService)// redis存储token的实现 .authorizationServerSettings( - AuthorizationServerSettings.builder().issuer(SecurityConstants.PIGX_LICENSE).build()), Customizer.withDefaults()); + AuthorizationServerSettings.builder().issuer(SecurityConstants.PIGX_LICENSE).build()), + Customizer.withDefaults()); + + // 设置授权码模式登录页面 http.with(new FormIdentityLoginConfigurer(), Customizer.withDefaults()); DefaultSecurityFilterChain securityFilterChain = http.build(); diff --git a/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/support/core/FormIdentityLoginConfigurer.java b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/support/core/FormIdentityLoginConfigurer.java index 0d790965b..d0d3c92cd 100644 --- a/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/support/core/FormIdentityLoginConfigurer.java +++ b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/support/core/FormIdentityLoginConfigurer.java @@ -9,28 +9,26 @@ import org.springframework.security.config.annotation.web.configurers.AbstractHt /** * @author lengleng * @data 2022-06-04 - * + *

* 基于授权码模式 统一认证登录 spring security & sas 都可以使用 所以抽取成 HttpConfigurer */ public final class FormIdentityLoginConfigurer - extends AbstractHttpConfigurer { + extends AbstractHttpConfigurer { - @Override - public void init(HttpSecurity http) throws Exception { - http.formLogin(formLogin -> { - formLogin.loginPage("/token/login"); - formLogin.loginProcessingUrl("/token/form"); - formLogin.failureHandler(new FormAuthenticationFailureHandler()); - formLogin.successHandler(new TenantSavedRequestAwareAuthenticationSuccessHandler()); + @Override + public void init(HttpSecurity http) throws Exception { + http.formLogin(formLogin -> { + formLogin.loginPage("/token/login"); + formLogin.loginProcessingUrl("/oauth2/form"); + formLogin.failureHandler(new FormAuthenticationFailureHandler()); + formLogin.successHandler(new TenantSavedRequestAwareAuthenticationSuccessHandler()); + }) + .logout(logout -> logout.logoutUrl("/oauth2/logout") + .logoutSuccessHandler(new SsoLogoutSuccessHandler()) + .deleteCookies("JSESSIONID") + .invalidateHttpSession(true)) // SSO登出成功处理 - }) - .logout() // SSO登出成功处理 - .logoutSuccessHandler(new SsoLogoutSuccessHandler()) - .deleteCookies("JSESSIONID") - .invalidateHttpSession(true) - .and() - .csrf() - .disable(); - } + .csrf(AbstractHttpConfigurer::disable); + } } diff --git a/pigx-boot/src/main/java/com/pig4cloud/pigx/bootstrap/PigxBootSecurityServerConfiguration.java b/pigx-boot/src/main/java/com/pig4cloud/pigx/bootstrap/PigxBootSecurityServerConfiguration.java deleted file mode 100644 index a492354f3..000000000 --- a/pigx-boot/src/main/java/com/pig4cloud/pigx/bootstrap/PigxBootSecurityServerConfiguration.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * - * Copyright (c) 2018-2025, lengleng All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * Neither the name of the pig4cloud.com developer nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * Author: lengleng (wangiegie@gmail.com) - * - */ - -package com.pig4cloud.pigx.bootstrap; - -import com.pig4cloud.pigx.auth.support.core.PigxDaoAuthenticationProvider; -import com.pig4cloud.pigx.auth.support.filter.PasswordDecoderFilter; -import com.pig4cloud.pigx.auth.support.filter.ValidateCodeFilter; -import com.pig4cloud.pigx.auth.support.handler.PigxAuthenticationFailureEventHandler; -import com.pig4cloud.pigx.auth.support.handler.PigxAuthenticationSuccessEventHandler; -import com.pig4cloud.pigx.auth.support.password.OAuth2ResourceOwnerPasswordAuthenticationProvider; -import com.pig4cloud.pigx.auth.support.sms.OAuth2ResourceOwnerSmsAuthenticationProvider; -import com.pig4cloud.pigx.common.core.constant.SecurityConstants; -import com.pig4cloud.pigx.common.security.component.PermitAllUrlProperties; -import com.pig4cloud.pigx.common.security.component.ResourceAuthExceptionEntryPoint; -import lombok.RequiredArgsConstructor; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.Ordered; -import org.springframework.core.annotation.Order; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.config.Customizer; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; -import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer; -import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService; -import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer; -import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings; -import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenGenerator; -import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector; -import org.springframework.security.web.DefaultSecurityFilterChain; -import org.springframework.security.web.SecurityFilterChain; -import org.springframework.security.web.authentication.AuthenticationConverter; -import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; -import org.springframework.security.web.util.matcher.AntPathRequestMatcher; - -/** - * @author lengleng 认证授权服务器配置 - */ -@Configuration -@RequiredArgsConstructor -public class PigxBootSecurityServerConfiguration { - - private final ResourceAuthExceptionEntryPoint resourceAuthExceptionEntryPoint; - - private final OpaqueTokenIntrospector customOpaqueTokenIntrospector; - - private final AuthenticationConverter accessTokenRequestConverter; - - private final OAuth2AuthorizationService authorizationService; - - private final PasswordDecoderFilter passwordDecoderFilter; - - private final OAuth2TokenGenerator oAuth2TokenGenerator; - - private final ValidateCodeFilter validateCodeFilter; - - private final PermitAllUrlProperties permitAllUrl; - - @Bean - @Order(Ordered.HIGHEST_PRECEDENCE) - public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http, - PigxAuthenticationSuccessEventHandler successEventHandler, - PigxAuthenticationFailureEventHandler failureEventHandler) throws Exception { - OAuth2AuthorizationServerConfigurer authorizationServerConfigurer = new OAuth2AuthorizationServerConfigurer(); - - // 增加验证码过滤器 - http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class); - // 增加密码解密过滤器 - http.addFilterBefore(passwordDecoderFilter, UsernamePasswordAuthenticationFilter.class); - - // 认证服务器配置 - http.with(authorizationServerConfigurer.tokenEndpoint((tokenEndpoint) -> {// 个性化认证授权端点 - tokenEndpoint.accessTokenRequestConverter(accessTokenRequestConverter) // 注入自定义的授权认证Converter - .accessTokenResponseHandler(successEventHandler) // 登录成功处理器 - .errorResponseHandler(failureEventHandler);// 登录失败处理器 - }).clientAuthentication(oAuth2ClientAuthenticationConfigurer -> // 个性化客户端认证 - oAuth2ClientAuthenticationConfigurer.errorResponseHandler(failureEventHandler))// 处理客户端认证异常 - , Customizer.withDefaults()) - .with(authorizationServerConfigurer.authorizationService(authorizationService)// redis存储token的实现 - .authorizationServerSettings( - AuthorizationServerSettings.builder().issuer(SecurityConstants.PIGX_LICENSE).build()), - Customizer.withDefaults()); - - // 资源服务器配置 - AntPathRequestMatcher[] requestMatchers = permitAllUrl.getIgnoreUrls() - .stream() - .map(AntPathRequestMatcher::new) - .toList() - .toArray(new AntPathRequestMatcher[]{}); - - http.authorizeHttpRequests(authorizeRequests -> authorizeRequests.requestMatchers(requestMatchers) - .permitAll() - .anyRequest() - .authenticated()) - .oauth2ResourceServer( - oauth2 -> oauth2.opaqueToken(token -> token.introspector(customOpaqueTokenIntrospector)) - .authenticationEntryPoint(resourceAuthExceptionEntryPoint)) - .exceptionHandling(configurer -> configurer.authenticationEntryPoint(resourceAuthExceptionEntryPoint)) - .headers(headers -> headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable)) - .csrf(AbstractHttpConfigurer::disable); - - http.with(authorizationServerConfigurer.authorizationService(authorizationService)// redis存储token的实现 - .authorizationServerSettings( - AuthorizationServerSettings.builder().issuer(SecurityConstants.PIGX_LICENSE).build()), - Customizer.withDefaults()); - - DefaultSecurityFilterChain securityFilterChain = http.build(); - - // 注入自定义授权模式实现 - addCustomOAuth2GrantAuthenticationProvider(http); - return securityFilterChain; - } - - /** - * 注入授权模式实现提供方 - *

- * 1. 密码模式
- * 2. 短信登录
- */ - @SuppressWarnings("unchecked") - private void addCustomOAuth2GrantAuthenticationProvider(HttpSecurity http) { - AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManager.class); - OAuth2AuthorizationService authorizationService = http.getSharedObject(OAuth2AuthorizationService.class); - - OAuth2ResourceOwnerPasswordAuthenticationProvider resourceOwnerPasswordAuthenticationProvider = new OAuth2ResourceOwnerPasswordAuthenticationProvider( - authenticationManager, authorizationService, oAuth2TokenGenerator); - - OAuth2ResourceOwnerSmsAuthenticationProvider resourceOwnerSmsAuthenticationProvider = new OAuth2ResourceOwnerSmsAuthenticationProvider( - authenticationManager, authorizationService, oAuth2TokenGenerator); - - // 处理 UsernamePasswordAuthenticationToken - http.authenticationProvider(new PigxDaoAuthenticationProvider()); - // 处理 OAuth2ResourceOwnerPasswordAuthenticationToken - http.authenticationProvider(resourceOwnerPasswordAuthenticationProvider); - // 处理 OAuth2ResourceOwnerSmsAuthenticationToken - http.authenticationProvider(resourceOwnerSmsAuthenticationProvider); - } - -}