【Dubbo3高级特性】「提升系统安全性」手把手教你如何通过令牌进行Dubbo3服务验证及服务鉴权控制实战指南(二)

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
注册配置 MSE Nacos/ZooKeeper,118元/月
云原生网关 MSE Higress,422元/月
简介: 【Dubbo3高级特性】「提升系统安全性」手把手教你如何通过令牌进行Dubbo3服务验证及服务鉴权控制实战指南

【Dubbo3高级特性】「提升系统安全性」手把手教你如何通过令牌进行Dubbo3服务验证及服务鉴权控制实战指南(一)https://developer.aliyun.com/article/1470989


实现案例

定义鉴权服务中心服务
建立Dubbo3的服务容器作为鉴权服务实现

Undertow容器处理功能,用于接收对应的Http鉴权请求接口服务,用于处理来资源服务提供者端的Http请求。

数据模型



定义对应的实现鉴权中心鉴权匹配实现类

定义Hutools的数据源DB

在对应的resources下的config文件下建立db.setting文件,之后配置对应的数据源

ini

复制代码

#中括表示一个分组,其下面的所有属性归属于这个分组,在此分组名为ds1,也可以没有分组
[ds1]
#自定义数据源设置文件,这个文件会针对当前分组生效,用于给当前分组配置单独的数据库连接池参数,没有则使用全局的配置
driver = com.mysql.jdbc.Driver
#JDBC url,必须
url = jdbc:mysql://127.0.0.1:3306/dubbo-shopping
#用户名,必须
user = root
#密码,必须,如果密码为空,请填写 pass =
pass = root$
实现查询数据库的Hutool操作

java

复制代码

List<Entity> authData = Db.use(dataSource).query("select * from auth_data");
if(CollectionUtil.isNotEmpty(authData)){
  Entity entity = authData.get(0);
  String ak = entity.getStr("ak");
  String sk = entity.getStr("sk");
}
实现传递过来的数据库的Hutool操作

java

复制代码

@Data
@Slf4j
@NoArgsConstructor
public class AuthService {
    DataSource dataSource = DSFactory.get("ds1");
    /**
     * 匹配ak和sk的值
     * @param appCode
     * @param appKey
     * @param secretKey
     * @return
     */
    public boolean matchSecretKey(String appCode,String appKey,String secretKey){
        log.info("appCode:{} - local-appkey:{} - local-secretKey:{}",appCode,appKey,secretKey);
        if(StringUtils.isEmpty(appKey)){
            return Boolean.FALSE;
        }
        try {
            List<Entity> authData = Db.use(dataSource).query("select * from auth_data where code = ?",appCode);
            if(CollectionUtil.isNotEmpty(authData)){
                Entity entity = authData.get(0);
                String ak = entity.getStr("ak");
                String sk = entity.getStr("sk");
                log.info("remote-appkey:{} - remote-secretKey:{}",ak,sk);
                if(ak.equals(ak)){
                    if(StringUtils.isEmpty(sk)){
                        return Boolean.FALSE;
                    }
                    else if(!SecureUtil.md5(sk).equals(secretKey)){
                        return Boolean.FALSE;
                    }
                }else{
                    return Boolean.FALSE;
                }
                return Boolean.TRUE;
            }
            return Boolean.FALSE;
        } catch (SQLException e) {
            log.error("auth is error!",e);
            return Boolean.FALSE;
        }
    }
}

鉴权服务 UndertowContainer

采用Undertow容器服务机制,在之前的章节已经介绍和说明了如何实现对应的dubbo的自定义容器实现,在这里我们使用的是UndertowContainer。如果想要学习可以关注之前的文章章节。

java

复制代码

package com.hyts.assemble.dubbo3.comp.container;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.NumberUtil;
import com.hyts.assemble.dubbo3.comp.auth.AuthService;
import io.undertow.Undertow;
import io.undertow.util.Headers;
import org.apache.dubbo.common.config.ConfigurationUtils;
import org.apache.dubbo.container.Container;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.stream.Collectors;
public class UnderTowContainer implements Container {
    //定义容器端口
    public static final String UNDERTOW_PORT = "dubbo.undertow.port";
    //定义容器contextPath
    public static final String UNDERTOW_DEFAULT_PATH = "dubbo.undertow.path";
    
    private AuthService authService = new AuthService();
    
    //设置HttpHandler回调方法
   final Undertow server = Undertow.builder()
            .addHttpListener(NumberUtil.parseInt(ConfigurationUtils.getProperty(UNDERTOW_PORT)), "localhost")
            .setHandler(exchange -> {
                if(exchange.getRequestPath().equals(ConfigurationUtils.getProperty(UNDERTOW_DEFAULT_PATH))){
                    String appKey = String.valueOf(exchange.getQueryParameters().get("appKey").poll());
                    String secretKey = String.valueOf(exchange.getQueryParameters().get("secretKey").poll());
                    String appCode = String.valueOf(exchange.getQueryParameters().get("appCode").poll());
                    boolean result = authService.matchSecretKey(appCode,appKey,secretKey);
                    exchange.getResponseSender().send(String.valueOf(result));
                }
            }).build();
            
