基于Nacos搭建SpringBootAdmin

young 534 2021-10-23

创建项目时采用的start.aliyun.com的脚手架进行依赖选择,Spring Cloud Alibaba版本为2.2.2.RELEASE,Spring Boot Admin无法监听到服务上线操作

百度查到两篇文章

https://blog.csdn.net/weixin_34143774/article/details/89551981

https://blog.csdn.net/wang_shuyu/article/details/106521497

该问题为Spring Cloud Alibaba的问题,查看GitHub上最新版本已为2.2.6.RELEASE,故将Spring Cloud Alibaba版本升级至最新版本

服务端搭建步骤

添加相关依赖

<properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot-admin.version>2.3.1</spring-boot-admin.version>
        <spring-boot.version>2.3.7.RELEASE</spring-boot.version>
        <spring-cloud-alibaba.version>2.2.6.RELEASE</spring-cloud-alibaba.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        <dependency>
            <groupId>de.codecentric</groupId>
            <artifactId>spring-boot-admin-starter-server</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring-cloud-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>de.codecentric</groupId>
                <artifactId>spring-boot-admin-dependencies</artifactId>
                <version>${spring-boot-admin.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

配置中引入了spring-cloud-starter-alibaba-nacos-config依赖

计划将注册中心相关配置全放置于配置中心,减少后续项目的重复配置

如无此计划可移除该依赖

添加注册中心及SpringBootAdmin注解

@EnableAdminServer
@EnableDiscoveryClient
@SpringBootApplication
public class BootAdminServerApplication {

添加Spring Security配置

@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 {
        // @formatter:off
        SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
        successHandler.setTargetUrlParameter("redirectTo");
        successHandler.setDefaultTargetUrl(adminContextPath + "/");

        http.authorizeRequests()
                //授予对所有静态资产和登录页面的公共访问权限。
                .antMatchers(adminContextPath + "/assets/**").permitAll()
                .antMatchers(adminContextPath + "/login").permitAll()
                //必须对每个其他请求进行身份验证
                .anyRequest().authenticated()
                .and()
                //配置登录和注销
                .formLogin().loginPage(adminContextPath + "/login").successHandler(successHandler).and()
                .logout().logoutUrl(adminContextPath + "/logout").and()
                //启用HTTP-Basic支持。这是Spring Boot Admin Client注册所必需的
                .httpBasic().and();
        // @formatter:on
    }
}

###配置application.yaml/bootstrap.yaml

如未引入spring-cloud-starter-alibaba-nacos-config依赖,可忽略config相关配置

spring:
  application:
    name: boot-admin-server
  security:
    user:
      name: young
      password: young
  cloud:
    nacos:
      discovery:
        server-addr: 10.0.16.6:8848
        metadata:
          user.name: ${spring.security.user.name}
          user.password: ${spring.security.user.password}
          management:
          	# 避免actuator访问时无context-path
            context-path: ${server.servlet.context-path}/actuator
      # 如无config配置,可忽略
      config:
        server-addr: 10.0.16.6:8848
        username: nacos
        password: nacos
        encode: UTF-8
        # 配置命名空间
        namespace: c2a45280-9955-4bbe-be51-c75ee2b8e62c
        shared-configs:
        	# 公用配置,可将discovery配置移入nacos配置中心
          - data-id: common-application.yaml
            group: common-config
            # 是否支持刷新配置,为false,修改配置后需重启才可生效
            refresh: false
        extension-configs:
          - data-id: application.yaml
            group: ${spring.application.name}
            refresh: false
          - data-id: ${spring.application.name}.yaml
            group: ${spring.application.name}
            refresh: true
management:
  endpoints:
    web:
      base-path: "/actuator"  # 配置 Endpoint 的基础路径
      exposure:
        include: '*'
  endpoint:
    health:
      show-details: always
server:
  servlet:
    context-path: /${spring.application.name}
  port: 9000

登录查看

服务启动后,访问http://localhost:9000/boot-admin-server

登录用户名密码为security配置的用户名密码

监控报警

邮件报警

引入spring-boot-starter-mail依赖,并配置相关配置即可
依赖

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

配置

spring:
  mail:
    host: smtp.163.com
    username: xxxx@163.com
    passwrod: xxxxxxxxxxxxx
  boot:
    admin:
      notify:
        mail:
          to: xxxxxx@xxx.com
          from: xxxx@163.com
          enable: true

客户端

客户端只需引入Nacos相关依赖,配置与Server端相同即可
如果要避免客户端应用的Endpoint被直接访问,可以在客户端对entpoint增加相关security配置

@Configuration
public class ActuatorSecurityConfig extends WebSecurityConfigurerAdapter {
     /*
        This spring actuator configuration does the following
        1. Restrict access to the Shutdown endpoint to the ACTUATOR_ADMIN role.
        2. Allow access to all other actuator endpoints.
        3. Allow access to static resources.
        4. Allow access to the home page (/).
        5. All other requests need to be authenticated.
        5. Enable http basic authentication to make the configuration complete.
           You are free to use any other form of authentication.
     */

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable()
                .authorizeRequests()
                .requestMatchers(EndpointRequest.to(ShutdownEndpoint.class))
                .authenticated()
                .requestMatchers(EndpointRequest.toAnyEndpoint())
                .authenticated()
                .requestMatchers(PathRequest.toStaticResources().atCommonLocations())
                .permitAll()
                .antMatchers("/")
                .permitAll()
                .antMatchers("/**")
                .permitAll()
                .and()
                .httpBasic();
    }
}