SpringCloud (十二) --------- 服务安全机制 与 Apollo 配置中心


一、Spring Cloud 服务安全机制

微服务的 Rest 服务都是 http 的,有可能暴露在公网上,那么任何人都可能调用,如果你的 Rest 服务有一些私密信息,这样会导致信息的泄露,所以我们的微服务需要增加一些安全机制。

如果想进行安全方面的处理,首先要在服务上进行如下处理。

A、配置依赖

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

B、application.properties文件

#认证用户名
spring.security.user.name=fancy
#认证密码
spring.security.user.password=123456

C、测试访问

地址栏输入:

http://localhost:9100/service/goods
http://localhost:9200/service/goods

此时就需要输入账号和密码才能访问接口。

注意

消费者集成了 Sleuth+zipkin 导致只能消费一次,可能内部有点冲突,把 Sleuth + zipkin 去掉,恢复正常。

1. 需要安全认证的服务调用

当远程的一个服务已经使用了密码验证,那么这个时候服务的消费方如果想直接访问就不能访问了,此时需要进行相关的处理。

A、如果是 restTemplate 调用

首先配置一个 HttpHeaders

@Bean 
public HttpHeaders getHeaders() {
    // 定义 Http 的头信息
    HttpHeaders headers = new HttpHeaders();
    // 认证的原始信息
    String auth = "fancy:123456";
    // 进行加密处理
    byte[] encodedAuth = Base64.getEncoder().encode(auth.getBytes(Charset.forName("US-ASCII")));
    String authHeader = "Basic " +  new String(encodedAuth);
    headers.set("Authorization", authHeader);
    return headers;
}

然后在调用的地方注入该 HttpHeaders

@Autowired
private HttpHeaders httpHeaders;

调用的时候要传入这个 http 头信息

@RequestMapping("/service/goods")
public ResultObject goods() {
    System.out.println("/service/goods-->8080");
    //调用远程的一个controller, restful的调用
    ResponseEntity<ResultObject> responseEntity = restTemplate.exchange(GOODS_SERVICE_URL, HttpMethod.GET, new HttpEntity<Object>(httpHeaders), ResultObject.class);
    return responseEntity.getBody();
}

B、如果是 feign 的方式调用

需要一个配置类

@Configuration
public class FeignConfiguration {

    //@RequestLine("GET /service/goods")

    /**
     * 一种契约,采用feign的契约方式,如果不配置该bean,会转成SpringMVC的方式
     */
    /*@Bean
    public Contract feignContract(){
        return new Contract.Default();
    }*/

    @Bean
    public BasicAuthRequestInterceptor basicAuthRequestInterceptor(){
        //传用户名和密码
        return new BasicAuthRequestInterceptor("fancy","123456");
    }
}

在 feign 的声明式接口注解上加入配置

@FeignClient(value="${service.id}", fallbackFactory = GoodsRemoteClientFallBackFactory.class,configuration = FeignConfiguration.class)
public interface GoodsRemoteClient {
/*fallback=GoodsRemoteClientFallBack.class*/

这样便可以实现调用\

2. 使用独立的安全服务

在实际项目开发中,服务一般都会非常多,绝大多数情况下,这些服务都需要用到安全验证,而且密码也会一样,如果每个服务都单独配置安全认证,工作量比较大,所以应该单独建立一个安全验证的项目,其他微服务如果需要安全认证就引入该项目的依赖即可。

此时我们需要使用如下的配置类来完成:

@Configuration
@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .passwordEncoder(new BCryptPasswordEncoder())
                .withUser("fancy")
                .password(new BCryptPasswordEncoder().encode("123456"))
                .roles("USER")
                .and()
                .withUser("admin")
                .password(new BCryptPasswordEncoder().encode("123456"))
                .roles("USER", "ADMIN");
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.httpBasic().and().authorizeRequests().anyRequest().fullyAuthenticated();
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }
}

二、Apollo 配置中心

1. Apollo 运行环境

A、环境要求

