news 2026/10/20 8:55:42

Apache Zeppelin 数据源授权(Data Source Authorization):个人凭据管理与 JDBC 连接池实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Apache Zeppelin 数据源授权(Data Source Authorization):个人凭据管理与 JDBC 连接池实践

导读

本文围绕 Apache Zeppelin 的**数据源授权(Data Source Authorization)**特性展开,讲解如何让每位登录用户使用自己的数据库账号(而非共享账号)访问 MySQL、Vertica、Presto 等数据源。读完本文你将掌握:在 Zeppelin UI 或通过 REST API 保存个人凭据的方法、凭据在conf/credentials.json中的存储与加密机制、凭据注入({entity.user}/{entity.password}占位符)与密码打码的原理,以及 JDBC 解释器如何基于这些凭据维护"每用户连接池"。

什么是数据源授权

数据源授权的核心思想是:认证与授权交由数据源自身完成。Zeppelin 并不代替数据库判断某个用户能访问什么表,而是把"以谁的账号登录数据库"这一环节交给用户自己决定,数据库再依据该账号的权限决定其可见范围。

典型场景如下:你已经在 Vertica 数据库中拥有一个账号,希望在 Zeppelin 中通过 JDBC 连接 Vertica 时使用这个账号,而不是让所有定义在conf/shiro.ini中的用户共享同一个数据库账号。此时只需要把自己的凭据(用户名 + 密码)保存到 Zeppelin,解释器即可在运行段落时自动使用它。

这条特性的演进始于 ZEPPELIN-828,由 Pull Request #860 实现;后续的社区管理解释器适配进度可关注 ZEPPELIN-1070(当前仓库中,JDBC 解释器已完整支持该机制,下文源码分析部分会给出依据)。

如何保存凭据信息

通过 UI 下拉菜单添加

在 Zeppelin 界面中打开 Credential 页面,即可在数据源下拉菜单中新增凭据。该交互由 credential.controller.js 实现:

  • 页面初始化时会调用GET /api/interpreter/setting拉取已配置的解释器名称列表,并为 Entity 输入框提供自动补全(angular.element('#entityname').autocomplete(...)),方便你直接选中某个解释器名称作为 Entity;
  • 新增凭据时通过PUT /api/credential提交{entity, username, password};
  • 列表中已有凭据可以就地编辑(仅可改用户名和密码,Entity 作为唯一键不可改)或删除(DELETE /api/credential/{entity})。

Entity 的命名约定:Entity 是区分每组凭据的键。官方建议其命名约定为Interpreter Name(解释器名称),例如为 JDBC 解释器保存的凭据,Entity 就叫jdbc。这样解释器在运行时才能按命名规则找到对应的凭据(下文"JDBC 解释器如何按用户取凭据"一节会说明)。

用户名与密码:填写你自己的数据库账号,例如 JDBC 解释器要连的 MySQL 用户名和密码。

注:原文档中引用的界面截图(Credential 标签页与新增凭据表单)位于docs/assets/themes/zeppelin/img/docs-img/目录下。由于该仓库的 docs 静态图片目录未包含这两张图,本文不强行配图,以文字说明代替。

凭据的归属与持久化

凭据按用户隔离存储,归属规则如下:

  • 若已启用 Shiro 认证(参见 Shiro 认证指南),凭据保存在当前登录用户名下;
  • 若未启用认证,凭据统一保存在anonymous用户名下;
  • 所有凭据最终持久化到conf/credentials.json(默认配置下;配置文件路径由zeppelin.credentials.persist与 conf 目录共同决定,见 ZeppelinConfiguration.java)。

持久化与加密由 Credentials.java 负责:

  • 构造时读取zeppelin.credentials.persist(默认true,见 ConfVars 定义 ZeppelinConfiguration.java),决定是否落盘;
  • 若配置了zeppelin.credentials.encryptKey,则用 Encryptor.java 对文件内容做AES(AESEngine + ZeroBytePadding)加密后 Base64 编码再写入;解密时反向操作;
  • 保存/加载通过ConfigStorage完成(支持本地文件系统等存储后端,见 LocalConfigStorage.java 与 FileSystemConfigStorage.java)。

因此,为保护生产环境中的数据库口令,建议在conf/zeppelin-site.xml中设置:

<property> <name>zeppelin.credentials.encryptKey</name> <value>your-encrypt-key</value> <description>Key used to encrypt credentials. If not set, credentials are stored in plain text.</description> </property>

通过 REST API 管理凭据

