概述
Dubbo 框架支持通过令牌验证在注册中心控制权限,以决定是否下发令牌给消费者,以防止消费者绕过注册中心访问服务提供者,另外通过注册中心可灵活改变授权方式,而不需修改或升级提供者。

配置
- 全局开启令牌
1 2 3 4
| <dubbo:provider interface="com.foo.BarService" token="true" />
<dubbo:provider interface="com.foo.BarService" token="123456" />
|
- 服务级别开启令牌
1 2 3 4
| <dubbo:service interface="com.foo.BarService" token="true" />
<dubbo:service interface="com.foo.BarService" token="123456" />
|
Token 流转
服务提供端
1 2 3 4 5 6 7 8 9 10
| +--- ServiceConfig#doExportUrlsFor1Protocol if (!ConfigUtils.isEmpty(token)) { if (ConfigUtils.isDefault(token)) { map.put(Constants.TOKEN_KEY, UUID.randomUUID().toString()); } else { map.put(Constants.TOKEN_KEY, token); } }
|
服务提供者将设置的 Token 最终会设置到 URL 中,最终写入到注册中心上。
服务消费端
服务消费者从注册中心获取服务提供者的 URL ,从而获得该服务的 Token 。在创建 RpcInvocation 时会自动带上 Token,最终会将 Token 发送到服务提供方,而 TokenFilter 就是处理来自服务消费方的 Token 的。
TokenFilter
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| @Activate(group = Constants.PROVIDER, value = Constants.TOKEN_KEY) public class TokenFilter implements Filter {
@Override public Result invoke(Invoker<?> invoker, Invocation inv) throws RpcException { String token = invoker.getUrl().getParameter(Constants.TOKEN_KEY); if (ConfigUtils.isNotEmpty(token)) { Class<?> serviceType = invoker.getInterface(); Map<String, String> attachments = inv.getAttachments(); String remoteToken = attachments == null ? null : attachments.get(Constants.TOKEN_KEY);
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); } }
|