关于 extension-user-approval
这是为 Caffeine AI 应用添加审批式访问管理的技能。用户可申请访问,管理员可审批或拒绝,并管理审批状态;此技能依赖 extension-authorization。
主要功能
- 01用户提交访问申请
- 02管理员批准或拒绝
- 03查看审批状态列表
- 04删除记录以允许重新申请
- 05检查用户是否已获批准
适用场景
- 01将应用功能限制为已批准用户使用
- 02审核待处理的访问申请
- 03恢复被拒用户的重新申请资格
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ caffeinelabs/ skills --skill extension-user-approval安装后在 Claude Code 中输入/extension-user-approval确认已加载。
附带文件migration/v0.x.y-to-v1.x.y.md
详细介绍
用户审批
适用于 Caffeine AI 的用户审批扩展。
概述
此技能添加基于审批的用户管理功能。用户申请访问权限;管理员批准或拒绝申请。获批用户可访问受保护的功能。
前置条件:必须先遵循 extension-authorization,因为此集成依赖于它。
后端
模块 API
预制模块 mo:caffeineai-user-approval/approval 提供底层审批状态管理。请勿修改该模块。
import AccessControl "mo:caffeineai-authorization/access-control";
module {
public type ApprovalStatus = {
#approved;
#rejected;
#pending;
};
public type UserApprovalState = { /* internal state */ };
public func initState(accessControlState: AccessControl.AccessControlState) : UserApprovalState;
public func isApproved(state : UserApprovalState, caller : Principal) : Bool;
public func requestApproval(state : UserApprovalState, caller : Principal);
public func setApproval(state : UserApprovalState, user : Principal, approval : ApprovalStatus);
public func removeApproval(state : UserApprovalState, user : Principal);
public type UserApprovalInfo = {
principal : Principal;
status : ApprovalStatus;
};
public func listApprovals(state : UserApprovalState) : [UserApprovalInfo];
}
在 main.mo 中设置
include MixinUserApproval(accessControlState, approvalState) 必须放在 main.mo 中,而不是自定义 mixin 文件中。在 actor 顶层声明 approvalState,并将其传入 mixin。该 mixin 会自动提供以下公共端点:
isCallerApproved()requestApproval()setApproval(user, status)removeApproval(user)listApprovals()
在作用域中保留 approvalState,以便在特定于应用的端点中使用自定义审批守卫。
请勿重新声明 mixin 提供的任何函数。
import AccessControl "mo:caffeineai-authorization/access-control";
import MixinAuthorization "mo:caffeineai-authorization/MixinAuthorization";
import MixinUserApproval "mo:caffeineai-user-approval/MixinUserApproval";
import UserApproval "mo:caffeineai-user-approval/approval";
import Runtime "mo:core/Runtime";
actor {
let accessControlState : AccessControl.AccessControlState;
include MixinAuthorization(accessControlState, null);
let approvalState : UserApproval.UserApprovalState;
include MixinUserApproval(accessControlState, approvalState);
// Example custom endpoint with an approval guard:
// public shared ({ caller }) func protectedFeature() : async () {
// if (not (UserApproval.isApproved(approvalState, caller) or AccessControl.hasPermission(accessControlState, caller, #admin))) {
// Runtime.trap("Unauthorized: Only approved users can perform this action");
// };
// };
};
迁移链的头部——UserApproval.initState 依赖访问控制状态,因此请在迁移函数体中按顺序计算:
import AccessControl "mo:caffeineai-authorization/access-control";
import UserApproval "mo:caffeineai-user-approval/approval";
module {
type NewActor = {
accessControlState : AccessControl.AccessControlState;
approvalState : UserApproval.UserApprovalState;
};
public func migration(_old : {}) : NewActor {
let accessControlState = AccessControl.initState();
{
accessControlState;
approvalState = UserApproval.initState(accessControlState);
};
};
};
在 initState 时,现有管理员会自动获批。所有其他用户都处于待审批状态。
匿名主体永远不会获批:requestApproval 和 setApproval 会因其触发 trap,而 isCallerApproved 会返回 false。对于尚未注册的已登录调用者,isCallerApproved 也会返回 false,而不是触发 trap。
重要:为每个自定义公共函数应用正确的授权检查和/或审批检查。
前端
基于审批的用户管理:
用户审批流程
- 检查审批状态(
isCallerApproved) - 如果尚未获批,则显示申请审批选项(
requestApproval)。仅向已登录用户显示;匿名主体调用时会触发 trap - 阻止未获批用户访问主要功能
- 管理员可以使用应用的所有功能
- 在 UI 中清楚显示审批状态
管理员控制面板
为管理员用户提供控制面板,以便:
- 列出所有用户及其审批状态(
listApprovals) - 批准或拒绝用户(
setApproval)。被拒绝的用户无法再次申请审批 - 移除用户条目(
removeApproval),使其可以再次申请审批 - 查看并分配用户角色(使用
getCallerUserRole和assignCallerUserRole)
后端集成
后端已实现以下功能。 完整接口请参阅
// 检查当前用户是否获批;管理员始终获批 isCallerApproved(): Promise;
// 提交审批申请 requestApproval(): Promise;
// 获取所有用户及其审批状态(仅限管理员) listApprovals(): Promise<Array>;
// 批准或拒绝用户(仅限管理员) setApproval(user: Principal, status: ApprovalStatus): Promise;
// 删除用户的审批条目,使其可以再次申请审批(仅限管理员) removeApproval(user: Principal): Promise;
// 为用户分配角色(仅限管理员) assignCallerUserRole(user: Principal, role: UserRole): Promise;
// 获取特定用户的当前角色 getCallerUserRole(): Promise;