bknd-registration
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseUser Registration Setup
用户注册设置
Configure and implement user self-registration in Bknd applications.
配置并在Bknd应用中实现用户自助注册。
Prerequisites
前提条件
- Bknd project with auth enabled ()
bknd-setup-auth - Password strategy configured
- For SDK: package installed
bknd
- 已启用认证的Bknd项目()
bknd-setup-auth - 已配置密码策略
- 若使用SDK:已安装包
bknd
When to Use UI Mode
何时使用UI模式
- Testing registration endpoint via admin panel
- Viewing registered users
UI steps: Admin Panel > Auth > Test password/register endpoint
- 通过管理面板测试注册端点
- 查看已注册用户
UI操作步骤: 管理面板 > 认证 > 测试密码/注册端点
When to Use Code Mode
何时使用代码模式
- Building registration forms in frontend
- Configuring registration settings
- Adding validation and error handling
- 在前端构建注册表单
- 配置注册设置
- 添加验证和错误处理
Registration Configuration
注册配置
Enable/Disable Registration
启用/禁用注册
typescript
import { serve } from "bknd/adapter/bun";
serve({
connection: { url: "file:data.db" },
config: {
auth: {
enabled: true,
allow_register: true, // Enable self-registration (default: true)
default_role_register: "user", // Role assigned on registration
strategies: {
password: {
type: "password",
config: {
hashing: "bcrypt", // "plain" | "sha256" | "bcrypt"
minLength: 8, // Minimum password length
},
},
},
roles: {
user: { implicit_allow: false },
},
},
},
});Config options:
| Option | Type | Default | Description |
|---|---|---|---|
| boolean | | Enable self-registration |
| string | - | Role for new users |
| number | 8 | Minimum password length |
typescript
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 },
},
},
},
});配置选项:
| 选项 | 类型 | 默认值 | 描述 |
|---|---|---|---|
| boolean | | 启用自助注册 |
| string | - | 新用户的角色 |
| number | 8 | 密码最小长度 |
SDK Registration
SDK注册
typescript
import { Api } from "bknd";
const api = new Api({
host: "http://localhost:7654",
storage: localStorage, // Persist token
});
async function register(email: string, password: string) {
const { ok, data, status } = await api.auth.register("password", {
email,
password,
});
if (ok) {
// Token stored automatically - user is logged in
return data.user;
}
if (status === 409) throw new Error("Email already registered");
if (status === 400) throw new Error("Invalid email or password");
throw new Error("Registration failed");
}Response:
typescript
{
ok: boolean;
data?: {
user: { id: number; email: string; role?: string };
token: string;
};
status: number;
}typescript
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("注册失败");
}响应:
typescript
{
ok: boolean;
data?: {
user: { id: number; email: string; role?: string };
token: string;
};
status: number;
}REST API Registration
REST API注册
bash
curl -X POST http://localhost:7654/api/auth/password/register \
-H "Content-Type: application/json" \
-d '{"email": "user@example.com", "password": "securepassword123"}'Responses:
| Status | Meaning |
|---|---|
| 201 | Success - returns user + token |
| 400 | Invalid email/password or too short |
| 403 | Registration disabled |
| 409 | Email already registered |
bash
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 Integration
React集成
Registration Form
注册表单
tsx
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("Passwords do not match");
return;
}
if (password.length < 8) {
setError("Password must be at least 8 characters");
return;
}
setLoading(true);
const { ok, status } = await api.auth.register("password", {
email,
password,
});
setLoading(false);
if (ok) {
onSuccess?.();
} else if (status === 409) {
setError("Email already registered");
} else {
setError("Registration failed");
}
}
return (
<form onSubmit={handleSubmit}>
{error && <p className="error">{error}</p>}
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Email"
required
/>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="Password"
minLength={8}
required
/>
<input
type="password"
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.target.value)}
placeholder="Confirm Password"
required
/>
<button disabled={loading}>
{loading ? "Creating..." : "Create Account"}
</button>
</form>
);
}tsx
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>
);
}Using useAuth Hook
使用useAuth钩子
tsx
import { useAuth } from "@bknd/react";
function RegisterPage() {
const { user, isLoading, register } = useAuth();
if (isLoading) return <div>Loading...</div>;
if (user) return <Navigate to="/dashboard" />;
async function handleRegister(email: string, password: string) {
await register("password", { email, password });
}
return <RegisterForm onSuccess={() => navigate("/dashboard")} />;
}tsx
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")} />;
}Custom Fields After Registration
注册后添加自定义字段
Registration only accepts and . Add custom fields after:
emailpasswordtypescript
// 1. Extend users entity
const schema = em({
users: entity("users", {
email: text().required().unique(),
name: text(),
avatar: text(),
}),
});
// 2. Update user after registration
const { data } = await api.auth.register("password", { email, password });
await api.data.updateOne("users", data.user.id, {
name: "John Doe",
avatar: "https://...",
});注册仅接受和。如需添加自定义字段,请在注册后操作:
emailpasswordtypescript
// 1. 扩展users实体
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://...",
});Invite-Only Apps
仅邀请制应用
Disable public registration:
typescript
{
auth: {
allow_register: false, // Disable self-registration
},
}
// Admin creates users via seed or plugin
await app.module.auth.createUser({
email: "invited@example.com",
password: tempPassword,
role: "user",
});禁用公开注册:
typescript
{
auth: {
allow_register: false, // 禁用自助注册
},
}
// 管理员通过种子数据或插件创建用户
await app.module.auth.createUser({
email: "invited@example.com",
password: tempPassword,
role: "user",
});Common Pitfalls
常见问题
Registration Disabled
注册已禁用
Problem: (403)
Registration not allowedFix:
{ auth: { allow_register: true } }问题: 提示“Registration not allowed”(403状态码)
解决方法: 设置
{ auth: { allow_register: true } }Role Not Found
角色不存在
Problem:
Role "user" not foundFix: Define role before using:
typescript
{
auth: {
roles: { user: { implicit_allow: false } },
default_role_register: "user",
},
}问题: 提示“Role "user" not found”
解决方法: 先定义角色再使用:
typescript
{
auth: {
roles: { user: { implicit_allow: false } },
default_role_register: "user",
},
}User Already Exists
用户已存在
Problem: 409 error
Fix: Handle gracefully:
tsx
if (status === 409) {
setError("Email already registered. Try logging in instead.");
}问题: 409错误
解决方法: 友好处理该错误:
tsx
if (status === 409) {
setError("邮箱已注册,请尝试登录。");
}Token Not Stored
令牌未存储
Problem: User not logged in after registration
Fix: Provide storage:
typescript
const api = new Api({
host: "http://localhost:7654",
storage: localStorage, // Required for persistence
});问题: 注册后用户未自动登录
解决方法: 提供存储选项:
typescript
const api = new Api({
host: "http://localhost:7654",
storage: localStorage, // 持久化存储所需
});Custom Fields Ignored
自定义字段被忽略
Problem: Extra fields passed to registration not saved
Cause: Registration only accepts email/password
Fix: Update user after registration (see Custom Fields section)
问题: 注册时传入的额外字段未保存
原因: 注册仅接受邮箱和密码
解决方法: 注册后更新用户信息(参考自定义字段章节)
Verification
验证
bash
undefinedbash
undefined1. Test registration
1. 测试注册
curl -X POST http://localhost:7654/api/auth/password/register
-H "Content-Type: application/json"
-d '{"email": "test@example.com", "password": "password123"}'
-H "Content-Type: application/json"
-d '{"email": "test@example.com", "password": "password123"}'
curl -X POST http://localhost:7654/api/auth/password/register
-H "Content-Type: application/json"
-d '{"email": "test@example.com", "password": "password123"}'
-H "Content-Type: application/json"
-d '{"email": "test@example.com", "password": "password123"}'
2. Verify token works
2. 验证令牌是否有效
curl http://localhost:7654/api/auth/me
-H "Authorization: Bearer <token>"
-H "Authorization: Bearer <token>"
undefinedcurl http://localhost:7654/api/auth/me
-H "Authorization: Bearer <token>"
-H "Authorization: Bearer <token>"
undefinedDOs and DON'Ts
注意事项
DO:
- Use bcrypt hashing in production
- Validate password length client-side to match server config
- Handle 409 error with login suggestion
- Store token with
storage: localStorage - Define roles before using
default_role_register
DON'T:
- Use in production
hashing: "plain" - Expect custom fields in registration payload
- Forget to handle registration errors
- Disable registration without alternative user creation
建议:
- 生产环境中使用bcrypt哈希算法
- 客户端验证密码长度以匹配服务器配置
- 处理409错误时提示用户尝试登录
- 使用存储令牌
storage: localStorage - 使用前先定义角色
default_role_register
禁止:
- 生产环境中使用
hashing: "plain" - 期望注册请求体中包含自定义字段
- 忽略注册错误处理
- 禁用注册后不提供其他用户创建方式
Related Skills
相关技能
- bknd-setup-auth - Configure authentication system
- bknd-create-user - Programmatic user creation (admin/seed)
- bknd-login-flow - Login/logout functionality
- bknd-password-reset - Password reset flow
- bknd-setup-auth - 配置认证系统
- bknd-create-user - 程序化创建用户(管理员/种子数据)
- bknd-login-flow - 登录/登出功能
- bknd-password-reset - 密码重置流程