Browse Source

feat:【infra】spring boot admin 默认需要登录

YunaiV 6 months ago
parent
commit
88f322311e

+ 98 - 0
yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/monitor/config/AdminServerConfiguration.java

@@ -1,9 +1,107 @@
 package cn.iocoder.yudao.module.infra.framework.monitor.config;
 
 import de.codecentric.boot.admin.server.config.EnableAdminServer;
+import jakarta.servlet.DispatcherType;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
+import org.springframework.core.annotation.Order;
+import org.springframework.security.config.Customizer;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.core.userdetails.User;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.provisioning.InMemoryUserDetailsManager;
+import org.springframework.security.web.SecurityFilterChain;
+import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
+import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
 
+/**
+ * Spring Boot Admin Server 配置
+ *
+ * 包含 Admin Server 的启用配置和安全配置
+ * 安全配置独立于 {@link cn.iocoder.yudao.framework.security.config.YudaoWebSecurityConfigurerAdapter},
+ * 使用 HTTP Basic 认证保护 Admin Server 端点,不影响现有的 Token 认证机制
+ *
+ * @author 芋道源码
+ */
 @Configuration(proxyBeanMethods = false)
 @EnableAdminServer
+@ConditionalOnClass(name = "de.codecentric.boot.admin.server.config.AdminServerProperties") // 目的:按需启动 spring boot admin 监控服务
 public class AdminServerConfiguration {
+
+    @Value("${spring.boot.admin.context-path:''}")
+    private String adminSeverContextPath;
+
+    @Value("${spring.boot.admin.client.username:admin}")
+    private String username;
+
+    @Value("${spring.boot.admin.client.password:admin}")
+    private String password;
+
+    /**
+     * Spring Boot Admin 专用的 InMemoryUserDetailsManager
+     * 使用内存存储,与系统用户隔离
+     */
+    @Bean("adminUserDetailsManager")
+    public InMemoryUserDetailsManager adminUserDetailsManager(PasswordEncoder passwordEncoder) {
+        UserDetails adminUser = User.builder()
+                .username(username)
+                .password(passwordEncoder.encode(password))
+                .roles("ADMIN_SERVER")
+                .build();
+        return new InMemoryUserDetailsManager(adminUser);
+    }
+
+    /**
+     * Spring Boot Admin Server 的 SecurityFilterChain
+     * 使用 @Order(1) 确保优先于默认的 SecurityFilterChain 匹配
+     */
+    @Bean("adminServerSecurityFilterChain")
+    @Order(1)
+    public SecurityFilterChain adminServerSecurityFilterChain(HttpSecurity httpSecurity,
+                                                               InMemoryUserDetailsManager adminUserDetailsManager) throws Exception {
+        // 登录成功后的处理器
+        SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
+        successHandler.setTargetUrlParameter("redirectTo");
+        successHandler.setDefaultTargetUrl(adminSeverContextPath + "/");
+
+        // 配置 HttpSecurity 对象
+        httpSecurity
+                // 仅匹配 Admin Server 的路径
+                .securityMatcher(adminSeverContextPath + "/**")
+                // 使用独立的 UserDetailsManager
+                .userDetailsService(adminUserDetailsManager)
+                // 授权配置
+                .authorizeHttpRequests(auth -> auth
+                        .requestMatchers(adminSeverContextPath + "/assets/**").permitAll() // 静态资源允许匿名访问
+                        .requestMatchers(adminSeverContextPath + "/login").permitAll() // 登录页面允许匿名访问
+                        .dispatcherTypeMatchers(DispatcherType.ASYNC).permitAll() // 异步请求允许
+                        .anyRequest().authenticated() // 其他请求需要认证
+                )
+                // 表单登录配置(用于 Admin UI 访问)
+                .formLogin(form -> form
+                        .loginPage(adminSeverContextPath + "/login")
+                        .successHandler(successHandler)
+                        .permitAll()
+                )
+                // 登出配置
+                .logout(logout -> logout
+                        .logoutUrl(adminSeverContextPath + "/logout")
+                        .logoutSuccessUrl(adminSeverContextPath + "/login")
+                )
+                // HTTP Basic 认证(用于 Admin Client 注册)
+                .httpBasic(Customizer.withDefaults())
+                // CSRF 配置
+                .csrf(csrf -> csrf
+                        .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
+                        .ignoringRequestMatchers(
+                                adminSeverContextPath + "/instances", // Admin Client 注册端点忽略 CSRF
+                                adminSeverContextPath + "/actuator/**" // Actuator 端点忽略 CSRF
+                        )
+                );
+        return httpSecurity.build();
+    }
+
 }

+ 0 - 7
yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/security/config/SecurityConfiguration.java

@@ -1,7 +1,6 @@
 package cn.iocoder.yudao.module.infra.framework.security.config;
 
 import cn.iocoder.yudao.framework.security.config.AuthorizeRequestsCustomizer;
-import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.security.config.annotation.web.builders.HttpSecurity;
@@ -13,9 +12,6 @@ import org.springframework.security.config.annotation.web.configurers.AuthorizeH
 @Configuration(proxyBeanMethods = false, value = "infraSecurityConfiguration")
 public class SecurityConfiguration {
 
-    @Value("${spring.boot.admin.context-path:''}")
-    private String adminSeverContextPath;
-
     @Bean("infraAuthorizeRequestsCustomizer")
     public AuthorizeRequestsCustomizer authorizeRequestsCustomizer() {
         return new AuthorizeRequestsCustomizer() {
@@ -32,9 +28,6 @@ public class SecurityConfiguration {
                         .requestMatchers("/actuator/**").permitAll();
                 // Druid 监控
                 registry.requestMatchers("/druid/**").permitAll();
-                // Spring Boot Admin Server 的安全配置
-                registry.requestMatchers(adminSeverContextPath).permitAll()
-                        .requestMatchers(adminSeverContextPath + "/**").permitAll();
                 // 文件读取
                 registry.requestMatchers(buildAdminApi("/infra/file/*/get/**")).permitAll();
             }

+ 2 - 0
yudao-server/src/main/resources/application-dev.yaml

@@ -138,6 +138,8 @@ spring:
         url: http://127.0.0.1:${server.port}/${spring.boot.admin.context-path} # 设置 Spring Boot Admin Server 地址
         instance:
           service-host-type: IP # 注册实例时,优先使用 IP [IP, HOST_NAME, CANONICAL_HOST_NAME]
+        username: admin
+        password: admin
       # Spring Boot Admin Server 服务端的相关配置
       context-path: /admin # 配置 Spring
 

+ 2 - 0
yudao-server/src/main/resources/application-local.yaml

@@ -158,6 +158,8 @@ spring:
         url: http://127.0.0.1:${server.port}/${spring.boot.admin.context-path} # 设置 Spring Boot Admin Server 地址
         instance:
           service-host-type: IP # 注册实例时,优先使用 IP [IP, HOST_NAME, CANONICAL_HOST_NAME]
+        username: admin
+        password: admin
       # Spring Boot Admin Server 服务端的相关配置
       context-path: /admin # 配置 Spring