    // 定义启动方法        
    @Override
    public void start() {
        server.start();
    }
   
    // 定义停止方法 
    @Override
    public void stop() {
        server.stop();
    }
}

定义容器的dubbo.properties

ini

复制代码

dubbo.container=spring,jetty,log4j,undertow
dubbo.undertow.path=/auth
dubbo.undertow.port=8081
服务提供端

只需要设置 service.auth 为 true,表示该服务的调用需要鉴权认证通过。param.sign为true表示需要对参数也进行校验,之前的章节的内容我们已经介绍了对应的如何建立校验功能的实现机制控制。

java

复制代码

// (注解方式)
@DubboService(parameters = {"service.auth","true"})
public class AuthServiceImpl implements AuthService {
}

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" xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    <context:property-placeholder/>
    <dubbo:application name="direct-consumer"/>
    <dubbo:registry address="zookeeper://${zookeeper.address:127.0.0.1}:2181" check="false"/>
    <dubbo:protocol name="dubbo" port="20880"/>
    <bean id="rpcAuthSampleApi" class="com.dubbo.shopping.commodity.rpc.auth.AuthServiceImpl"/>
    <dubbo:service id="rpcAuthSampleApiHandler" interface="com.dubbo.shopping.commodity.api.AuthService"
                   ref="rpcAuthSampleApi" version="0.0.0" filter="auth">
      <dubbo:parameter key="service.auth" value="true"/>
</dubbo:service>
</beans>
服务提供端-建立服务鉴权过滤器

在之前的章节文章中介绍了对应的META-INF/dubbo下建立org.apache.dubbo.rpc.Filter文件,之后进行auth=com.dubbo.shopping.common.auth.filter.AuthFilter,之后会进行定义我们的authFilter过滤器实现类。

建立dubbo.properties配置信息读取相关的鉴权服务的地址

resources文件下建立dubbo.properties之后添加对应的内容

properties

复制代码

dubbo.auth.url=http://localhost:8081/auth

可以使用对应的配置工具进行获取配置信息。

java

复制代码

ConfigurationUtils.getProperty("dubbo.auth.url")

定义对应的服务提供端-建立服务鉴权过滤器

java

复制代码

@Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        boolean authNeed = Boolean.valueOf(invoker.getUrl().getParameter("service.auth"));
        String ak = invocation.getAttachment("AK");
        String sk = invocation.getAttachment("SK");
        String authUrl = ConfigurationUtils.getProperty("dubbo.auth.url");
        if(authNeed){
            log.info("PROCESS AUTH THE INVOKE!APPKEY {} , SECRETKEY {} : authUrl:{}",ak,sk,authUrl);
            String result = HttpUtil.get(authUrl+"?appCode="+"dubbo-shopping"+"&appKey="+ak+"&secretKey="+sk);
            if(!Boolean.valueOf(result)){
                log.error("NOT AUTH THE INVOKE! APPKEY {} , SECRETKEY {}",ak,sk);
                throw new RpcException("NOT AUTH THE INVOKE!");            }
        }
        log.info("PASS AUTH THE INVOKE!APPKEY {} , SECRETKEY {}",ak,sk);
//        if(paramSign){
//        }
        return invoker.invoke(invocation);
    }
服务消费端

只需要配置好对应的证书等信息即可,之后会自动地在对这些需要认证的接口发起调用前进行签名操作,通过与鉴权服务的交互,用户无需在代码中配置 AK/SK 这些敏感信息,并且在不重启应用的情况下刷新 AK/SK,达到权限动态下发的目的。

该方案目前已经提交给 Dubbo 开源社区,并且完成了基本框架的合并,除了 AK/SK 的鉴权方式之外,通过 SPI 机制支持用户可定制化的鉴权认证以及适配公司内部基础设施的密钥存储。

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" xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    <context:property-placeholder/>
    <dubbo:application name="direct-consumer"/>
    <dubbo:registry address="zookeeper://${zookeeper.address:127.0.0.1}:2181" check="false"/>
    <dubbo:provider token="true"/>
    <dubbo:protocol name="dubbo" port="20880"/>
    <dubbo:reference id="authSampleApi" check="false" interface="com.dubbo.shopping.commodity.api.AuthSampleApi" version="*"/>
</beans>
模拟远程调用

java

复制代码

package com.dubbo.shopping.commodity.controller;
import cn.hutool.crypto.SecureUtil;
import com.dubbo.shopping.commodity.api.AnnotationConstants;
import com.dubbo.shopping.commodity.api.AuthSampleApi;
import com.dubbo.shopping.commodity.api.CommodityQueryApi;
import com.dubbo.shopping.commodity.entity.BaseInfo;
import com.dubbo.shopping.commodity.model.CommodityQueryDTO;
import com.dubbo.shopping.model.rpc.RpcRequest;
import io.swagger.annotations.ApiOperation;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.rpc.RpcContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
 * <p>
 * 商品主题信息 前端控制器
 * </p>
 *
 * @author libo
 * @since 2022-05-08
 */