推荐虚拟机内存在2G或以上
JDK 1.8环境
MySQL版本要求:5.6.5+
Apollo的表结构对timestamp使用了多个default 声明,所以需要MySQL5.6.5以上版本

B、项目下载打包

从Github下载项目自己进行编译打包也可以,不过 apollo 本身提供了一个可以直接使用的 jar 包。https://github.com/nobodyiam/apollo-build-scripts

在这里插入图片描述

C、创建数据库

Apollo 服务端共需要两个数据库:ApolloPortalDB 和 ApolloConfigDB,把数据库、表的创建和样例数据 sql 文件导入数据库即可。

在这里插入图片描述

apolloportaldb.sql
导入成功后,可以通过执行如下sql语句来验证:

select `Id`, `AppId`, `Name` from ApolloPortalDB.App

apolloconfigdb.sql
导入成功后,可以通过执行如下sql语句来验证:

select `NamespaceId`, `Key`, `Value`, `Comment` from ApolloConfigDB.Item

在这里插入图片描述

Apollo服务端需要知道如何连接到你创建的数据库,所以需要修改 startup.sh,修改 ApolloPortalDB 和 ApolloConfigDB 两个数据库的连接信息。

注意:配置的用户需要具有对 ApolloPortalDB 和 ApolloConfigDB 数据库的读写权限。

#apollo config db info
apollo_config_db_url=jdbc:mysql://localhost:3306/ApolloConfigDB?characterEncoding=utf8
apollo_config_db_username=用户名
apollo_config_db_password=密码(如果没有密码,留空即可)

# apollo portal db info
apollo_portal_db_url=jdbc:mysql://localhost:3306/ApolloPortalDB?characterEncoding=utf8
apollo_portal_db_username=用户名
apollo_portal_db_password=密码(如果没有密码,留空即可)

注意:不要修改 demo.sh 的其它部分

D、启动 Apollo 配置中心

执行启动脚本

./demo.sh start (里面会启动三个服务,启动会比较慢)

在这里插入图片描述

启动成功后,访问:http://ip:8070 登录账号默认是: apollo/admin。

在这里插入图片描述

Config-service 8080端口
Admin-service 8090端口
Portal 管控台 8070端口

2. Apollo 应用开发

对于我们的应用开发而言,Apollo 阿波罗分布式配置中心属于客户端-服务端模式,我们的应用程序是客户端,Apollo 阿波罗是服务端。

A、在项目中添加 apollo 的依赖

<!-- apollo-client -->
<dependency>
    <groupId>com.ctrip.framework.apollo</groupId>
    <artifactId>apollo-client</artifactId>
    <version>1.5.1</version>
</dependency>

B、配置文件

我们的应用程序也就是 Apollo 客户端依赖于AppId、pollo Meta Server等环境信息来工作,需要做如下配置:

AppId:AppId是应用的身份信息,是从服务端获取配置的一个重要信息。

SpringBoot application.properties

Apollo 支持通过 Spring Boot 的 application.properties 或bootstrap.properties 文件配置:

app.id=YOUR-APP-ID

app.properties

在项目的 classpath:/META-INF/app.properties 文件存在,并且其中内容配置:

app.id=YOUR-APP-ID

Apollo Meta Server:元数据服务器

Apollo 可以在 Spring Boot 的 application.properties 或 bootstrap.properties 中指定

apollo.meta=http://config-service-url

通过 app.properties 配置文件在 classpath:/META-INF/app.properties 指定

apollo.meta=http://config-service-url

在main方法的类上加一个注解

@EnableApolloConfig //开启apollo配置支持

C、本地缓存路径

Apollo客户端会把从服务端获取到的配置在本地文件系统缓存一份,用于在遇到服务不可用,或网络不通的时候,依然能从本地恢复配置,不影响应用正常运行

本地缓存路径默认位于以下路径,所以请确保 /opt/data 或 C:\opt\data\ 目录存在,且应用有读写权限。

Mac/Linux: /opt/data/{appId}/config-cache
Windows: C:\opt\data\{appId}\config-cache
{appId}+{cluster}+{namespace}.properties

