- 物联网
- 后端
【免费下载链接】OctoPrint
OctoPrint is the snappy web interface for your 3D printer!
导读
本文围绕 OctoPrint JavaScript Client Library 的访问控制(access)组件展开,系统讲解如何通过OctoPrintClient.access.permissions、OctoPrintClient.access.users与OctoPrintClient.access.groups三个子模块,在前端脚本或第三方客户端中完成权限查询、用户与用户组管理、密码与 API Key 维护、用户个性化设置读写等操作。读完本文,你将掌握 access 组件全部 API 方法及参数语义、底层 REST 端点映射、权限校验机制与常见错误处理,并能在自己的 OctoPrint 插件或外部客户端中直接落地使用。
组件定位与前置条件
access组件是 OctoPrint JS Client Library 中与「访问控制」REST API 对应的客户端封装。组件对应的源文档为 docs/jsclientlib/access.rst,其底层 HTTP 端点定义于 docs/api/access.rst,服务端实现位于 src/octoprint/server/api/access.py。
权限前提
文档开头即给出重要提示:本组件的大多数方法要求调用方持有的 API Token(X-Api-Key)或浏览器会话具备管理员权限,或者该会话恰好对应待操作的用户本身;部分方法则严格需要管理员权限。具体到每个方法,本文会在相应小节标注权限要求。
从源码看,权限校验在服务端通过装饰器强制执行。以 src/octoprint/server/api/access.py 为例:
- 用户与用户组的大部分写操作使用
@Permissions.ADMIN.require(403),非管理员直接返回 403; - 写操作(POST / PUT / DELETE)额外叠加
@require_credentials_checked_recently,即要求“凭据已在近期验证过”(recent credentials check),防止借用长期有效的会话进行敏感操作; - 读取用户记录、修改密码、读写个人设置等接口则采用“当前用户等于目标用户,或拥有 ADMIN 权限”二选一的判定逻辑。
权限对象模型位于 src/octoprint/access/permissions.py:OctoPrintPermission通过as_dict()暴露key、name、dangerous、default_groups、description与needs字段;PermissionsMetaClass将注册的权限统一收集到Permissions.permissions字典,并支持Permissions.all()与Permissions.filter()遍历。/api/access/permissions端点正是用Permissions.all()枚举后逐个as_dict()输出(见 src/octoprint/server/api/access.py 的get_permissions)。
引入方式
access属于按需加载的组件。按 docs/jsclientlib/index.rst 的说明,可以通过 webassets 一次性引入完整客户端:
{% assets "js_client" %}<script type="text/javascript" src="{{ ASSET_URL }}"></script>{% endassets %}或只引入单个组件文件(注意不要遗漏base组件,其余所有组件都依赖它):
<script type="text/javascript" src="{{ url_for("static", filename="js/app/client/base.js") }}"></script> <script type="text/javascript" src="{{ url_for("static", filename="js/app/client/access.js") }}"></script>同时必须保证 jQuery($)与 lodash(_)可用,组件源码 src/octoprint/static/js/app/client/access.js 依赖这两个全局对象:
<script src="{{ url_for("static", filename="js/lib/jquery/jquery.min.js") }}"></script> <script src="{{ url_for("static", filename="js/lib/lodash.min.js") }}"></script>引入完成后,全局变量OctoPrint(OctoPrintClient的实例)即包含OctoPrint.access命名空间,其内部结构在 src/octoprint/static/js/app/client/access.js 末尾组装:
var OctoPrintAccessClient = function (base) { this.base = base; this.permissions = new OctoPrintAccessPermissionsClient(this); this.groups = new OctoPrintAccessGroupsClient(this); this.users = new OctoPrintAccessUsersClient(this); }; OctoPrintClient.registerComponent("access", OctoPrintAccessClient);OctoPrintClient.registerComponent(见 src/octoprint/static/js/app/client/base.js)会把组件懒加载挂到客户端原型上,因此OctoPrint.access.permissions、OctoPrint.access.users、OctoPrint.access.groups均可直接访问。
OctoPrintClient.access.permissions:权限清单查询
permissions.list(opts)
获取系统内全部已注册权限的列表。
- 参数
opts:object,请求的附加选项(如自定义 headers、超时等); - 返回值:jQuery Promise,resolve 后携带权限列表响应。
实现位于 src/octoprint/static/js/app/client/access.js 的OctoPrintAccessPermissionsClient.prototype.list,内部仅调用this.base.get("api/access/permissions")。底层 REST 端点为GET /api/access/permissions(见 docs/api/access.rst 的 “List all permissions” 小节),服务端get_permissions返回形如{"permissions": [ ... ]}的 JSON,每个元素包含key、name、dangerous、default_groups、description、needs等字段(由 src/octoprint/access/permissions.py 的OctoPrintPermission.as_dict定义)。
典型用法:
OctoPrint.access.permissions.list() .done(function (response) { console.log(response.permissions); });OctoPrintClient.access.users:用户管理
users子组件把用户相关的全部 REST 操作封装为 9 个方法,统一以api/access/users为基地址(见 src/octoprint/static/js/app/client/access.js 的OctoPrintAccessUsersClient)。下方列出方法签名、权限要求、底层端点与典型示例。
users.list(opts)
获取所有已注册用户的列表。
- 需要管理员权限;
- 底层端点:
GET /api/access/users; - 服务端在 src/octoprint/server/api/access.py 的
get_users中,对每个用户调用as_dict();若近期未验证过凭据,返回的用户记录中apikey会被置为null,这是刻意的安全行为。
OctoPrint.access.users.list() .done(function (response) { console.log(response.users); });用户记录的数据结构由 src/octoprint/access/users.py 的User.as_dict定义,包含:name、active(布尔)、permissions(权限 key 列表)、groups(用户组 key 列表)、needs、apikey、settings、has_password。
users.get(name, opts)
获取指定用户的信息。
- 参数
name:string,用户名; - 底层端点:
GET /api/access/users/<username>; - 权限:
SETTINGS权限或登录身份即该用户本人(服务端逻辑见 src/octoprint/server/api/access.py 的get_user:current_user.get_name() == username or current_user.has_permission(Permissions.ADMIN)); - 未知用户返回 404;无权限返回 403。
OctoPrint.access.users.get("user1") .done(function (user) { console.log(user.name, user.active, user.permissions); });users.add(user, opts)
新增用户。
- 需要管理员权限;
- 参数
user:object,新用户数据; - 底层端点:
POST /api/access/users; - 客户端前置校验(见 src/octoprint/static/js/app/client/access.js):
user.name与user.password必须存在,否则抛出InvalidArgumentError; - 客户端自动构造的请求体:
name、password、groups(缺省为[])、permissions(缺省为[])、active(缺省为true,!!user.active强转布尔); - 服务端(
add_user)要求请求体包含name、password、active,缺失时返回 400;用户名重复返回 409;用户名非法返回 400; - 成功时返回用户列表响应(与
users.list相同结构)。
OctoPrint.access.users.add({ name: "newuser", password: "s3cr3t", active: true, groups: ["users"], permissions: [] }).done(function (response) { console.log(response.users); });users.update(name, active, permissions, groups, opts)
更新既有用户。
- 需要管理员权限;
- 参数:
name(string,用户名)、active(bool,新的激活状态)、permissions(list,权限 key 列表)、groups(list,用户组 key 列表)、opts(object); - 底层端点:
PUT /api/access/users/<username>,客户端通过putJson提交{active: !!active, groups: groups, permissions: permissions}; - 服务端
update_user按请求体中出现的字段,分别调用change_user_groups、change_user_permissions、change_user_activation(见 src/octoprint/server/api/access.py); - 未知用户返回 404。
兼容性说明(重要):源码中保留了对旧参数顺序(name, active, admin, permissions, groups, opts)的兼容逻辑——当第三个参数permissions的类型是 boolean 时,会将其视为旧的admin标志,把所有参数左移一位并打印弃用警告:
if (typeof permissions == "boolean") { // old parameter order: name, active, *admin*, permissions, groups, opts console.log( "Calling OctoPrint.access.users.update with admin flag is deprecated and will be removed in OctoPrint 3.0.0. Use permissions or groups instead." ); permissions = groups; groups = opts; opts = arguments.length >= 6 ? arguments[5] : {}; }因此,应始终使用新的五参数形式,不要依赖旧的 admin 布尔标志。
OctoPrint.access.users.update("newuser", true, ["ADMIN"], ["admins"]) .done(function (response) { /* ... */ });users.delete(name, opts)
删除既有用户。
- 需要管理员权限;
- 底层端点:
DELETE /api/access/users/<username>; - 服务端
remove_user中,若目标用户即当前登录用户,返回 400(“You cannot delete yourself”);未知用户返回 404; - 成功时返回用户列表响应。
OctoPrint.access.users.delete("newuser") .done(function (response) { /* ... */ });users.changePassword(name, password, oldpw, opts)
修改指定用户的密码。
- 参数:
name(string)、password(string,新密码)、oldpw(string,旧密码,可选但大多数情况下必需)、opts(object); - 底层端点:
PUT /api/access/users/<username>/password; - 客户端实现有一个便捷行为:若第三个参数传入的是 object(即调用者省略了
oldpw直接传opts),会自动把参数移位:if (_.isObject(oldpw)) { opts = oldpw; oldpw = undefined; }; - 请求体为
{"password": newPassword},仅在提供oldpw时才附加"current": oldpw; - 服务端规则(见 docs/api/access.rst 与
change_password_for_user):拥有SETTINGS权限,或登录身份即目标用户;没有管理员权限时,请求体必须包含current(当前密码),且服务端会校验其正确性;若current被提供,即使调用方有管理员权限也会一并校验; - 典型错误码:400(缺
password或必需的current)、403(无权限 / 非本人 / 凭据未近期验证 / 当前密码不匹配)、404(未知用户)。
// 用户本人修改自己的密码 OctoPrint.access.users.changePassword("user1", "newpass", "oldpass"); // 管理员为他人改密(不提供旧密码) OctoPrint.access.users.changePassword("user2", "newpass");users.generateApiKey(name, opts)
为用户生成(重置)新的个人 API Key。
- 底层端点:
POST /api/access/users/<username>/apikey; - 权限:
SETTINGS权限或登录身份即目标用户,且要求近期凭据校验(服务端generate_apikey_for_user); - 无需请求体;响应 JSON 中通过
apikey属性返回新生成的 key(jsonify({"apikey": apikey})); - 生成逻辑在 src/octoprint/access/users.py 的
generate_api_key。
OctoPrint.access.users.generateApiKey("user1") .done(function (response) { console.log("New API key:", response.apikey); });users.resetApiKey(name, opts)
将用户的个人 API Key 重置为未设置状态。
- 底层端点:
DELETE /api/access/users/<username>/apikey; - 权限同上:
SETTINGS权限或登录身份即目标用户,且要求近期凭据校验; - 成功后返回
SUCCESS(204 语义),对应服务端delete_apikey_for_user调用的delete_api_key(见 src/octoprint/access/users.py)。
OctoPrint.access.users.resetApiKey("user1");users.getSettings(name, opts)
获取指定用户的个人设置。
- 底层端点:
GET /api/access/users/<username>/settings; - 权限:
SETTINGS权限或登录身份即目标用户(服务端get_settings_for_user返回userManager.get_all_user_settings(username)); - 未知用户返回 404,无权限返回 403;
- 返回的 JSON 对象即该用户的个性化设置(可能为空对象)。
OctoPrint.access.users.getSettings("user1") .done(function (settings) { /* ... */ });users.saveSettings(name, settings, opts)
保存/更新指定用户的个人设置。
- 参数
settings:object,允许只传部分设置,服务端会将其与现有设置合并(merge),而非整体覆盖; - 底层端点:
PATCH /api/access/users/<username>/settings(PATCH 语义天然支持部分更新); - 客户端通过
patchJson提交,settings = settings || {}保证空对象合法; - 权限:
SETTINGS权限或登录身份即目标用户;当操作者是管理员(非本人)时,服务端要求近期凭据校验; - 成功后返回
SUCCESS。
OctoPrint.access.users.saveSettings("user1", { theme: "dark" }) .done(function () { /* 已合并保存 */ });OctoPrintClient.access.groups:用户组管理
groups子组件对应api/access/groups端点(见 src/octoprint/static/js/app/client/access.js 的OctoPrintAccessGroupsClient)。用户组(group)用于批量授予权限:组内可包含权限列表、子组(subgroups)以及是否作为新用户默认组(default)。服务端模型在 src/octoprint/access/groups.py,内置了admin、users、guest、readonly等默认组(_init_defaults),其中users组默认对新建用户生效。
groups.list(opts)
获取所有已注册用户组的列表。
- 底层端点:
GET /api/access/groups,返回{"groups": [ ... ]}; - 服务端
get_groups对groupManager.groups逐个调用as_dict(); - 权限:
SETTINGS权限(见 docs/api/access.rst)。
OctoPrint.access.groups.list() .done(function (response) { console.log(response.groups); });groups.get(key, opts)
获取指定用户组的信息。
- 参数
key:string,用户组 ID(注意是key而非显示名称); - 底层端点:
GET /api/access/groups/<key>; - 服务端
get_group通过groupManager.find_group(key)查找,未知组返回 404; - 客户端前置校验:
key必须设置,否则抛出InvalidArgumentError。
OctoPrint.access.groups.get("admins") .done(function (group) { console.log(group); });groups.add(group, opts)
新增用户组。
- 需要管理员权限;
- 参数
group:object,要求至少包含key与name;还支持description、permissions、subgroups以及default布尔标志; - 客户端前置校验:
group.key与group.name缺一不可,否则抛出InvalidArgumentError; - 请求体字段(见客户端
add实现)与 REST 数据模型完全对应(docs/api/access.rst 的 “Group registration request” 表):
| 字段 | 必填 | 类型 | 说明 |
|---|---|---|---|
key | 是 | string | 用户组标识符 |
name | 是 | string | 用户组显示名称 |
description | 否 | string | 可读描述,缺省为空串 |
permissions | 是 | string 列表 | 分配给该组的权限 key 列表 |
subgroups | 否 | string 列表 | 作为子组的用户组 key 列表 |
default | 否 | boolean | 是否将新用户默认加入该组(缺省 false) |
- 服务端
add_group:缺少key/name/permissions/subgroups任一字段返回 400;组 key 已存在或存在循环子组引用(CyclicSubgroupReference)返回 409; - 成功时返回组列表响应。
OctoPrint.access.groups.add({ key: "operators", name: "Operators", description: "Machine operators", permissions: ["PRINT", "MONITOR_TERMINAL"], subgroups: ["users"], default: false }).done(function (response) { /* ... */ });groups.update(group, opts)
更新既有用户组,通过group.key标识目标组。
- 需要管理员权限;
- 参数
group:object,必须包含key; - 只会更新以下字段:
description、permissions、subgroups、default(key与name不参与更新); - 客户端在组装请求体时,
description若未在group中定义则置为空串(group.hasOwnProperty("description") ? group.description : ""),permissions、subgroups、default原样传递; - 底层端点:
PUT /api/access/groups/<key>; - 服务端
update_group:default字段按valid_boolean_trues解析为布尔;组不可修改(GroupCantBeChanged,如内置组)返回 403;未知组返回 404;循环子组引用返回 409; - 成功时返回组列表响应。
OctoPrint.access.groups.update({ key: "operators", description: "Machine operators (updated)", permissions: ["PRINT", "MONITOR_TERMINAL", "FILES_DOWNLOAD"], subgroups: ["users"], default: false }).done(function (response) { /* ... */ });groups.delete(key, opts)
删除用户组。
- 需要管理员权限;
- 参数
key:string,用户组 ID; - 底层端点:
DELETE /api/access/groups/<key>; - 服务端
remove_group:未知组返回 404;组不可移除(GroupUnremovable,如内置组)返回 403; - 成功时返回组列表响应。
OctoPrint.access.groups.delete("operators") .done(function (response) { /* ... */ });底层请求机制与 Promise 使用要点
access组件的全部方法都基于 src/octoprint/static/js/app/client/base.js 提供的 HTTP 原语:
get(url, opts):GET,对应groups.list、users.get等;postJson(url, data, opts):POST +Content-Type: application/json,请求体经JSON.stringify(undefined 值会被替换为 null),对应groups.add、users.add、users.generateApiKey;putJson(url, data, opts):PUT + JSON,对应groups.update、users.update、users.changePassword;patchJson(url, data, opts):PATCH + JSON,对应users.saveSettings;delete(url, opts):DELETE,对应groups.delete、users.delete、users.resetApiKey。
所有方法都返回 jQuery Promise,可链式使用.done()、.fail()、.always()。鉴权头由getRequestHeaders统一注入:设置了OctoPrint.options.apikey时发送X-Api-Key;未设置时视为浏览器上下文,对非 GET/HEAD/OPTIONS 方法自动附加X-CSRF-Token(从csrf_tokencookie 读取,跨域请求除外)。因此,无论是通过OctoPrint.options.apikey携带管理员 API Key,还是依赖登录会话 + CSRF Token,上述方法都能正常工作。
客户端参数校验通过OctoPrintClient.InvalidArgumentError(createCustomException("InvalidArgumentError"),定义于 src/octoprint/static/js/app/client/base.js)抛出,例如users.add缺用户名/密码、groups.add缺 key/name、所有按 key/name 定位的方法缺标识符时都会触发。
完整示例:面向多服务器的用户管理
以下示例演示如何实例化独立客户端并组合使用 access 组件的方法(参考 docs/jsclientlib/index.rst 的多客户端模式):
var client = new OctoPrintClient({ baseurl: "http://octopi.local/", apikey: "ADMIN_API_KEY" }); client.access.users.list() .fail(function (xhr) { if (xhr.status === 403) { console.error("需要管理员权限或近期凭据校验"); } }) .done(function (response) { // 过滤出当前激活的用户 var activeUsers = response.users.filter(function (u) { return u.active; }); console.log(activeUsers); }); client.access.groups.add({ key: "engineers", name: "Engineers", permissions: ["PRINT"], subgroups: ["users"], default: false }).done(function () { console.log("组已创建"); });权限、安全与错误处理速查
综合 docs/api/access.rst、src/octoprint/server/api/access.py 与 src/octoprint/static/js/app/client/access.js,整理各方法的权限与典型错误如下:
| 方法 | 权限要求 | 底层端点 | 典型错误 |
|---|---|---|---|
permissions.list | 无特殊要求 | GET/api/access/permissions | — |
users.list | ADMIN | GET/api/access/users | 403 |
users.get | ADMIN 或本人 | GET/api/access/users/<name> | 403 / 404 |
users.add | ADMIN | POST/api/access/users | 400 / 409 |
users.update | ADMIN | PUT/api/access/users/<name> | 400 / 404 |
users.delete | ADMIN | DELETE/api/access/users/<name> | 400(删除自己)/ 404 |
users.changePassword | ADMIN 或本人(本人需current) | PUT/api/access/users/<name>/password | 400 / 403 / 404 |
users.generateApiKey | ADMIN 或本人 + 近期凭据 | POST/api/access/users/<name>/apikey | 403 / 404 |
users.resetApiKey | ADMIN 或本人 + 近期凭据 | DELETE/api/access/users/<name>/apikey | 403 / 404 |
users.getSettings | ADMIN 或本人 | GET/api/access/users/<name>/settings | 403 / 404 |
users.saveSettings | ADMIN 或本人(管理员需近期凭据) | PATCH/api/access/users/<name>/settings | 403 / 404 |
groups.list | SETTINGS | GET/api/access/groups | 403 |
groups.get | SETTINGS | GET/api/access/groups/<key> | 404 |
groups.add | ADMIN + 近期凭据 | POST/api/access/groups | 400 / 409 |
groups.update | ADMIN + 近期凭据 | PUT/api/access/groups/<key> | 403 / 404 / 409 |
groups.delete | ADMIN + 近期凭据 | DELETE/api/access/groups/<key> | 403 / 404 |
几个值得注意的安全细节:
- 近期凭据校验:用户组写操作以及管理员代他人执行改密、API Key、设置等操作时,服务端强制要求近期凭据校验(
require_credentials_checked_recently/ensure_credentials_checked_recently,见 src/octoprint/server/api/access.py),从而避免会话被长期借用后直接执行敏感操作。 - API Key 脱敏:
users.list与users.get在凭据未近期验证时,返回记录中的apikey一律置为null(见get_users/get_user),防止敏感信息泄露。 - 内置组保护:
admin、users、guest、readonly等默认组受GroupCantBeChanged/GroupUnremovable保护,删除或修改会分别收到 403。 - 循环子组引用:
groups.add/groups.update若形成循环子组关系,服务端返回 409,客户端应捕获该错误并向用户提示。 - 删除自身限制:
users.delete不允许删除当前登录用户,服务端返回 400。
扩展阅读与相关资源
- 组件文档索引:docs/jsclientlib/index.rst(含客户端库的引入方式、
OctoPrint全局实例与多客户端用法) - 底层 REST API 完整文档:docs/api/access.rst(端点、数据模型、错误码)
- 客户端实现源码:src/octoprint/static/js/app/client/access.js
- 客户端基础组件(请求原语与参数校验):src/octoprint/static/js/app/client/base.js
- 服务端 REST 实现:src/octoprint/server/api/access.py
- 权限模型:src/octoprint/access/permissions.py
- 用户模型:src/octoprint/access/users.py
- 用户组模型:src/octoprint/access/groups.py
- 第三方客户端授权工作流可参考内置的 Application Key 插件文档:docs/bundledplugins/appkeys.rst,它为外部客户端补充了额外的 JS Client Library 方法,与本文的 API Key 机制互补。
- 物联网
- 后端
【免费下载链接】OctoPrint
OctoPrint is the snappy web interface for your 3D printer!
相关推荐
如何用Automated YouTube Channel打造24/7自动运行的YouTube频道:终极指南
如何用Automated YouTube Channel打造24/7自动运行的YouTube频道:终极指南 Automated YouTube Channel是
物联网后端GitHub_Trending/ma/machine-learning-for-trading中的协整检验:配对交易策略开发
GitHub_Trending/ma/machine learning for trading中的协整检验:配对交易策略开发 GitHub_Trending/m
示例工程金融科技机器学习人工智能深度学习如何通过802.1X认证实现网络访问控制:完整指南
如何通过802.1X认证实现网络访问控制:完整指南 802.1X认证是IEEE制定的端口网络访问控制(PNAC)标准,通过为有线和无线网络提供设备身份验证机制,
网络安全渗透测试密码学
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考