SpringBootAdmin搭建过程

随着微服务的流行,相比较以前一个大型应用程序搞定所有需求,我们现在更倾向于把大型应用程序切分成多个微服务。而SpringBoot是微服务的基础,一个一个的微服务构成了一个错综复杂的系统,spring-boot-starter-actuator 是SpringBoot下的一个包它提供了监控接口,例如:/health、/info等等,实际上除了之前提到的信息,还有其他信息业需要监控:当前处于活跃状态的会话数量、当前应用的并发数、服务资源、延迟以及其他度量信息,精简配置。而SpringBootAdmin正是基于这些接口开发了一套功能强大的监控系统。

创建SpringBootAdmin的Server端

1.加入以下依赖

<dependency>
    <groupId>de.codecentric</groupId>
    <artifactId>spring-boot-admin-server</artifactId>
</dependency>
<dependency>
    <groupId>de.codecentric</groupId>
    <artifactId>spring-boot-admin-server-ui</artifactId>
</dependency>

2.在application中加入注解如下

@Configuration
@EnableAutoConfiguration
@EnableAdminServer
public class SpringBootAdminApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringBootAdminApplication.class, args);
    }
}

创建SpringBootAdmin的Client端

1.加入以下依赖

<dependency>
    <groupId>de.codecentric</groupId>
    <artifactId>spring-boot-admin-starter-client</artifactId>
</dependency>

client中引入很多其他包,目前用到的是 jolokia(用来添加JMX功能) 和 actuator(SpringBoot提供的监控端点所依赖的包)。

2.配置文件中添加

spring.boot.admin.url: http://localhost:8080  //要注册的服务端
management.security.enabled: false //SpringBoot 1.5以后的版本都默认开启端点保护

SpringBootAdmin的Server端也可以注册在eureka这样的管理中心上,好处是可以监控所有注册在eureka上的服务,SpringBootAdmin客户端无需再配置服务端,注册到Eureka上后,SpringBootAdmin可以定时拉取服务注册列表,无需再为服务节点配置监控中心的地址。

为监控系统添加权限保护

为server端设置登陆页面和权限

1.在server端中需要引入如下依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>de.codecentric</groupId>
    <artifactId>spring-boot-admin-server-ui</artifactId>
</dependency>
<dependency>
    <groupId>de.codecentric</groupId>
    <artifactId>spring-boot-admin-server-ui-login</artifactId>
</dependency>

2.修改配置文件

security.user.name=aa
security.user.password=aa //登陆用户名密码
security.basic.enabled=false //关掉security框架自带的登陆弹出框

3.配置config类

@Bean
    public HttpHeadersProvider httpHeadersProvider() {
        return new ServerAuthHttpHeaderProvider();
    }


    @Override
    public void configure(WebSecurity web) throws Exception {
        //忽略css.jq.img等文件
        web.ignoring().antMatchers("/**.html", "/**.css", "/img/**", "/**.js", "/third-party/**");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin().loginPage("/login.html").loginProcessingUrl("/login").permitAll().defaultSuccessUrl("/")
                .and()//Logout Form configuration
                .logout()
                .deleteCookies("remove")
                .logoutSuccessUrl("/login.html").permitAll()
                .and().authorizeRequests().antMatchers(HttpMethod.POST, "/apiapplications/").permitAll()
                .antMatchers("/health").permitAll()
                .anyRequest().authenticated()//
                .and().csrf().ignoringAntMatchers("/api/**", "/**")
                .csrfTokenRepository(csrfTokenRepository()).and()
                .addFilterAfter(csrfHeaderFilter(), CsrfFilter.class);
    }

    private Filter csrfHeaderFilter() {
        return new OncePerRequestFilter() {
            @Override
            protected void doFilterInternal(HttpServletRequest request,
                                            HttpServletResponse response, FilterChain filterChain)
                    throws ServletException, IOException {
                CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
                if (csrf != null) {
                    Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
                    String token = csrf.getToken();
                    if (cookie == null || token != null && !token.equals(cookie.getValue())) {
                        cookie = new Cookie("XSRF-TOKEN", token);
                        cookie.setPath("/");
                        response.addCookie(cookie);
                    }
                }
                filterChain.doFilter(request, response);
            }
        };
    }

    private CsrfTokenRepository csrfTokenRepository() {
        HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
        repository.setHeaderName("X-XSRF-TOKEN");
        return repository;
    }

为client端设置端点保护

1.加入如下依赖

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

2.修改配置文件

#可在线查看日志
endpoints.logfile.enabled=true
logging.file=fileDir
#客户端开启停止服务端点
endpoints.shutdown.enabled=true
#保护客户端端点数据
security.user.name=aa
security.user.password=aa
security.basic.path=/aa
eureka.instance.metadata-map.user.name=${security.user.name}
eureka.instance.metadata-map.user.password=${security.user.password}

Eureka中的metadataMap是专门用来存放一些自定义的数据,当注册中心或者其他服务需要此服务的某些配置时可以在metadataMap里取。实际上,每个instance都有各自的metadataMap,map中存放着需要用到的属性。例如,上面配置中的eureka.instance.metadata-map.user.name,当这个服务成功注册到Eureka上,SpringBootAdmin就会取拿到这个instance,进而拿到metadataMap里的属性,然后放入请求头,向此服务发送请求,访问此服务的actuator开放的端点。

需要注意的是如果项目中用到了Zuul这样设置可能还不完善。例如,某服务用swagger2测接口,但是访问swagger的页面被设置了权限,此时直接访问swagger的页面会提示输入用户名和密码,但是即使输入正确也还是进入不了页面。这是因为Zuul转发请求默认是会省略一些东西的

为了避免Zuul请求路由到别的系统泄露一些重要信息,在请求头中默认没有这三个属性。而SpringSecurity是通过请求中的请求头Authentiction来取账号密码,所以每次提交账号密码验证的时候都获取不到,解决办法是修改zuul配置 zuul.sensitive-headers= 覆盖zuul的默认配置即可。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容