凭据管理同样暴露为 REST API,由 CredentialRestApi.java 实现(@Path("/credential")),接口行为与 UI 页面一一对应:

  • GET /api/credential:返回当前用户的全部凭据(实体、用户名、密码);
  • PUT /api/credential:新增/更新凭据,请求体 JSON 为{"entity": "jdbc", "username": "user", "password": "password"};任一字段为空时返回400 BAD_REQUEST;
  • DELETE /api/credential:删除当前用户的全部凭据,不存在时返回404 NOT_FOUND;
  • DELETE /api/credential/{entity}:删除指定 Entity 的凭据,不存在时返回404 NOT_FOUND。

完整的请求/响应示例可参考 Credential REST API 文档,例如保存一条凭据:

curl -X PUT -H "Content-Type: application/json" -d '{"entity":"jdbc","username":"mysql_user","password":"mysql_password"}' \ http://[zeppelin-server]:[zeppelin-port]/api/credential/

需要说明的是,上述 REST API 文档中的示例以entity1/user1/password1等占位符形式给出,实际使用时应替换为真实 Entity 与账号口令。该 API 的测试用例位于 CredentialsRestApiTest.java,覆盖了凭据的存取与删除流程。

不同数据源的凭据使用差异

原文档针对三类常见数据源给出了差异化的说明:

  • JDBC 解释器:需要维护每用户(per-user)的连接池。解释器的interpret方法以用户字符串为参数,从对应用户的连接池中取出连接执行 JDBC 调用。具体实现见下文源码分析。
  • Presto:如果 Presto 后端代码基于用户执行 HDFS 授权,那么可以不提供密码,凭据中可以只保存用户名。
  • Vertica 与 MySQL:必须为用户存储密码信息,连接时以"用户名 + 密码"完成认证。

源码级原理解析

JDBC 解释器如何按用户取凭据

JDBCInterpreter.java 完整实现了凭据驱动的连接管理,关键逻辑如下:

  1. 解析当前用户:getUser(context)优先取登录用户(Shiro principal);若为anonymous且解释器设置了default.user,则回退使用该属性值(JDBCInterpreter.java)。
  2. 解析 Entity 命名:getEntityName(replName, propertyKey)规定——当解释器名恰为jdbc时,Entity 取属性键本身(default);否则取解释器名(JDBCInterpreter.java)。这正是官方建议"Entity 用解释器名"的代码依据。
  3. 读取凭据:getUsernamePassword(context, entity)从context.getAuthenticationInfo().getUserCredentials()中按 Entity 取出UsernamePassword(JDBCInterpreter.java)。
  4. 每用户连接池:setUserProperty(context)在解释器自身未配置default.user/default.password时,用当前用户凭据覆盖用户属性;随后createConnectionPool(url, user, properties)以jdbc:apache:commons:dbcp:default{user}这样的池名注册 DBCP 连接池(JDBCInterpreter.java、JDBCInterpreter.java),从而实现"一个用户一个连接池"。若找不到该用户的凭据,则关闭该用户连接池(closeDBPool(user))。

与此对应的官方文档说明见 JDBC 解释器文档:当default.user与default.password被删除(使用 X 按钮)后,解释器会转而使用用户在 Credential 页面保存的凭据建立连接。

凭据注入与密码打码

除 JDBC 解释器外,Zeppelin 还提供了通用的凭据注入机制,由 Paragraph.java 与 CredentialInjector.java 实现:

  • 解释器属性injectCredentials(常量定义见 Constants.java)控制是否启用注入,默认false;
  • 启用后,段落的脚本中形如{entity.user}与{entity.password}的占位符会被替换为对应 Entity 的用户名与密码;
  • 注入的密码在返回结果中会被打码:CredentialInjector.hidePasswords(ret)会把结果中出现的密码文本替换为###,避免凭据随结果泄露(覆盖 HTML / TEXT / TABLE 三种结果类型)。

例如,在段落中写:

%jdbc SELECT * FROM table WHERE creator = '{jdbc.user}'

启用injectCredentials后,{jdbc.user}会被替换为当前用户在 Credential 页面中为 Entityjdbc保存的用户名。

凭据的数据模型

凭据按"用户 → 多个 Entity → 用户名/密码"三层组织:

  • 顶层是 Credentials.java 持有的Map<String, UserCredentials> credentialsMap,key 为用户名;
  • 每个UserCredentials内部再按 Entity 维护多组UsernamePassword(其结构定义见 CredentialsInfoSaving.java 等org.apache.zeppelin.user包下的类);
  • 落到conf/credentials.json时,大致形态为:
{ "credentialsMap": { "anonymous": { "userCredentials": { "jdbc": { "username": "mysql_user", "password": "mysql_password" } } } } }

(以上 JSON 仅用于示意结构,实际字段名以CredentialsInfoSaving的 Gson 序列化结果为准。)相关单元测试见 CredentialsTest.java 与 EncryptorTest.java。