3. Apollo 客户端的实现原理

在这里插入图片描述
1、客户端和服务端保持了一个长连接,从而能第一时间获得配置更新的推送。(通过Http Long Polling实现)

2、客户端还会定时从 Apollo 配置中心服务端拉取应用的最新配置,这是一个fallback 机制,为了防止推送机制失效导致配置不更新。

3、客户端定时拉取会上报本地版本,所以一般情况下,对于定时拉取的操作,服务端都会返回 304 - Not Modified。定时频率默认为每 5 分钟拉取一次,客户端也可以通过在运行时指定 System Property: apollo.refreshInterval 来覆盖,单位为分钟。

4、客户端从 Apollo 配置中心服务端获取到应用的最新配置后,会保存在内存中
客户端会把从服务端获取到的配置在本地文件系统缓存一份。在遇到服务不可用,或网络不通的时候,依然能从本地恢复配置。

5、应用程序可以从Apollo客户端获取最新的配置、订阅配置更新通知。

4. Apollo 配置中心设计

在这里插入图片描述
Apollo的总体设计,从下往上看分别是:

Config Service 提供配置的读取、推送等功能,服务对象是Apollo客户端。
Admin Service 提供配置的修改、发布等功能,服务对象是Apollo Portal (管理界面)。

Config Service 和 Admin Service 都是多实例、无状态部署,所以需要将自己注册到 Eureka 中并保持心跳。

在 Eureka 之上我们架了一层 Meta Server 用于封装 Eureka 的服务发现接口。
Client 通过域名访问 Meta Server 获取 Config Service 服务列表 (IP+Port),而后直接通过 IP+Port 访问服务,同时在 Client 侧会做 load balance、错误重试。

Portal 通过域名访问 Meta Server 获取 Admin Service 服务列表 (IP+Port),而后直接通过 IP+Port 访问服务,同时在 Portal 侧会做 load balance、错误重试。

为了简化部署,我们实际上会把 Config Service、Eureka 和 Meta Server 三个逻辑角色部署在同一个JVM进程中。

5. Apollo 模块

Config Service

提供配置获取接口
提供配置更新推送接口 (基于Http long polling)
服务端使用 Spring DeferredResult实现异步化,从而大大增加长连接数量
目前使用的 tomcat embed 默认配置是最多 10000 个连接(可以调整),使用了4C8G的虚拟机实测可以支撑 10000 个连接,所以满足需求(一个应用实例只会发起一个长连接)。
接口服务对象为 Apollo 客户端

Admin Service

提供配置管理接口
提供配置修改、发布等接口
接口服务对象为Portal

Meta Server

Portal 通过域名访问 Meta Server 获取 Admin Service 服务列表(IP+Port)
Client通过域名访问 Meta Server 获取 Config Service 服务列表(IP+Port)
Meta Server 从 Eureka 获取 Config Service 和 Admin Service 的服务信息,相当于是一个Eureka Client
增设一个 Server 的角色主要是为了封装服务发现的细节,对 Portal 和 Client 而言,永远通过一个 Http 接口获取 Admin
Service 和 Config Service 的服务信息,而不需要关心背后实际的服务注册和发现组件
Meta Server 只是一个逻辑角色,在部署时和 Config Service 是在一个 JVM 进程中的,所以IP、端口和 Config Service 一致

Eureka

基于 Eureka 和 Spring Cloud Netflix 提供服务注册和发现 Config Service和Admin Service会向 Eureka 注册服务,并保持心跳。为了简单起见,目前Eureka在部署时和Config Service是在一个JVM进程中的(通过Spring Cloud Netflix)

Portal

提供 Web 界面供用户管理配置
通过 Meta Server 获取 Admin Service 服务列表(IP+Port),通过IP+Port访问服务
在 Portal 侧做 load balance、错误重试

Client

Apollo提供的客户端程序,为应用提供配置获取、实时更新等功能
通过Meta Server获取Config Service服务列表(IP+Port),通过IP+Port访问服务
在Client侧做load balance、错误重试

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

在森林中麋了鹿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值