ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Apache Zeppelin 使用 Apache Shiro 实现 Notebook 认证与权限控制完整指南

2026/10/6 15:48:42 拓冰建站 浏览量
Apache Zeppelin 使用 Apache Shiro 实现 Notebook 认证与权限控制完整指南 数据分析数据可视化大数据后端前端任务调度【免费下载链接】zeppelinWeb-based notebook that enables>项目地址https://gitcode.com/gh_mirrors/zeppe/zeppelin点击查看免费下载Apache Shiro 是一个强大且易用的 Java 安全框架涵盖认证Authentication、授权Authorization、加密Cryptography与会话管理Session Management四大能力。本文基于 Zeppelin 仓库的 官方安全文档 与 shiro.ini 模板系统讲解如何为 Zeppelin Notebook 启用 Shiro 认证、配置用户与角色、接入 Active Directory / LDAP / PAM / Knox SSO / Kerberos SPNEGO 等企业级身份源以及如何通过 URL 级权限与安全 Cookie 加固整个 Web 服务。读完本文你将能够独立完成从匿名访问到多身份源、基于角色的细粒度授权的完整安全改造。OverviewShiro 如何保护 Zeppelin NotebookApache Shiro 是一个纯 Java 实现的安全框架在 Zeppelin 中扮演认证与授权的核心角色。启用后当你访问 Apache Zeppelin Web 界面时会先被要求输入凭据用户名与密码登录成功后你便拥有访问所有笔记Note的权限——包括其他用户创建的笔记。也就是说Shiro 解决的是谁能进入系统与进入后能访问哪些功能这两类问题。Important Note重要提示默认情况下Zeppelin 允许匿名访问。官方强烈建议你按本文档所述配置 Apache Shiro 认证至少完成下文安全加固相关步骤或者仅在受控、可信的安全环境中部署和使用 Zeppelin。三步启用 Zeppelin Notebook 认证Zeppelin 的 notebook 认证配置非常简单只需以下几个步骤。1. 启用 ShiroEnable Shiro在 Zeppelin 的conf目录下默认提供了shiro.ini.template它只是示例模板。官方强烈建议通过下面的命令复制生成真正的shiro.ini文件cp conf/shiro.ini.template conf/shiro.inishiro.ini采用 Shiro 标准的 INI 文件格式分为[main]Bean 配置、[users]静态用户、[roles]角色定义、[urls]URL 过滤规则等小节。关于shiro.ini文件格式的更多信息可参考 Shiro 官方 Configuration 文档INI Sections 章节。仓库自带的 conf/shiro.ini.template 本身就是一个带有大量中文/英文注释的可直接参考样例。2. 启动 Zeppelinbin/zeppelin-daemon.sh start #(或 restart)启动完成后在浏览器中访问 http://localhost:8080 即可看到 Zeppelin 界面。3. 登录Login访问时会出现登录窗口使用以下任一用户名/密码组合即可登录[users] admin password1, admin user1 password2, role1, role2 user2 password3, role3 user3 password4, role2上述配置中每个用户的密码之后紧跟其拥有的角色roles角色可设置多个逗号分隔。例如admin拥有admin角色user1同时拥有role1与role2两个角色。Groups and permissionsLDAP / AD 目录服务的角色映射可选如果你希望借助用户组Group与权限Permission体系进行管理可以在shiro.ini的[main]段配置 LDAP 或 Active Directory Realm。示例配置如下activeDirectoryRealm org.apache.zeppelin.realm.ActiveDirectoryGroupRealm activeDirectoryRealm.systemUsername userNameA activeDirectoryRealm.systemPassword passwordA activeDirectoryRealm.searchBase CNUsers,DCSOME_GROUP,DCCOMPANY,DCCOM activeDirectoryRealm.url ldap://ldap.test.com:389 activeDirectoryRealm.groupRolesMap CNaGroupName,OUgroups,DCSOME_GROUP,DCCOMPANY,DCCOM:group1 activeDirectoryRealm.authorizationCachingEnabled false activeDirectoryRealm.principalSuffix corp.company.net ldapRealm org.apache.zeppelin.realm.LdapGroupRealm # search base for ldap groups (only relevant for LdapGroupRealm): ldapRealm.contextFactory.environment[ldap.searchBase] dcCOMPANY,dcCOM ldapRealm.contextFactory.url ldap://ldap.test.com:389 ldapRealm.userDnTemplate uid{0},ouUsers,dcCOMPANY,dcCOM ldapRealm.contextFactory.authenticationMechanism simple其中groupRolesMap将目录中的实际组如CNaGroupName,OUgroups,...映射为系统内的逻辑角色如group1principalSuffix用于给用户名自动追加域后缀如corp.company.net便于以user而非usercorp.company.net的形式登录authorizationCachingEnabled false关闭授权信息缓存确保组变更实时生效。与此同时还需要在shiro.ini中定义希望在系统内使用的角色/组例如[roles] admin * hr * finance * group1 *这里*表示该角色拥有全部权限通配符。Configure Realm深入理解与配置各类 Realm可选Realm 是 Apache Zeppelin 中负责认证与授权的核心组件。默认情况下Zeppelin 使用IniRealm即直接在conf/shiro.ini的[user]与[group]实际为[users]与[roles]段中配置用户和组。你也可以改用 Shiro 自带的JndiLdapRealm、JdbcRealm或自定义实现AuthorizingRealm。Note当使用以下任意社区自定义 Realm 时默认的基于密码的 IniRealm 认证需要被禁用即不再依赖[users]段的静态账号完成认证。Active Directory使用 Zeppelin 自带的ActiveDirectoryGroupRealm在[main]段配置activeDirectoryRealm org.apache.zeppelin.realm.ActiveDirectoryGroupRealm activeDirectoryRealm.systemUsername userNameA activeDirectoryRealm.systemPassword passwordA activeDirectoryRealm.hadoopSecurityCredentialPath jceks://file/user/zeppelin/conf/zeppelin.jceks activeDirectoryRealm.searchBase CNUsers,DCSOME_GROUP,DCCOMPANY,DCCOM activeDirectoryRealm.url ldap://ldap.test.com:389 activeDirectoryRealm.groupRolesMap CNaGroupName,OUgroups,DCSOME_GROUP,DCCOMPANY,DCCOM:group1 activeDirectoryRealm.authorizationCachingEnabled false activeDirectoryRealm.principalSuffix corp.company.net从源码看ActiveDirectoryGroupRealm.java 继承自 Shiro 的AbstractLdapRealm其认证流程为先用用户提交的用户名/密码直接绑定 LDAP 上下文bind 成功即密码正确再通过系统账号在searchBase下检索用户的memberOf属性最后用groupRolesMap将组名翻译为角色名见getRoleNamesForGroups方法。使用 Hadoop Credential 保护系统密码除了在shiro.ini中以明文形式配置systemPassword管理员还可以把密码放入 Hadoop Credentialjceks 密钥库。创建密钥库需要 hadoop-commons 在 classpath 中执行hadoop credential create activeDirectoryRealm.systempassword -provider jceks://file/user/zeppelin/conf/zeppelin.jceks然后在shiro.ini中取消注释并配置以下行即可activeDirectoryRealm.hadoopSecurityCredentialPath jceks://file/user/zeppelin/conf/zeppelin.jceks从源码看ActiveDirectoryGroupRealm.java 的getSystemPassword()会优先读取hadoopSecurityCredentialPath指向的 jceks 中的凭据alias 为activeDirectoryRealm.systemPassword仅在未配置时才回退到明文systemPassword。LDAPLDAP Realm 有两种配置方式。较简单的是LdapGroupRealm但它对LDAP 组 → 用户的映射以及基于用户组的授权灵活性有限。样例配置ldapRealm org.apache.zeppelin.realm.LdapGroupRealm # search base for ldap groups (only relevant for LdapGroupRealm): ldapRealm.contextFactory.environment[ldap.searchBase] dcCOMPANY,dcCOM ldapRealm.contextFactory.url ldap://ldap.test.com:389 ldapRealm.userDnTemplate uid{0},ouUsers,dcCOMPANY,dcCOM ldapRealm.contextFactory.authenticationMechanism simple更灵活的是LdapRealm。它支持把 LDAP 组映射到角色roles也支持基于角色/组的认证准入控制。完整样例配置如下[main] ldapRealmorg.apache.zeppelin.realm.LdapRealm ldapRealm.contextFactory.authenticationMechanism simple ldapRealm.contextFactory.url ldap://localhost:33389 ldapRealm.userDnTemplate uid{0},oupeople,dchadoop,dcapache,dcorg # Ability to set ldap paging Size if needed default is 100 ldapRealm.pagingSize 200 ldapRealm.authorizationEnabled true ldapRealm.searchBase dchadoop,dcapache,dcorg ldapRealm.userSearchBase dchadoop,dcapache,dcorg ldapRealm.groupSearchBase ougroups,dchadoop,dcapache,dcorg ldapRealm.groupObjectClass groupofnames # Allow userSearchAttribute to be customized # If userSearchAttributeName was configured, Zeppelin would use userObjectClass and userSearchAttributeName to search for an actual user DN # Otherwise, memberAttributeValueTemplate would be used to construct the user DN. ldapRealm.userSearchAttributeName sAMAccountName ldapRealm.memberAttribute member # force usernames returned from ldap to lowercase useful for AD ldapRealm.userLowerCase true # ability set searchScopes subtree (default), one, base ldapRealm.userSearchScope subtree; ldapRealm.groupSearchScope subtree; ldapRealm.memberAttributeValueTemplate cn{0},oupeople,dchadoop,dcapache,dcorg ldapRealm.contextFactory.systemUsername uidguest,oupeople,dchadoop,dcapache,dcorg ldapRealm.contextFactory.systemPassword S{ALIASldcSystemPassword} # enable support for nested groups using the LDAP_MATCHING_RULE_IN_CHAIN operator ldapRealm.groupSearchEnableMatchingRuleInChain true # optional mapping from physical groups to logical application roles ldapRealm.rolesByGroup LDN_USERS: user_role, NYK_USERS: user_role, HKG_USERS: user_role, GLOBAL_ADMIN: admin_role # optional list of roles that are allowed to authenticate. Incase not present all groups are allowed to authenticate (login). # This changes nothing for url specific permissions that will continue to work as specified in [urls]. ldapRealm.allowedRolesForAuthentication admin_role,user_role ldapRealm.permissionsByRole user_role *:ToDoItemsJdo:*:*, *:ToDoItem:*:*; admin_role * securityManager.sessionManager $sessionManager securityManager.realms $ldapRealm对照源码 LdapRealm.java 可以确认以下实现细节pagingSize默认值为100用于控制 LDAP 分页查询的每页结果数groupObjectClass默认值为groupOfNamesmemberAttribute默认值为membergroupIdAttribute默认值为cn当配置了userSearchAttributeName如sAMAccountName时Zeppelin 会先用系统账号在userSearchBaseuserObjectClass范围内检索真实用户 DN否则直接通过memberAttributeValueTemplate拼接出用户 DNuserSearchScope/groupSearchScope支持subtree默认、one、base三种取值对应SearchControls的不同搜索深度groupSearchEnableMatchingRuleInChain true时使用 LDAP 的1.2.840.113556.1.4.1941MATCHING_RULE_IN_CHAIN 操作符实现嵌套组Nested Group支持rolesByGroup提供物理组 → 逻辑应用角色的可选映射allowedRolesForAuthentication提供允许登录的角色白名单为空时所有组均可登录只影响登录准入不影响 [urls] 中的 URL 权限permissionsByRole定义每个角色拥有的 Shiro 通配符权限;分隔角色条目分隔角色与权限,分隔同一角色的多条权限组搜索的结果会同时保存到 Shiro Session 的subject.userRoles/subject.userGroups属性中方便其他模块读取。RoleMappingLdapRealm用户直配角色对于某些LDAP 组与用户没有映射关系的目录结构可以选择RoleMappingLdapRealm它允许直接把用户名映射到角色ldapRealm org.apache.zeppelin.realm.RoleMappingLdapRealm ldapRealm.rolesByUsername user1:admin,user2:user,user3:user,user4:user ldapRealm.defaultRole guest对照源码 RoleMappingLdapRealm.javarolesByUsername支持一个用户映射多个角色逗号分隔未在映射表中的用户将获得defaultRole源码默认值为role1。LDAP 系统密码的 Hadoop Credential 方式同样地可以不在shiro.ini中明文写systemPassword而是用 Hadoop credential 命令行创建密钥库hadoop credential create ldapRealm.systemPassword -provider jceks://file/user/zeppelin/conf/zeppelin.jceks然后在shiro.ini中添加ldapRealm.hadoopSecurityCredentialPath jceks://file/user/zeppelin/conf/zeppelin.jceks从源码看LdapRealm.java 的onInit()会通过getSystemPassword(hadoopSecurityCredentialPath, ldapRealm.systemPassword)从 jceks 中读取系统密码并设置到JndiLdapContextFactory。Caution已知限制由于 LdapRealm 的一个已知缺陷从 LDAP 只获取ldapRealm.pagingSize数量的结果。在大目录树中这可能导致角色Roles缺失。建议通过ldapRealm.groupSearchBase限制搜索范围或用ldapRealm.groupSearchFilter收窄所需组。PAMPAM可插拔认证模块认证支持复用 Zeppelin 所在主机上已有的认证模块。在典型 Linux 系统上模块按服务如sshd、passwd等配置在/etc/pam.d/目录下。你可以复用其中一个服务也可以为 Zeppelin 单独创建一个。启用 PAM 认证需要两个参数realm所使用的 Shiro Realmservice/etc/pam.d/下要使用的服务名称必须与/etc/pam.d/下的文件名一致。[main] pamRealmorg.apache.zeppelin.realm.PamRealm pamRealm.servicesshd从源码看PamRealm.java 基于 libpam4j 实现doGetAuthenticationInfo中调用new PAM(service).authenticate(username, password)完成认证doGetAuthorizationInfo则把 PAM 用户的 Unix 组直接作为 Shiro 角色返回user.getUnixUser().getGroups()。Knox SSOKnoxSSO 为接入多种认证系统与 SSO 解决方案提供了抽象层使参与的 Web 应用无需为每个解决方案单独做集成。当 Zeppelin 启用 Knox SSO 后系统会在内部使用 Apache Hadoop Groups Mapping 来确定登录用户的组成员关系并据此设置基于组的角色访问权限。在conf/shiro.ini的[main]段做如下修改即可启用### A sample for configuring Knox JWT Realm knoxJwtRealm org.apache.zeppelin.realm.jwt.KnoxJwtRealm ## Domain of Knox SSO knoxJwtRealm.providerUrl https://domain.example.com/ ## Url for login knoxJwtRealm.login gateway/knoxsso/knoxauth/login.html ## Url for logout knoxJwtRealm.logout gateway/knoxssout/api/v1/webssout knoxJwtRealm.redirectParam originalUrl knoxJwtRealm.cookieName hadoop-jwt knoxJwtRealm.publicKeyPath /etc/zeppelin/conf/knox-sso.pem # This is required if KNOX SSO is enabled, to check if knoxJwtRealm.cookieName cookie was expired/deleted. authc org.apache.zeppelin.realm.jwt.KnoxAuthenticationFilter从源码看KnoxJwtRealm.java 使用 nimbus-jose-jwt 解析并校验 JWTvalidateToken会依次验证 RSA 签名通过publicKeyPath指定的 X.509 PEM 公钥证书与过期时间JWT 必须包含exp声明认证通过后通过 HadoopGroups实现获取用户组作为角色。authc过滤器被替换为KnoxAuthenticationFilter用于检查hadoop-jwtCookie 是否过期/被删除。仓库的 shiro.ini.template 中该段还额外提供了knoxJwtRealm.logoutAPI true选项。HTTP SPNEGO AuthenticationKerberosHTTP SPNEGOSimple and Protected GSS-API NEGOtiation是基于 Kerberos Ticket 的 Web 服务用户认证标准方式。Zeppelin 基于 Apache Hadoop Auth 支持通过接受并校验用户的 Kerberos Ticket 来完成认证。启用后同样会使用 Hadoop Groups Mapping 确定用户组从而设置基于组的角色权限。在conf/shiro.ini的[main]段配置krbRealm org.apache.zeppelin.realm.kerberos.KerberosRealm krbRealm.principalHTTP/zeppelin.fqdn.domain.comEXAMPLE.COM krbRealm.keytab/etc/security/keytabs/spnego.service.keytab krbRealm.nameRulesDEFAULT krbRealm.signatureSecretFile/etc/security/http_secret krbRealm.tokenValidity36000 krbRealm.cookieDomaindomain.com krbRealm.cookiePath/ authc org.apache.zeppelin.realm.kerberos.KerberosAuthenticationFilter对照源码 KerberosRealm.java 可以看到关键实现onInit()中加载 principal 与 keytab 并初始化 GSSManagerauthenticate()通过WWW-Authenticate: Negotiate触发 SPNEGO 握手认证成功后生成被签名 Cookiehadoop.authtokenValidity默认 36000 秒10 小时doGetAuthorizationInfo通过 HadoopGroups查询用户组作为角色。模板中该段还支持krbRealm.logout、krbRealm.logoutAPI、krbRealm.providerUrl、krbRealm.redirectParam等扩展配置。上述配置要正常工作还需要在 Zeppelin 之外完成一些前置工作1. 准备有效的 SPNEGO keytab位于 Zeppelin 节点上且可被zeppelin用户读取。如果已有其他 Hadoop 服务生成的 SPNEGO keytab可直接复用无需重新生成。一个可用 keytab 的示例$ klist -kt /etc/security/keytabs/spnego.service.keytab Keytab name: FILE:/etc/security/keytabs/spnego.service.keytab KVNO Timestamp Principal ---- ------------------- ------------------------------------------------------ 2 11/26/2018 16:58:38 HTTP/zeppelin.fqdn.domain.comEXAMPLE.COM 2 11/26/2018 16:58:38 HTTP/zeppelin.fqdn.domain.comEXAMPLE.COM 2 11/26/2018 16:58:38 HTTP/zeppelin.fqdn.domain.comEXAMPLE.COM确保 keytab 权限足够严格同时仍可被zeppelin用户读取$ ls -l /etc/security/keytabs/spnego.service.keytab -r--r-----. 1 root hadoop 346 Nov 26 16:58 /etc/security/keytabs/spnego.service.keytab注意上例中zeppelin用户之所以能读取 keytab是因为它是hadoop组的成员。2. 准备签名密钥文件位于 Zeppelin 节点上且可被zeppelin用户读取。该文件包含用于签署 SPNEGO 交互过程中生成的hadoop.authCookie 的随机二进制数据。如果节点上已有此类文件应优先复用。需要生成时使用以下命令dd if/dev/urandom of/etc/security/http_secret bs1024 count1 chown hdfs:hadoop /etc/security/http_secret chmod 440 /etc/security/http_secretSecure Cookie为 Zeppelin 会话启用 HttpOnly可选Zeppelin 可以在会话 Cookie 上设置HttpOnly标志。开启后Zeppelin 的 Cookie 无法被客户端脚本读取从而能防御绝大多数跨站脚本XSS攻击。在conf/shiro.ini的[main]段中、定义sessionManager之后添加以下配置cookie org.apache.shiro.web.servlet.SimpleCookie cookie.name JSESSIONID cookie.secure true cookie.httpOnly true sessionManager.sessionIdCookie $cookie仓库的 shiro.ini.template 默认已启用cookie.httpOnly true并额外提供了cookie.sameSite LAX默认限制会话 Cookie 为同站请求仅在 Zeppelin 被有意嵌入其他 origin 时设置为 NONEcookie.secure true仅在 Zeppelin 运行于 HTTPS 时取消注释启用。模板中还配置了securityManager.sessionManager.globalSessionTimeout 86400000即 24 小时以及shiro.loginUrl /api/login。Secure your Zeppelin informationURL 级授权保护敏感信息可选默认情况下任何在[users]中定义的用户都可以查看 Zeppelin 的Interpreter Setting解释器设置、Credential凭据和Configuration配置信息。某些场景下你可能希望隐藏这些信息。由于 Shiro 提供url-based security基于 URL 的安全你可以通过注释/取消注释conf/shiro.ini中的以下行来实现[urls] /api/interpreter/** authc, roles[admin] /api/configurations/** authc, roles[admin] /api/credential/** authc, roles[admin]这样只有拥有admin角色的用户才能看到Interpreter Setting、Credential和Configuration信息。若想把这些权限授予其他用户只需修改roles[ ]中定义的角色与[users]段保持一致。对照 shiro.ini.template 的[urls]段可以看到更完整的默认策略/api/version与/api/cluster/address保持anon匿名/api/interpreter/setting/restart/**默认允许所有已认证用户重启解释器如需仅限 admin 可注释该行/api/interpreter/**、/api/notebook-repositories/**、/api/configurations/**、/api/credential/**、/api/admin/**均要求authc, roles[admin]末尾的/** authc表示除上述外所有路径都要求登录而注释中的/** anon则允许匿名访问所有未列出的 URL。注意 URL 规则的匹配顺序自上而下第一条匹配生效。多角色AND 语义默认情况下Shiro 只有在用户同时拥有 URL 规则中定义的所有角色时才放行例如[urls] /api/interpreter/** authc, roles[admin, role1]多角色或指定用户OR 语义如果希望满足任意一个定义的角色或用户本身即可放行可以使用 Zeppelin 自带的AnyOfRolesUserAuthorizationFilter[main] anyofrolesuser org.apache.zeppelin.utils.AnyOfRolesUserAuthorizationFilter [urls] /api/interpreter/** authc, anyofrolesuser[admin, user1] /api/configurations/** authc, roles[admin] /api/credential/** authc, roles[admin]对照源码 AnyOfRolesUserAuthorizationFilter.java它与 Shiro 原生RolesAuthorizationFilter的区别在于原生过滤器使用 AND 语义而isAccessAllowed()中遍历角色数组只要subject.hasRole(roleName)成立或subject.getPrincipal()恰好等于roleName即该用户本身即返回true。对应测试见 AnyOfRolesUserAuthorizationFilterTest.java。NOTE以上所有配置都定义在conf/shiro.ini文件中。FAQ代理 Basic 认证场景下的认证头处理问题Zeppelin 服务器配置为表单认证form-based authentication但它位于配置为 Basic 认证的代理例如 NGINX见 HTTP Basic Authentication using NGINX之后且不希望 Zeppelin 服务器清掉认证头。解决在zeppelin-site.xml中将zeppelin.server.authorization.header.clear设置为falsezeppelin.server.authorization.header.clear false该配置项在仓库 conf/zeppelin-site.xml.template 中有对应定义默认值为true描述为Authorization header to be cleared if server is running as authcBasic。当 Zeppelin 自身以authcBasic之外的认证模式运行时若需要透传上游代理注入的认证头如X-Auth-User等代理认证结果就需要关闭此开关否则 Zeppelin 会按默认行为清掉该头。Other authentication methods其他认证方式除 Shiro 之外Zeppelin 还支持其他认证接入方式例如 HTTP Basic Authentication using NGINX。该方案通过反向代理在 Zeppelin 前面完成 Basic 认证适用于不希望把认证逻辑放进 Zeppelin 进程本身的部署形态可与本文的 Shiro 配置结合形成代理层认证 应用层授权的分层安全架构。小结从静态账号IniRealm到企业级目录服务Active Directory / LDAP / RoleMappingLdapRealm再到主机级 PAM、统一 SSOKnox SSO与 Kerberos SPNEGOZeppelin 通过 Apache Shiro 提供了覆盖绝大多数企业场景的认证与授权能力。核心配置文件始终是conf/shiro.ini由 conf/shiro.ini.template 复制而来配合[main]Realm 与过滤器 Bean、[users]静态用户、[roles]角色定义与[urls]URL 级权限四个小节即可实现从匿名开放到细粒度角色授权的完整安全闭环。所有自定义 Realm 与过滤器ActiveDirectoryGroupRealm、LdapGroupRealm、LdapRealm、RoleMappingLdapRealm、PamRealm、KnoxJwtRealm、KerberosRealm、AnyOfRolesUserAuthorizationFilter均可在 zeppelin-server 源码 中查看其具体实现与默认值配合各 Realm 的单元测试如 LdapRealmTest.java、PamRealmTest.java、KnoxJwtRealmTest.java可进一步验证其行为。赞分享数据分析数据可视化大数据后端前端任务调度【免费下载链接】zeppelinWeb-based notebook that enables>项目地址https://gitcode.com/gh_mirrors/zeppe/zeppelin点击查看免费下载相关推荐Apache Zeppelin 多用户支持完全指南Shiro 认证、Notebook 授权、用户模拟与隔离模式Apache Zeppelin 多用户支持完全指南Shiro 认证、Notebook 授权、用户模拟与隔离模式 多用户支持Multi user Suppor数据分析数据可视化大数据后端前端任务调度ET 框架 Buff 系统实战指南事件驱动与键值对数值如何撑住复杂技能ET 框架 Buff 系统实战指南事件驱动与键值对数值如何撑住复杂技能 本文基于 ET 框架Unity3D 客户端 C 服务端框架用一个最小 Buf数据分析数据可视化大数据后端前端任务调度Apache Zeppelin Notebook REST API 完全指南Apache Zeppelin Notebook REST API 完全指南 概述 Apache Zeppelin 提供了一个功能强大的 REST API允许数据分析数据可视化大数据后端前端任务调度上一篇如何在 PC 上运行 Switch 游戏Ryujinx 模拟器的部署、调优与排错手册下一篇RVM Chef Cookbook 常见问题解决方案创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考