使用反向代理 现有后台集成 Spring Boot Admin

1,082 阅读2分钟

Spring Boot Admin是用于管理和监控 Spring Boot 应用程序的开源项目。

但是想要把它集成到现有的后台不是很方便,SBA是一个独立的应用,如果想要在后台访问需要开放端口,并且想要查看更多的监控指标需要开放 /actuator/** 接口, SBA默认不需要登录,可以选择集成spring security添加登录验证,但是我想要的是直接在后台查看,而不是跳转后再次登录。

总结下来两个问题:

1、怎么样和现有后台集成

2、接入现有安全认证体系

(其实就是一个问题,怎么集成到现有后台,就好像打开一个新菜单页面,并且只有登录后才能访问)

1、反向代理

第一个问题我想到了反向代理,使用反向代理屏蔽SBA的地址,只要你不在nginx配置,其他人就无法访问SBA的默认页面

反向代理我使用了smiley-http-proxy-servlet这个开源框架,当然也有其他框架可以使用,比如Charon

这里我用smiley-http-proxy-servlet举个例子

首先引入依赖

<dependency>
    <groupId>org.mitre.dsmiley.httpproxy</groupId>
    <artifactId>smiley-http-proxy-servlet</artifactId>
    <version>1.12.1</version>
</dependency>

配置代理

import org.mitre.dsmiley.httpproxy.ProxyServlet;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.http.HttpServlet;

/**
 * @author sushengbuyu
 * @date 2022/8/2
 */
@Configuration
public class SpringBootAdminProxy {

    @Bean
    public ServletRegistrationBean<HttpServlet> servletRegistrationBean() {
        ServletRegistrationBean<HttpServlet> servletRegistrationBean = new ServletRegistrationBean<>(new ProxyServlet()
                , "/boot-admin/*");
        servletRegistrationBean.addInitParameter(ProxyServlet.P_TARGET_URI, "http://localhost:9000/boot-admin/");
        servletRegistrationBean.addInitParameter(ProxyServlet.P_LOG, "true");
        return servletRegistrationBean;
    }
}

SBA配置

server:
  port: 9000

spring:
  main:
    allow-bean-definition-overriding: true
  boot:
    admin:
      context-path: /boot-admin
      ui:
        # 本地代理地址
        public-url: http://localhost:8003/boot-admin/

后台页面配置

<template>
  <div v-loading="loading" :style="'height:'+ height">
    <iframe id="boot-admin" :src="url" frameborder="no" style="width: 100%;height: 100%" scrolling="auto" />
  </div>
</template>
<script>

import { getToken } from '@/utils/auth'

export default {
  name: 'BootAdmin',
  data() {
    return {
      height: document.documentElement.clientHeight - 94.5 + 'px;',
      loading: true,
      url: 'http://localhost:8003/boot-admin',
      html: ''
    }
  },
  created: function() {
    // 拼接token
    this.url = this.url + '?Authorization=' + getToken()
  },
  mounted: function() {
    setTimeout(() => {
      this.loading = false
    }, 100)
    const that = this
    window.onresize = function temp() {
      that.height = document.documentElement.clientHeight - 94.5 + 'px;'
    }
  }
}
</script>

访问效果

image.png

就像访问一个普通菜单一样

2、token传递,SBA添加Authorization请求头

后台页面代理里在访问SBA页面时携带了当前登录用户的token令牌,这个就是用来认证/actuator接口的

SBA需要接收令牌并且在访问 /actuator接口时 添加Authorization请求头,放入token令牌

首先,接收并存储令牌

import de.codecentric.boot.admin.server.web.client.CompositeHttpHeadersProvider;
import de.codecentric.boot.admin.server.web.client.HttpHeadersProvider;
import de.codecentric.boot.admin.server.web.client.InstanceExchangeFilterFunction;
import de.codecentric.boot.admin.server.web.client.InstanceExchangeFilterFunctions;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.List;

/**
 * @author sushengbuyu
 * @date 2022/8/2
 */
@Slf4j
@Component
public class AdminFilter implements Filter, Ordered {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        String uri = request.getRequestURI();
        if ("/boot-admin/".equals(uri)) {
            log.info("URL: {}, Authorization: {}", uri, request.getParameter("Authorization"));
            AuthHttpHeadersProvider.AUTH = request.getParameter("Authorization");
        }
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Bean
    @Order(0)
    public InstanceExchangeFilterFunction addHeadersInstanceExchangeFilter(
            List<HttpHeadersProvider> headersProviders) {
        headersProviders.add(new AuthHttpHeadersProvider());
        return InstanceExchangeFilterFunctions.addHeaders(new CompositeHttpHeadersProvider(headersProviders));
    }

    @Override
    public int getOrder() {
        return 0;
    }
}

添加自定义过滤器,拦截 /boot-admin/ 请求,获取token令牌并保存至静态变量 (这里有个问题,token只能存一个,后续待完善)

SBA添加请求头


import de.codecentric.boot.admin.server.domain.entities.Instance;
import de.codecentric.boot.admin.server.web.client.HttpHeadersProvider;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;

/**
 * 添加自定义请求头
 * @author sushengbuyu
 * @date 2022/8/2
 */
@Slf4j
public class AuthHttpHeadersProvider implements HttpHeadersProvider {

    public static String AUTH = "";

    @Override
    public HttpHeaders getHeaders(Instance instance) {
        HttpHeaders headers = new HttpHeaders();
        headers.set("Authorization", AUTH);
        return headers;
    }
}

实现SBA的HttpHeadersProvider接口,添加Authorization请求头

后台的 /actuator 接口现在可以不用放开了,SBA请求时会携带用户token过来,直接验证即可

image.png 后台登录用户访问

image.png 未登录用户访问

image.png

image.png