Spring Cloud中如何保证各个微服务之间调用的安全性

一.背景

微服务架构下,我们的系统根据业务被拆分成了多个职责单一的微服务。

每个服务都有自己的一套API提供给别的服务调用,那么如何保证安全性呢?

不是说你想调用就可以调用,一定要有认证机制,是我们内部服务发出的请求,才可以调用我们的接口。

需要注意的是我们这边讲的是微服务之间调用的安全认证,不是统一的在API官网认证,需求不一样,API网关处的统一认证是和业务挂钩的,我们这边是为了防止接口被别人随便调用。

二.方案

OAUTH2

Spring Cloud可以使用OAUTH2来实现多个微服务的统一认证授权

通过向OAUTH2服务进行集中认证和授权,获得access_token

而这个token是受其他微服务信任的,在后续的访问中都把access_token带过去,从而实现了微服务的统一认证授权。

JWT

JWT是一种安全标准。基本思路就是用户提供用户名和密码给认证服务器,服务器验证用户提交信息信息的合法性;如果验证成功,会产生并返回一个Token,用户可以使用这个token访问服务器上受保护的资源。

感觉这2种好像没多大区别呀,其实是有区别的:OAuth2是一种授权框架 ,JWT是一种认证协议

无论使用哪种方式切记用HTTPS来保证数据的安全性。

三.用哪种

我个人建议用JWT,轻量级,简单,适合分布式无状态的应用

用OAUTH2的话就麻烦点,各种角色,认证类型,客户端等等一大堆概念

四.怎么用

首先呢创建一个通用的认证服务,提供认证操作,认证成功后返回一个token

@RestController
@RequestMapping(value="/oauth")
public class AuthController {
    @Autowired
    private AuthService authService;
    @PostMapping("/token")
    public ResponseData auth(@RequestBody AuthQuery query) throws Exception {
        if (StringUtils.isBlank(query.getAccessKey()) || StringUtils.isBlank(query.getSecretKey())) {
            return ResponseData.failByParam("accessKey and secretKey not null");
        }
        User user = authService.auth(query);
        if (user == null) {
            return ResponseData.failByParam("认证失败");
        }
        JWTUtils jwt = JWTUtils.getInstance();
        return ResponseData.ok(jwt.getToken(user.getId().toString()));
    }
    @GetMapping("/token")
    public ResponseData oauth(AuthQuery query) throws Exception {
        if (StringUtils.isBlank(query.getAccessKey()) || StringUtils.isBlank(query.getSecretKey())) {
            return ResponseData.failByParam("accessKey and secretKey not null");
        }
        User user = authService.auth(query);
        if (user == null) {
            return ResponseData.failByParam("认证失败");
        }
        JWTUtils jwt = JWTUtils.getInstance();
        return ResponseData.ok(jwt.getToken(user.getId().toString()));
    }
}

JWT可以加入依赖,然后写个工具类即可,建议写在全局的包中,所有的服务都要用,具体代码请参考:JWTUtils

GITHUB地址:https://github.com/jwtk/jjwt

JWT提供了很多加密的算法,我这边用的是RSA,目前是用的一套公钥以及私钥,这种做法目前来说是不好的,因为万一秘钥泄露了,那就谈不上安全了,所以后面会采用配置中心的方式来动态管理秘钥。

类里主要逻辑是生成token,然后提供一个检查token是否合法的方法,以及是否过期等等判断。

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.7.0</version>
</dependency>

统一认证的服务有了,我们只需要将认证服务注册到注册中心即可给别的服务消费。

那么我们如何使用刚刚的认证服务来做认证呢,最简单的办法就是用Filter来处理

比如说我现在有一个服务fangjia-fsh-house-service,之前是随便谁都能调用我提供的接口,现在我想加入验证,只有验证通过的才可以让它调用我的接口

那就在fangjia-fsh-house-service中加一个过滤器来判断是否有权限调用接口,我们从请求头中获取认证的token信息,不需要依赖Cookie

这个过滤器我也建议写在全局的项目中,因为也是所有服务都要用,代码请参考:HttpBasicAuthorizeFilter

