SpringBoot Admin监控Spring程序

简介: SpringBoot Admin监控Spring程序

SpringBoot Admin是开源社区孵化的项目,用于对SpringBoot应用的管理和监控。

SpringBoot Admin 分为服务端(spring-boot-admin-server)和客户端(spring-boot-admin-client),服务端和客户端之间采用http通讯方式实现数据交互;单体项目中需要整合spring-boot-admin-client才能让应用被监控。在SpringCloud项目中,spring-boot-admin-server 是直接从注册中心抓取应用信息,不需要每个微服务应用整合spring-boot-admin-client就可以实现应用的管理和监控。


测试版本:springboot2.5.9,spring-admin2.6.0,spring-security2.5.9


一、快速入门


1.1 SpringBoot Admin Server的搭建


(1)pom

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>de.codecentric</groupId>
            <artifactId>spring-boot-admin-starter-server</artifactId>
            <version>2.6.0</version>
        </dependency>


(2)yml

server:
  port: 8100 # 端口随便起
spring:
  application:
    name: spring-admin-server


(3)启动类

import de.codecentric.boot.admin.server.config.EnableAdminServer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
 * @author yh
 * @description 开启 springboot admin 服务端
 * @date 2022/6/6
 */
@EnableAdminServer
@SpringBootApplication
public class AdminServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(AdminServerApplication.class, args);
    }
}


浏览器访问测试 http://127.0.0.1:8100/

1673406133585.jpg


1.2 SpringBoot Admin Client端搭建


所谓的 client端就是指我们需要被监控的应用端。


(1)pom

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>de.codecentric</groupId>
            <artifactId>spring-boot-admin-starter-client</artifactId>
            <version>2.6.0</version>
        </dependency>


(2)application.yml配置


应用端口

开放端点用于SpringBootAdmin 监控

配置应用名称(该名称会在SpringBoot Admin的管理页面显示)

配置Admin Server的地址

配置下日志文件的文件名和存放位置 (如果不配置则会看不到日志)

server:
  port: 8101
#开放端点用于SpringBoot Admin的监控
management:
  endpoints:
    web:
      exposure:
        include: '*' #与 Spring Boot 2 一样,大多数端点默认情况下都不会通过 http 公开,我们会公开所有端点。对于生产,您应该仔细选择要公开的端点。
  info:
    env:
      enabled: true # 从 Spring Boot 2.6 开始,默认情况下禁用 env info 贡献者。因此,我们必须启用它
spring:
  application:
    name: spring-admin-client
  boot:
    admin:
      client:
        url: http://localhost:8100   #这里配置admin server 的地址
logging:
  file:
    name: admin-client.log  #配置生成日志文件名称


(3)写一个Controller模拟一个普通的接口,通过浏览器访问这个接口就会打印日志,具体代码如下

@Slf4j
@RestController
@RequestMapping("/hello")
public class HelloController {
    // 线程安全 AtomicInteger
    private AtomicInteger count = new AtomicInteger(0);
    @GetMapping("/get")
    private String hello() {
        // 每次进来如打印下日志
        log.info("{} 啪...我第{}次进来了.", LocalDateTime.now(),  count.addAndGet(1));
        // 每次进来new 个大对象,便于监控观察堆内存变化
        byte[] bytes = new byte[100*1024*1024];
        log.info("new了 100MB");
        return "hi springboot addmin " + LocalDateTime.now();
    }
}


(4)写个启动类

@SpringBootApplication
public class AdminClientApplication {
    public static void main(String[] args) {
        SpringApplication.run(AdminClientApplication.class, args);
    }
}


1.3 效果展示


当我们的admin-client项目启动后,在 admin-server的管理页面的应用墙上就能看到admin-client这个应用了,具体可参考下图

1673406199170.jpg

可查看应用的具体信息


在应用墙点击这个应用,我们可以看到这个应用的具体信息,如堆内存变化及线程数等。具体可参考下图

1673406216628.jpg

日志查看及堆内存变化观察


请求我们在admin-client中写的模拟接口 http://localhost:8010/hello/get,该接口请求一次则会输出日志,同时开辟100MB的堆内存空间。


请求多次后在网页上可以实时的看到日志如下图

1673406240268.jpg

1673406250072.jpg


二、安全性


2.1 admin-server端安全加固


这个SpringBoot Admin的管理后台如果没密码就能访问,那实在太不安全了,因此我们要给它加上登录的功能。


