Dubbo 令牌验证和优雅停机

前言

大家好,今天开始给大家分享 — Dubbo 专题之 Dubbo 令牌验证和优雅停机。在前面的章节中我们介绍了 Dubbo 延迟和粘滞连接,了解了什么是延迟和粘滞连接以及日常的使用场景和实现原理,同时我们知道延迟连接是在使用实例对象的时候才创建通讯连接,粘滞连接是尽可能的使用已经创建的连接,它们都有类似减少连接创建的作用。那本章节讨论一些轻松的话题就是令牌验证和优雅停机,那什么是令牌呢?以及它的作用是什么呢?。那就让我们快速开始吧!

1. 令牌验证和优雅停机简介

首先介绍什么是令牌,我们通过一个生活中的小例子讨论什么是令牌。例如:我们小伙伴经常坐火车出去玩那得首先购买火车票吧,然后我们拿着火车票到安检口进行检票,检票成功我们就可以乘坐火车,如果检票失败则不能乘坐。这里的火车票就是我们所说的令牌,只有拿到有效的令牌我们才有权限或资格做后续的事情。

那什么是优雅停机呢?简单的理解就是在应用正常处理完成过后才退出应用,但是如果我们通过kill -9 PID 等强制关闭指令,是不会执行优雅停机的,只有通过 kill PID 时,才会执行。在我的 Dubbo 是通过 JDK 的 ShutdownHook 来完成优雅停机。

2. 配置方式

Dubbo 主要通过 XML 、注解、配置文件的方式配置:

2.1 令牌验证配置方式

XML 配置方式

  1. 全局设置
<!--随机token令牌,使用UUID生成-->
<dubbo:provider token="true" />

或者

<!--固定token令牌,相当于密码-->
<dubbo:provider token="123456" />
  1. 服务级别设置
<!--随机token令牌,使用UUID生成-->
<dubbo:service interface="com.muke.dubbocourse.common.api.BookFacade" token="true" />

或者

<!--固定token令牌,相当于密码-->
<dubbo:service interface="com.muke.dubbocourse.common.api.BookFacade" token="123456" />

注解方式:服务级别设置

@DubboService(token = "true")
//@Service(token = "true")

配置文件:全局配置

dubbo.provider.token=true

2.2 优雅停机配置方式

Dubbo 中主要通过属性配置和编码方式:

属性配置

# dubbo.properties
dubbo.service.shutdown.wait=15000

编码方式

DubboShutdownHook.destroyAll();

Tips:使用 tomcat 等容器部署的场景,建议通过扩展 ContextListener 等自行调用以下代码实现优雅停机

3. 使用场景

下面我们看看 Dubbo 中令牌验证和优雅停机的使用场景。首先 Dubbo 中的场景描述是令牌验证在注册中心控制权限,以决定要不要下发令牌给消费者,可以防止消费者绕过注册中心访问提供者,另外通过注册中心可灵活改变授权方式,而不需修改或升级提供者。优雅停机在 Dubbo 中注意也是用于资源的回收处理等。下面我们讨论常用的使用场景:

  1. 令牌验证使用场景:从 Dubbo 令牌验证场景描述中我们可以知道可以通过令牌对消费者访问接口进行授权访问,即我们可以通过自行拓展对注册信息进行动态调整以支持接口权限动态访问控制。

  2. 优雅停机使用场景:在 Dubbo 应用退出时关闭底层的网络连接资源、缓存操作资源等等。

4. 示例演示

下面我们以获取图书列表为例进行实例演示主要演示令牌验证。项目结构如下:

idea

下面我们看看服务消费端的配置dubbo-provider-xml.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">

    <dubbo:application name="demo-provider" metadata-type="remote"/>

    <dubbo:registry address="zookeeper://127.0.0.1:2181"/>

    <bean id="bookFacade" class="com.muke.dubbocourse.tokenverify.provider.BookFacadeImpl"/>

    <!--暴露本地服务为Dubbo服务-->
    <dubbo:service interface="com.muke.dubbocourse.async.api.BookFacade" ref="bookFacade" token="12345"/>

</beans>

上面我们开启服务级别的 token 配置 token="12345" 设置 token 固定值。下面我们看看服务消费端配置文件dubbo-consumer-xml.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">

    <dubbo:application name="demo-consumer" logger="log4j"/>

    <dubbo:registry address="zookeeper://127.0.0.1:2181"/>

    <!--1.通过注册中心获取服务引用-->
<!--    <dubbo:reference id="bookFacade" interface="com.muke.dubbocourse.common.api.BookFacade">-->
<!--    </dubbo:reference>-->

    <!--2.url直接指定服务提供者所做机器以及端口-->
    <dubbo:reference id="bookFacade"
                     interface="com.muke.dubbocourse.common.api.BookFacade" url="dubbo://localhost:20890">
    </dubbo:reference>

</beans>

上面的 XML 中如果使用第一种方式可以正常访问我们的bookFacade服务,如果使用第二种直连的方式绕开注册中心则会得到以下错误:

Caused by: io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: /192.168.101.8:20890Caused by: java.net.ConnectException: Connection refused at sun.nio.ch.SocketChannelImpl.checkConnect(Native Method)

因为我们的服务开启 token 验证如果绕开注册中心直接调用则 token 会验证不通过。

<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<ins class="adsbygoogle"
style="display:block; text-align:center;"
data-ad-layout="in-article"
data-ad-format="fluid"
data-ad-client="ca-pub-4279907681900931"
data-ad-slot="6812672741"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>

5. 原理分析

下面我们主要分析 Dubbo 中的令牌验证源码。

token 的解析过程

当我们的服务服务端的服务暴露时会调用方法`org.apache.dubbo.config.ServiceConfig

doExportUrlsFor1Protocol`其核心代码如下:

    private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) {
        
                //...
        //获取在服务提供端配置的 token 值 ,例如:token="123456" 
        if(ConfigUtils.isEmpty(token) && provider != null) {
            token = provider.getToken();
        }

        if (!ConfigUtils.isEmpty(token)) {
            //如果配置值为:true 或 default 则产生一个随机的token值
            if (ConfigUtils.isDefault(token)) {
                map.put(TOKEN_KEY, UUID.randomUUID().toString());
            } else {
              //设置为配置的token值
                map.put(TOKEN_KEY, token);
            }
        }
        //init serviceMetadata attachments
        serviceMetadata.getAttachments().putAll(map);

       //...
    }

在上面的代码中我们可以看到从我们的配置中获取token值并注册到注册中心,如果配置值为:truedefault 则产生一个随机的token值,否则使用配置的token值。

token使用过程

在服务消费端调用请求到达服务提供端前会经过一些了的过滤器,其中就包括了对token的校验过滤器。核心代码如下:

public class TokenFilter implements Filter {    @Override    public Result invoke(Invoker<?> invoker, Invocation inv)            throws RpcException {        //获取token参数值        String token = invoker.getUrl().getParameter(TOKEN_KEY);        if (ConfigUtils.isNotEmpty(token)) {            Class<?> serviceType = invoker.getInterface();            Map<String, String> attachments = inv.getAttachments();            String remoteToken = (attachments == null ? null : attachments.get(TOKEN_KEY));            //验证消费者携带的token与服务提供端的token是否相等            if (!token.equals(remoteToken)) {                throw new RpcException("Invalid token! Forbid invoke remote service " + serviceType + " method " + inv.getMethodName() + "() from consumer " + RpcContext.getContext().getRemoteHost() + " to provider " + RpcContext.getContext().getLocalHost());            }        }        return invoker.invoke(inv);    }}

通过上面的过滤器对token进行验证,如果验证通过则调用后面的执行器,如果验证失败则抛出异常。

6. 小结

在本小节中我们主要学习了 Dubbo 中的令牌验证和优雅停机,以及常见的使用场景和使用方式。同时我们也通过示例演示和源码分析对 Dubbo 的令牌验证原理进行解析。其中令牌验证核心思想就是通过服务提供端提供的token或者随机产生的token放入注册中心进行管理,然后服务消费端获取token令牌并且在调用服务提供端时携带 token,服务提供端根据消费端携带的token进行验证。在优雅停机方面 Dubbo 是通过 JDK 的 ShutdownHook 来完成优雅停机。

本节课程的重点如下:

  1. 理解 Dubbo 中令牌验证和优雅停机

  2. 了解令牌验证和优雅停机使用方式

  3. 了解令牌验证和优雅停机使用场景

  4. 了解 Dubbo 中令牌验证原理

作者

个人从事金融行业,就职过易极付、思建科技、某网约车平台等重庆一流技术团队,目前就职于某银行负责统一支付系统建设。自身对金融行业有强烈的爱好。同时也实践大数据、数据存储、自动化集成和部署、分布式微服务、响应式编程、人工智能等领域。同时也热衷于技术分享创立公众号和博客站点对知识体系进行分享。关注公众号:青年IT男 获取最新技术文章推送!

博客地址: http://youngitman.tech

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容

  • Dubbo在Docker中的优雅停机 优雅停机 优雅停机是指在停止应用时,执行的一系列保证应用正常关闭的操作。这些...
    望望hope阅读 1,919评论 0 3
  • 一、Dubbo是什么 Dubbo 是一个分布式、高性能、透明化的 RPC 服务框架,提供服务自动注册、自动发现等高...
    小波同学阅读 2,502评论 0 10
  • 什么是RPCRPC(Remote Procedure Call)是一种通过网络从远程计算机程序上请求服务,而不需要...
    Hitooo阅读 382评论 0 0
  • 一、Dubbo是什么? Dubbo是阿里巴巴开源的基于 Java 的高性能 RPC 分布式服务框架,现已成为 Ap...
    Djbfifjd阅读 1,047评论 0 8
  • 官方文档 快速启动 关键配置 启动类 XML配置-标签的含义-配置的优先级 dubbo-admin搭建-githu...
    巨子联盟阅读 19,759评论 3 7