Bknd用户注册设置Skill bknd-registration

这个技能用于在 Bknd 应用程序中配置和实现用户自注册功能,包括注册配置、启用/禁用注册、设置默认角色、密码验证、SDK 和 API 集成,以及前端 React 表单开发。关键词:Bknd、用户注册、身份验证、配置、SDK、API、React。

后端开发 0 次安装 0 次浏览 更新于 3/8/2026

名称: bknd-registration 描述: 在 Bknd 应用程序中设置用户注册流程时使用。涵盖注册配置、启用/禁用注册、默认角色、密码验证、注册表单和自定义字段。

用户注册设置

在 Bknd 应用程序中配置和实现用户自注册。

前提条件

  • 启用身份验证的 Bknd 项目 (bknd-setup-auth)
  • 配置密码策略
  • 对于 SDK:安装 bknd

何时使用 UI 模式

  • 通过管理面板测试注册端点
  • 查看已注册用户

UI 步骤: 管理面板 > 身份验证 > 测试密码/注册端点

何时使用代码模式

  • 在前端构建注册表单
  • 配置注册设置
  • 添加验证和错误处理

注册配置

启用/禁用注册

import { serve } from "bknd/adapter/bun";

serve({
  connection: { url: "file:data.db" },
  config: {
    auth: {
      enabled: true,
      allow_register: true,  // 启用自注册(默认:true)
      default_role_register: "user",  // 注册时分配的角色
      strategies: {
        password: {
          type: "password",
          config: {
            hashing: "bcrypt",  // "plain" | "sha256" | "bcrypt"
            minLength: 8,       // 最小密码长度
          },
        },
      },
      roles: {
        user: { implicit_allow: false },
      },
    },
  },
});

配置选项:

选项 类型 默认值 描述
allow_register boolean true 启用自注册
default_role_register string - 新用户的角色
minLength number 8 最小密码长度

SDK 注册

import { Api } from "bknd";

const api = new Api({
  host: "http://localhost:7654",
  storage: localStorage,  // 持久化令牌
});

async function register(email: string, password: string) {
  const { ok, data, status } = await api.auth.register("password", {
    email,
    password,
  });

  if (ok) {
    // 令牌自动存储 - 用户已登录
    return data.user;
  }

  if (status === 409) throw new Error("邮箱已注册");
  if (status === 400) throw new Error("无效的邮箱或密码");
  throw new Error("注册失败");
}

响应:

{
  ok: boolean;
  data?: {
    user: { id: number; email: string; role?: string };
    token: string;
  };
  status: number;
}

REST API 注册

curl -X POST http://localhost:7654/api/auth/password/register \
  -H "Content-Type: application/json" \
  -d '{"email": "user@example.com", "password": "securepassword123"}'

响应:

状态码 含义
201 成功 - 返回用户 + 令牌
400 无效邮箱/密码或太短
403 注册已禁用
409 邮箱已注册

React 集成

注册表单

import { useState } from "react";
import { useApp } from "bknd/react";

function RegisterForm({ onSuccess }: { onSuccess?: () => void }) {
  const { api } = useApp();
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [confirmPassword, setConfirmPassword] = useState("");
  const [error, setError] = useState<string | null>(null);
  const [loading, setLoading] = useState(false);

  async function handleSubmit(e: React.FormEvent) {
    e.preventDefault();
    setError(null);

    if (password !== confirmPassword) {
      setError("密码不匹配");
      return;
    }

    if (password.length < 8) {
      setError("密码必须至少8个字符");
      return;
    }

    setLoading(true);
    const { ok, status } = await api.auth.register("password", {
      email,
      password,
    });
    setLoading(false);

    if (ok) {
      onSuccess?.();
    } else if (status === 409) {
      setError("邮箱已注册");
    } else {
      setError("注册失败");
    }
  }

  return (
    <form onSubmit={handleSubmit}>
      {error && <p className="error">{error}</p>}
      <input
        type="email"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
        placeholder="邮箱"
        required
      />
      <input
        type="password"
        value={password}
        onChange={(e) => setPassword(e.target.value)}
        placeholder="密码"
        minLength={8}
        required
      />
      <input
        type="password"
        value={confirmPassword}
        onChange={(e) => setConfirmPassword(e.target.value)}
        placeholder="确认密码"
        required
      />
      <button disabled={loading}>
        {loading ? "创建中..." : "创建账户"}
      </button>
    </form>
  );
}

使用 useAuth 钩子

import { useAuth } from "@bknd/react";

function RegisterPage() {
  const { user, isLoading, register } = useAuth();

  if (isLoading) return <div>加载中...</div>;
  if (user) return <Navigate to="/dashboard" />;

  async function handleRegister(email: string, password: string) {
    await register("password", { email, password });
  }

  return <RegisterForm onSuccess={() => navigate("/dashboard")} />;
}

注册后自定义字段

注册仅接受 emailpassword。注册后添加自定义字段:

// 1. 扩展用户实体
const schema = em({
  users: entity("users", {
    email: text().required().unique(),
    name: text(),
    avatar: text(),
  }),
});

// 2. 注册后更新用户
const { data } = await api.auth.register("password", { email, password });

await api.data.updateOne("users", data.user.id, {
  name: "John Doe",
  avatar: "https://...",
});

仅邀请应用

禁用公共注册:

{
  auth: {
    allow_register: false,  // 禁用自注册
  },
}

// 管理员通过种子或插件创建用户
await app.module.auth.createUser({
  email: "invited@example.com",
  password: tempPassword,
  role: "user",
});

常见陷阱

注册已禁用

问题: 注册不允许 (403)

修复: { auth: { allow_register: true } }

角色未找到

问题: 角色 "user" 未找到

修复: 使用前定义角色:

{
  auth: {
    roles: { user: { implicit_allow: false } },
    default_role_register: "user",
  },
}

用户已存在

问题: 409 错误

修复: 优雅处理:

if (status === 409) {
  setError("邮箱已注册。尝试登录代替。");
}

令牌未存储

问题: 注册后用户未登录

修复: 提供存储:

const api = new Api({
  host: "http://localhost:7654",
  storage: localStorage,  // 持久化所需
});

自定义字段被忽略

问题: 传递给注册的额外字段未保存

原因: 注册仅接受邮箱/密码

修复: 注册后更新用户(参见自定义字段部分)

验证

# 1. 测试注册
curl -X POST http://localhost:7654/api/auth/password/register \
  -H "Content-Type: application/json" \
  -d '{"email": "test@example.com", "password": "password123"}'

# 2. 验证令牌有效
curl http://localhost:7654/api/auth/me \
  -H "Authorization: Bearer <token>"

应该做和不应该做

应该做:

  • 生产中使用 bcrypt 哈希
  • 客户端验证密码长度以匹配服务器配置
  • 用登录建议处理 409 错误
  • 使用 storage: localStorage 存储令牌
  • 使用 default_role_register 前定义角色

不应该做:

  • 生产中使用 hashing: "plain"
  • 期望注册有效载荷中的自定义字段
  • 忘记处理注册错误
  • 禁用注册而没有替代的用户创建方法

相关技能

  • bknd-setup-auth - 配置身份验证系统
  • bknd-create-user - 编程式用户创建(管理员/种子)
  • bknd-login-flow - 登录/注销功能
  • bknd-password-reset - 密码重置流程