参考SpringBoot Admin的官方文档,我们可以在Admin-Server端添加Spring Security 相关依赖及就可以实现需要登录后才能访问网页管理面板。


官网参考链接:链接


下面开始具体的改造


(1)admin-server 添加Spring Security 相关依赖

<!--springboot admin 安全相关-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>


(2)admin-server 设置账号和密码

server:
  port: 8100
spring:
  application:
    name: spring-admin-server
  # 设置账号和密码
  security:
    user:
      name: admin
      password: 123456


(3)admin-server 添加一个Spring Security 配置类

import de.codecentric.boot.admin.server.config.AdminServerProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
  @Configuration
    public class SecuritySecureConfig extends WebSecurityConfigurerAdapter {
        private final String adminContextPath;
        public SecuritySecureConfig(AdminServerProperties adminServerProperties) {
            this.adminContextPath = adminServerProperties.getContextPath();
        }
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
            successHandler.setTargetUrlParameter("redirectTo");
            successHandler.setDefaultTargetUrl(adminContextPath + "/");
            http.authorizeRequests()
                    //1.配置所有静态资源和登录页可以公开访问
                    .antMatchers(adminContextPath + "/assets/**").permitAll()
                    .antMatchers(adminContextPath + "/login").permitAll()
                    .anyRequest().authenticated()
                    .and()
                    //2.配置登录和登出路径
                    .formLogin().loginPage(adminContextPath + "/login").successHandler(successHandler).and()
                    .logout().logoutUrl(adminContextPath + "/logout").and()
                    //3.开启http basic支持,admin-client注册时需要使用
                    .httpBasic().and()
                    .csrf()
                   //4.开启基于cookie的csrf保护
                    .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
                    //5.忽略这些路径的csrf保护以便admin-client注册
                    .ignoringAntMatchers(
                            adminContextPath + "/instances",
                            adminContextPath + "/actuator/**"
                    );
        }
    }


(4)admin-server 安全加固后访问测试


再次访问http://localhost:8100/ ,发现需要登录

1673406328867.jpg

当我们输入正确的账号密码登录后,情况如下图

1673406336407.jpg

这个时候的应用数居然变成了0了,在我们没进行安全加固时是有一个admin-client应用的,为什么就不见了?


原因是添加了账号密码认证后,admin-client端也需要配置下 admin-server的账号和密码。没配不会报错异常,只会出现WARN。。。


(5)admin-client 端设置 admin-server的账号密码


admin-client 注册到 admin-server时,admin-server端有个http Basic认证,通过了认证后 admin-client才能注册到 admin-server上。


admin-client的application.yml中配置访问密码配置可参考下面代码

spring:
  application:
    name: spring-admin-client
  boot:
    admin:
      client:
        url: http://localhost:8100   #这里配置admin server 的地址
        # 配置 admin-server的账号和密码
        username: admin
        password: 123456


(6) 再次访问 admin-server 管理后台


当我们登录后,终于再次看到了我们的admin-client这个应用

1673406356546.jpg


2.2 admin-client端的安全


admin-client端如果把actuator 端点都暴露出来,是非常不安全的。因此我们可以添加Spring Security对admin-client 也进行安全加固。


下面所有操作均在admin-client中进行


(1)添加Spring Security依赖

<!--spring security-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>


(2)yml配置


yml中需要设置client的账号和密码,官网相关配置如下图所示

1673406376520.jpg

本次演示的admin-client的相关yml配置参考下面代码

server:
  port: 8101
#开放端点用于SpringBoot Admin的监控
management:
  endpoints:
    web:
      exposure:
        include: '*'
  info:
    env:
      enabled: true
spring:
  application:
    name: spring-admin-client
  boot:
    admin:
      client:
        url: http://localhost:8100   #这里配置admin server 的地址
        # 配置 admin-server的账号和密码
        username: admin
        password: 123456
        instance:
          metadata:
            # 这里配置admin-client的账号和密码
            user.name: ${spring.security.user.name}
            user.password: ${spring.security.user.password}
  # admin-client 的用户名和密码
  security:
    user:
      name: clientAdmin
      password: 123456
logging:
  file:
    name: admin-client.log  #配置生成日志文件名称


(3)添加Spring Security 配置类


