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

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介: 【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月前
|
XML Dubbo Java
【Dubbo3高级特性】「框架与服务」服务的异步调用实践以及开发模式
【Dubbo3高级特性】「框架与服务」服务的异步调用实践以及开发模式
46 0
|
1月前
|
SpringCloudAlibaba 负载均衡 Dubbo
SpringCloudAlibaba:3.2dubbo的高级特性
SpringCloudAlibaba:3.2dubbo的高级特性
30 1
|
1月前
|
XML Dubbo Java
【Dubbo3高级特性】「框架与服务」 Nacos作为注册中心-服务分组及服务分组聚合实现
【Dubbo3高级特性】「框架与服务」 Nacos作为注册中心-服务分组及服务分组聚合实现
75 0
|
1月前
|
Cloud Native Dubbo 应用服务中间件
【Dubbo3高级特性】「微服务云原生架构」带你从零基础认识搭建公司内部服务用户中心体系(实战指南-序章)
【Dubbo3高级特性】「微服务云原生架构」带你从零基础认识搭建公司内部服务用户中心体系(实战指南-序章)
75 0
|
1月前
|
Java fastjson 数据安全/隐私保护
【Dubbo3技术专题】「云原生微服务开发实战」 一同探索和分析研究RPC服务的底层原理和实现
【Dubbo3技术专题】「云原生微服务开发实战」 一同探索和分析研究RPC服务的底层原理和实现
59 0
|
1月前
|
Dubbo Java 应用服务中间件
微服务学习 | Springboot整合Dubbo+Nacos实现RPC调用
微服务学习 | Springboot整合Dubbo+Nacos实现RPC调用
|
7月前
|
负载均衡 Dubbo 应用服务中间件
微服务技术系列教程(31) - Dubbo-原理及负载均衡分析
微服务技术系列教程(31) - Dubbo-原理及负载均衡分析
60 0
|
7月前
|
Dubbo Java 应用服务中间件
微服务技术系列教程(30) - Dubbo-SpringCloud与Dubbo区别
微服务技术系列教程(30) - Dubbo-SpringCloud与Dubbo区别
51 0
|
1月前
|
Dubbo Java 应用服务中间件
阿里巴巴资深架构师深度解析微服务架构设计之SpringCloud+Dubbo
软件架构是一个包含各种组织的系统组织,这些组件包括Web服务器,应用服务器,数据库,存储,通讯层),它们彼此或和环境存在关系。系统架构的目标是解决利益相关者的关注点。
|
23天前
|
Dubbo Cloud Native 应用服务中间件
【阿里云云原生专栏】云原生环境下的微服务治理:阿里云 Dubbo 与 Nacos 的深度整合
【5月更文挑战第25天】阿里云Dubbo和Nacos提供微服务治理的强大工具,整合后实现灵活高效的治理。Dubbo是高性能RPC框架,Nacos则负责服务发现和配置管理。整合示例显示,通过Nacos注册中心,服务能便捷注册发现,动态管理配置。简化部署,提升适应性,但也需注意服务稳定性和策略规划。这种整合为云原生环境的微服务架构带来强大支持,未来应用前景广阔。
214 2