主要逻辑就是获取token然后通过JWTUtils来验证是否合法,不合法给提示,合法则放过

这边需要注意的地方是解密的秘钥必须跟加密时是相同的,不然解密必然失败,就是bug了

//验证TOKEN
if (!StringUtils.hasText(auth)) {
    PrintWriter print = httpResponse.getWriter();
    print.write(JsonUtils.toJson(ResponseData.fail("非法请求【缺少Authorization信息】", 
                 ResponseCode.NO_AUTH_CODE.getCode())));
    return;
}
JWTUtils.JWTResult jwt = jwtUtils.checkToken(auth);
if (!jwt.isStatus()) {
    PrintWriter print = httpResponse.getWriter();
    print.write(JsonUtils.toJson(ResponseData.fail(jwt.getMsg(), jwt.getCode())));
    return;
}
chain.doFilter(httpRequest, response);

到这步为止,只要调用方在认证通过之后,通过认证服务返回的token,然后塞到请求头Authorization中,就可以调用其他需要认证的服务了。

这样看起来貌似很完美,但是用起来不方便呀,每次调用前都需要去认证,然后塞请求头,如何做到通用呢,不需要具体的开发人员去关心,对使用者透明,下篇文章,我们继续探讨如何实现方便的调用。

具体代码可以参考我的github:

https://github.com/yinjihuan/spring-cloud

推荐阅读:

《知识点-Spring Boot 统一异常处理汇总》

《Spring Boot 1.X和2.X优雅重启实战》

《Spring Boot中快速操作Mongodb》

《面试-线程池的成长之路》

原文发布于微信公众号 - 猿天地(cxytiandi)

原文发表时间:2018-05-26

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏黄日成的专栏

浅析 P2P 穿越 NAT 的原理、技术、方法 (上)

在 NAT 环境下,实现 P2P 通信的完整解决方案包括几个部分呢?相关的原理、方法、技术有哪些?

2K1
来自专栏向治洪

基于xmpp聊天室实现,国外牛人作品

XMPP的官网:http://xmpp.org/ 测试帐号注册:https://register.jabber.org PC端下载地址注册之后就会看到下载地址 ...

3375
来自专栏大闲人柴毛毛

手把手0基础项目实战(三)——教你开发一套电商平台的安全框架

写在最前 本文是《手把手项目实战系列》的第三篇文章,预告一下,整个系列会介绍如下内容: 《手把手0基础项目实战(一)——教你搭建一套可自动化构建的微服务框架(S...

4526
来自专栏weixuqin 的专栏

springMVC 学习笔记(一):spring 入门

springMVC 是 spring 框架的一个模块,springMVC 和 spring 无需通过中间整合层进行整合。springMVC 是一个基于 mvc ...

1312
来自专栏菩提树下的杨过

spring-boot 速成(1) helloworld

一、mac上安装 $ brew tap pivotal/tap $ brew install springboot 安装成功后,可在终端查看命令行 ➜  ~ s...

2245
来自专栏张戈的专栏

零门槛!使用Docker快速部署ES集群

自从接触 Docker 之后,对 Docker 简直是爱不释手,做什么都是行云流水。遇到部署开源软件需求,第一时间想到的都是有没有现成的 Docker 镜像?能...

2.6K4
来自专栏木木玲

Netty in action ——— 事件循环 和 线程模式

2393
来自专栏PHP在线

重磅资料!Github上的PHP资源汇总大全

依赖管理 ——用于依赖管理的包和框架 Composer/Packagist : 一个包和依赖管理器 Composer Installers: 一个多框架Com...

3164
来自专栏PhpZendo

什么是依赖注入

本文是依赖注入(Depeendency Injection)系列教程的第一篇文章,本系列教程主要讲解如何使用 PHP 实现一个轻量级服务容器,教程包括:

2871
来自专栏Java面试通关手册

结合Spring发送邮件的四种正确姿势,你知道几种?

测试使用的环境是企业主流的SSM 框架即 SpringMVC+Spring+Mybatis。为了节省时间,我直接使用的是我上次的“SSM项目中整合Echarts...

1403

扫码关注云+社区

领取腾讯云代金券