@RestController
@RequestMapping("/commodity/base-info")
public class BaseInfoController {
    @Autowired
    AuthSampleApi authSampleApi;
    @ApiOperation("权限控制调用")
    @RequestMapping("/auth")
    public ResponseEntity auth(){
        RpcContext.getClientAttachment().setAttachment("AK","dubbo3");
        RpcContext.getClientAttachment().setAttachment("SK", SecureUtil.md5("123456"));
        return ResponseEntity.ok(authSampleApi.executeAuth("test parameter"));
    }
}

既可以实现鉴权服务机制,大家还可以自己进行扩展实现。

相关实践学习
基于MSE实现微服务的全链路灰度
通过本场景的实验操作,您将了解并实现在线业务的微服务全链路灰度能力。
相关文章
|
1月前
|
Dubbo Java 应用服务中间件
微服务框架Dubbo环境部署实战
微服务框架Dubbo环境部署的实战指南,涵盖了Dubbo的概述、服务部署、以及Dubbo web管理页面的部署,旨在指导读者如何搭建和使用Dubbo框架。
86 17
微服务框架Dubbo环境部署实战
|
13天前
|
缓存 负载均衡 Dubbo
Dubbo技术深度解析及其在Java中的实战应用
Dubbo是一款由阿里巴巴开源的高性能、轻量级的Java分布式服务框架,它致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案。
39 6
|
2月前
|
JSON Dubbo Java
【Dubbo协议指南】揭秘高性能服务通信,选择最佳协议的终极攻略!
【8月更文挑战第24天】在分布式服务架构中,Apache Dubbo作为一款高性能的Java RPC框架,支持多种通信协议,包括Dubbo协议、HTTP协议及Hessian协议等。Dubbo协议是默认选择,采用NIO异步通讯,适用于高要求的内部服务通信。HTTP协议通用性强,利于跨语言调用;Hessian协议则在数据传输效率上有优势。选择合适协议需综合考虑性能需求、序列化方式、网络环境及安全性等因素。通过合理配置,可实现服务性能最优化及系统可靠性提升。
45 3
|
2月前
|
C# 开发者 Windows
勇敢迈出第一步:手把手教你如何在WPF开源项目中贡献你的第一行代码,从选择项目到提交PR的全过程解析与实战技巧分享
【8月更文挑战第31天】本文指导您如何在Windows Presentation Foundation(WPF)相关的开源项目中贡献代码。无论您是初学者还是有经验的开发者,参与这类项目都能加深对WPF框架的理解并拓展职业履历。文章推荐了一些适合入门的项目如MvvmLight和MahApps.Metro,并详细介绍了从选择项目、设置开发环境到提交代码的全过程。通过具体示例,如添加按钮点击事件处理程序,帮助您迈出第一步。此外,还强调了提交Pull Request时保持专业沟通的重要性。参与开源不仅能提升技能,还能促进社区交流。
32 0
|
2月前
|
Dubbo Java Nacos
【实战攻略】破解Dubbo+Nacos+Spring Boot 3 Native打包后运行异常的终极秘籍——从零开始彻底攻克那些让你头疼不已的技术难题!
【8月更文挑战第15天】Nacos作为微服务注册与配置中心受到欢迎,但使用Dubbo+Nacos+Spring Boot 3进行GraalVM native打包后常遇运行异常。本文剖析此问题及其解决策略:确认GraalVM版本兼容性;配置反射列表以支持必要类和方法;采用静态代理替代动态代理;检查并调整配置文件;禁用不支持的功能;利用日志和GraalVM诊断工具定位问题;根据诊断结果调整GraalVM配置。通过系统排查方法,能有效解决此类问题,确保服务稳定运行。
68 0
|
2月前
|
缓存 负载均衡 Dubbo
Dubbo服务集群容错原理(重要)
该文章主要介绍了Dubbo服务集群容错的原理,包括集群容错技术的概念、Dubbo中使用的集群容错技术种类及其原理。
|
5月前
|
监控 安全 Linux
Linux系统的防御从多个方面来保护系统安全
防火墙:使用防火墙软件如iptables或Firewalld来限制网络流量,保护系统免受恶意网络攻击。
|
5月前
|
网络协议 安全 Linux
linux系统安全及应用——端口扫描
linux系统安全及应用——端口扫描
74 0
|
安全 Linux
Linux 系统安全 - 近期发现的 polkit pkexec 本地提权漏洞(CVE-2021-4034)修复方案
Linux 系统安全 - 近期发现的 polkit pkexec 本地提权漏洞(CVE-2021-4034)修复方案
1230 2
|
安全 网络协议 Unix
Linux系统安全与应用
系统安全问题一直存在着,当系统往往出现安全漏洞的时候会对我们的系统运行有一定程度的影响,严重的话还会造成系统瘫痪等问题。
Linux系统安全与应用
下一篇
无影云桌面