使用注意事项

  • 先启用认证,再谈用户隔离:如果希望每位用户使用各自数据库账号,请先按 Shiro 认证指南 配置认证;否则所有凭据都归入anonymous,也就失去了"个人凭据"的意义。
  • Entity 命名保持一致:JDBC 解释器按getEntityName规则(解释器名为jdbc时取default,否则取解释器名)查找凭据,保存凭据时 Entity 务必与解释器命名匹配。
  • 密码存储安全:默认zeppelin.credentials.persist=true会将凭据写入conf/credentials.json;生产环境应配置zeppelin.credentials.encryptKey启用 AES 加密,并保护好该密钥文件本身。
  • 凭据注入按需开启:injectCredentials默认关闭,只有确实需要在段落脚本中使用{entity.user}/{entity.password}占位符时才开启,且注意其会对返回结果中的密码做###打码处理。
  • 数据库侧差异:Presto 在依赖 HDFS 授权时可只保存用户名;Vertica、MySQL 等必须同时保存用户名与密码。
  • 适用范围:该特性最初面向自定义第三方解释器设计(ZEPPELIN-828),当前仓库中 JDBC 解释器已原生支持;使用其他解释器时请以其文档为准确认是否支持凭据读取。

总结

数据源授权让 Zeppelin 把"数据库认证与授权"交还给数据源本身,同时通过 UI、REST API 两层入口为用户提供个人凭据的保存、查询、更新与删除能力。其底层由Credentials(持久化 + AES 加密)、CredentialRestApi(REST 接口)、JDBCInterpreter(每用户连接池)与CredentialInjector(占位符注入 + 密码打码)协同完成。围绕该特性的核心代码与文档均可在当前仓库中定位到:datasource_authorization.md、Credentials.java、JDBCInterpreter.java、credential.controller.js。

  • 数据分析
  • 数据可视化
  • 大数据
  • 后端

【免费下载链接】zeppelin

Web-based notebook that enables>项目地址:https://gitcode.com/gh_mirrors/zeppelin1/zeppelin

点击查看免费下载

相关推荐

上一篇:Hitboxer:告别游戏操作冲突,实现键盘精准控制的终极解决方案
下一篇:终极Hitboxer指南:免费开源SOCD清洁工具让你的游戏操作更精准

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/20 3:18:04

Android Studio安装配置全指南:打不开问题排查与values多语言创建

很多朋友第一次接触 Android 开发&#xff0c;最先卡住的地方往往不是代码&#xff0c;而是环境搭建这一步。Android Studio 的安装过程看起来就是“下一步、下一步”&#xff0c;但实际上牵扯到 JDK 版本、SDK 目录、系统变量、模拟器性能这些细节&#xff0c;任何一个地方出了…

作者头像 李华
网站建设 2026/10/14 7:47:00

安防监控视频汇聚实战:EasyCVR平台架构与部署经验

1. 为什么安防监控越来越需要"视频汇聚"这一步先聊个我在实际项目里最常见的场景。一个中型园区&#xff0c;前端摄像头可能有五六种品牌&#xff0c;海康、大华、宇视、天地伟业&#xff0c;再加上一些老旧的模拟摄像头通过编码器接入。监控室里的NVR各有各的IP&…

作者头像 李华
网站建设 2026/10/14 11:46:19

为AI编程助手打造持久记忆:claude-mem上下文管理实践

上周我在做模拟项目X的跨平台重构时遇到一个特别闹心的事&#xff1a;白天和Claude Code讨论好的接口设计&#xff0c;晚上新建会话想继续改代码&#xff0c;它居然完全不记得我们上午定好的方案&#xff0c;上下文里只剩当时贴进去的那几段代码。我一拍桌子&#xff0c;决定自…

作者头像 李华
网站建设 2026/10/15 15:05:53

PS5手柄跨平台适配方案:AnyPS5如何解锁DualSense完整体验

第一次把PS5手柄接到电脑上那个下午&#xff0c;我原本以为会是无缝衔接&#xff1a;插线、装驱动、打开游戏、开玩。结果折腾了半个多小时&#xff0c;灯是亮了&#xff0c;但键位错乱、扳机死沉、触觉反馈全部失效。后来我才意识到&#xff0c;PS5的DualSense虽然是市面上手感…

作者头像 李华
网站建设 2026/10/19 19:52:54

单片机计算机毕设之基于单片机的室内甲醛超标本地声光与手机远程双重报警系统设计 基于单片机的学生宿舍空气质量无线监测与自动通风装置设计(030111)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于嵌入式单片机&#xff0c;Java、小程序技术领域和毕业项目实战 ✌️…

作者头像 李华