为何要到配置?因为Spring Security不配置时会把所有请求都拦截的,而我们这里只需要拦截监控端点/actuator/**即可。同时,官网中提到admin-server访问admin-client时,也是采用http Basic认证方式的;因此需要配置Spring Security支持Http Basic认证方式。

@Configuration
    @Slf4j
    public class SpringSecurityActuatorConfig extends WebSecurityConfigurerAdapter {
        public SpringSecurityActuatorConfig() {
            log.info("SpringSecurityActuatorConfig... start");
        }
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            //  这个配置只针对  /actuator/** 的请求生效
            http.antMatcher("/actuator/**")
                    // /actuator/下所有请求都要认证
                    .authorizeRequests().anyRequest().authenticated()
                    // 启用httpBasic认证模式,当springboot admin-client 配置了密码时,
                    // admin-server走httpbasic的认证方式来拉取client的信息
                    .and().httpBasic()
                    // 禁用csrf
                    .and().csrf().disable();
        }
    }


(4)效果展示


admin-server端依旧能看到admin-client的信息,说明我们添加SpringSecurity 后 admin-server的监控管理功能正常,具体见下图

1673406413288.jpg

当我们去访问admin-client的监控端点 http://localhost:8101/actuator/health 时,发现需要进行http Basic认证;这也证明了我们的认证拦截只拦截了监控端点。效果如下图

1673406422651.jpg


(5)存在的问题


通过上面的一通配置,admin-client 添加 Spring Security 对actuator的端点进行安全认证的功能是实现了,但也存在着问题。


当我们项目本来就是使用SpringSecurity 安全框架进行认证和授权时。上述的配置就要做修改了。因为我们一般都不用HttpBasic认证,而是用的表单登录认证。也就出现了配置多个Spring Security的问题。虽然有这个问题,但是网上还是有解决方案的。


(6)多个Spring Security共存方案


这个方案是在Spring Security官方文档里面找到的


链接为:Spring Security Reference


里面的重点就是通过添加Order注解来指定多个Spring Security的优先级


下面直接贴上我的代码;为了直观,我就在同一个类里面建了2个静态的Spring Security配置类

/**
 * SpringSecurity 表单和HttpBasic 共存配置参考,写在一个类里面方便对比
 */
@Slf4j
public class SpringSecurityConfig2 {
    /*
     * 这个表单和HttpBasic 共存配置玩法,参考url如下:
     *  官方url:https://docs.spring.io/spring-security/site/docs/4.2.3.BUILD-SNAPSHOT/reference/htmlsingle/#multiple-httpsecurity
     *  项目启动日志如下,可以看到创建了2条过滤链
     * 2020-11-11 22:57:56.340  INFO 12692 --- [main] o.s.s.web.DefaultSecurityFilterChain: Creating filter chain: Ant [pattern='/actuator/**'],
     * 2020-11-11 22:57:56.344  INFO 12692 --- [main] o.s.s.web.DefaultSecurityFilterChain: Creating filter chain: any request,
     */
    /**
     * HttpBasic 认证方式,只对/actuator/** 生效,由于设置了Order,优先级会高于FormLoginWebSecurityConfigurerAdapter
     * @author ZENG.XIAO.YAN
     * @Date 2020-11-11
     * @version 1.0
     */
    @Configuration
    @Order(1)
    public static class HttpBasicSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
        public HttpBasicSecurityConfigurationAdapter() {
            log.info("HttpBasicSecurityConfigurationAdapter... start");
        }
        protected void configure(HttpSecurity http) throws Exception {
            //  这个配置只针对  /actuator/** 的请求生效
            http.antMatcher("/actuator/**")
                    // /actuator/下所有请求都要认证
                    .authorizeRequests().anyRequest().authenticated()
                    // 启用httpBasic认证模式,当springboot admin-client 配置了密码时,
                    // admin-server走httpbasic的认证方式来拉取client的信息
                    .and().httpBasic()
                    // 禁用csrf
                    .and().csrf().disable();
        }
    }
    /**
     * 表单登录认证方式配置,由于没有指定Order,所以默认是最大2147483647,数值越大,优先级越低
     * @author ZENG.XIAO.YAN
     * @Date 2020-11-11
     * @version 1.0
     */
    @Configuration
    public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
        public FormLoginWebSecurityConfigurerAdapter() {
            log.info("FormLoginWebSecurityConfigurerAdapter... start");
        }
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .formLogin();
        }
    }
}


添加完这个配置类后,记得把我们上面配置的SpringSecurityActuatorConfig 这个类删除了,然后重启项目。效果如下:


访问 http://localhost:8101/actuator/health ,则出现的是httpBasic认证的页面

1673406498952.jpg

访问 http://localhost:8101/hello/get ,则出现的是Spring Security 自带的表单登录页面

1673406515801.jpg

访问admin-server 的管理页面,发现admin-client应用信息正常,说明本次修改的Spring Security配置没有问题

1673406526080.jpg


三、小结


(1)本文介绍了SpringBoot Admin的简单使用,同时介绍了admin-server端的安全配置和admin-client端的安全配置


(2)在介绍admin-client端的安全配置时,引申出了 如何实现多个SpringSecurity 配置 共存

相关实践学习
通过日志服务实现云资源OSS的安全审计
本实验介绍如何通过日志服务实现云资源OSS的安全审计。
相关文章
|
5月前
|
人工智能 运维 Java
Spring AI Alibaba Admin 开源!以数据为中心的 Agent 开发平台
Spring AI Alibaba Admin 正式发布!一站式实现 Prompt 管理、动态热更新、评测集构建、自动化评估与全链路可观测,助力企业高效构建可信赖的 AI Agent 应用。开源共建,现已上线!
6487 88
|
5月前
|
前端开发 Java 应用服务中间件
《深入理解Spring》 Spring Boot——约定优于配置的革命者
Spring Boot基于“约定优于配置”理念,通过自动配置、起步依赖、嵌入式容器和Actuator四大特性,简化Spring应用的开发与部署,提升效率,降低门槛,成为现代Java开发的事实标准。
|
5月前
|
前端开发 Java 微服务
《深入理解Spring》:Spring、Spring MVC与Spring Boot的深度解析
Spring Framework是Java生态的基石,提供IoC、AOP等核心功能;Spring MVC基于其构建,实现Web层MVC架构;Spring Boot则通过自动配置和内嵌服务器,极大简化了开发与部署。三者层层演进,Spring Boot并非替代,而是对前者的高效封装与增强,适用于微服务与快速开发,而深入理解Spring Framework有助于更好驾驭整体技术栈。
|
5月前
|
XML Java 应用服务中间件
【SpringBoot(一)】Spring的认知、容器功能讲解与自动装配原理的入门,带你熟悉Springboot中基本的注解使用
SpringBoot专栏开篇第一章,讲述认识SpringBoot、Bean容器功能的讲解、自动装配原理的入门,还有其他常用的Springboot注解!如果想要了解SpringBoot,那么就进来看看吧!
627 2
|
6月前
|
人工智能 Java 机器人
基于Spring AI Alibaba + Spring Boot + Ollama搭建本地AI对话机器人API
Spring AI Alibaba集成Ollama,基于Java构建本地大模型应用,支持流式对话、knife4j接口可视化,实现高隐私、免API密钥的离线AI服务。
5414 2
基于Spring AI Alibaba + Spring Boot + Ollama搭建本地AI对话机器人API
存储 JSON Java
767 0
|
6月前
|
人工智能 Java 开发者
【Spring】原理解析:Spring Boot 自动配置
Spring Boot通过“约定优于配置”的设计理念,自动检测项目依赖并根据这些依赖自动装配相应的Bean,从而解放开发者从繁琐的配置工作中解脱出来,专注于业务逻辑实现。
2231 0
|
6月前
|
Prometheus 监控 Java
日志收集和Spring 微服务监控的最佳实践
在微服务架构中,日志记录与监控对系统稳定性、问题排查和性能优化至关重要。本文介绍了在 Spring 微服务中实现高效日志记录与监控的最佳实践,涵盖日志级别选择、结构化日志、集中记录、服务ID跟踪、上下文信息添加、日志轮转,以及使用 Spring Boot Actuator、Micrometer、Prometheus、Grafana、ELK 堆栈等工具进行监控与可视化。通过这些方法,可提升系统的可观测性与运维效率。
619 1
日志收集和Spring 微服务监控的最佳实践
|
6月前
|
存储 安全 Java
如何在 Spring Web 应用程序中使用 @SessionScope 和 @RequestScope
Spring框架中的`@SessionScope`和`@RequestScope`注解用于管理Web应用中的状态。`@SessionScope`绑定HTTP会话生命周期,适用于用户特定数据,如购物车;`@RequestScope`限定于单个请求,适合无状态、线程安全的操作,如日志记录。合理选择作用域能提升应用性能与可维护性。
278 1