@saleandwin/auth
v2.2.0
Published
Authentication center for framework-ts projects with OAuth, email, and password support
Maintainers
Readme
@saleandwin/auth
企业级认证中心模块,为 framework-ts 项目提供完整的用户认证和授权解决方案。支持游客登录和角色权限管理。
✨ 特性
🔐 多种认证方式
- 邮箱密码登录 - 传统的用户名密码认证
- Magic Link - 无密码邮箱链接登录
- OAuth 登录 - 支持 Google、GitHub、Microsoft、Discord、Twitter
- 游客登录 - 无需注册的临时用户体验 🆕
🛡️ 安全可靠
- 密码加密 - bcrypt 哈希算法
- JWT 令牌 - 安全的访问控制
- 会话管理 - 自动过期和刷新机制
- 输入验证 - Zod 严格类型验证
- 速率限制 - 防暴力破解保护
👥 角色权限系统 🆕
- 等级制权限 - 基于数字等级的简单权限控制
- 预设角色 - 游客、用户、管理员、超级管理员
- 灵活分配 - 支持角色过期时间设置
- 权限检查 - 角色名称和等级双重检查
📧 邮件集成
- Resend 集成 - 专业的邮件发送服务
- 邮箱验证 - 自动发送验证码
- Magic Link - 一键登录链接
- 响应式模板 - 美观的 HTML 邮件模板
💾 数据库优化
- Cloudflare D1 - 边缘数据库优化
- 类型安全 - 完整的 TypeScript 支持
- 高性能查询 - 优化的 SQL 语句
- 自动清理 - 过期数据自动清理
Architecture
The library follows a clean architecture pattern:
Handler -> Service -> Table- Handler: HTTP request handling for Next.js routes
- Service: Business logic, validation, and data processing
- Table: Database access layer with prepared statements
📦 安装
npm install @saleandwin/auth
# 或
pnpm add @saleandwin/auth
# 或
yarn add @saleandwin/auth🚀 快速开始
1. 基础配置
import { AuthHandler, type AuthConfig, type AuthEnv } from '@saleandwin/auth';
// 在 Cloudflare Workers 中
export default {
async fetch(request: Request, env: AuthEnv, ctx: ExecutionContext): Promise<Response> {
const config: AuthConfig = {
jwt_secret: env.JWT_SECRET,
jwt_expires_in: '7d',
session_duration: 7 * 24 * 60 * 60, // 7天
magic_link_duration: 30 * 60, // 30分钟
verification_code_duration: 10 * 60, // 10分钟
password_reset_duration: 60 * 60, // 1小时
oauth_providers: {
google: {
client_id: env.GOOGLE_CLIENT_ID,
client_secret: env.GOOGLE_CLIENT_SECRET,
redirect_uri: 'https://yourapp.com/auth/callback/google'
}
},
email: {
api_key: env.RESEND_API_KEY,
from_email: '[email protected]',
from_name: 'Your App'
}
};
// 注入环境变量(包含 DB)
const authHandler = AuthHandler.createInstance(config, env);
// 处理请求...
}
};2. 数据库设置
# 使用 Cloudflare D1 CLI
wrangler d1 execute your-database --file=./node_modules/@saleandwin/auth/migrations.sql
# 或直接执行 SQL
cat ./node_modules/@saleandwin/auth/migrations.sql | sqlite3 your-database.db3. 环境变量
# 必需配置
AUTH_JWT_SECRET=your-super-secret-jwt-key-at-least-32-characters
RESEND_API_KEY=re_your_resend_api_key
[email protected]
FROM_NAME=Your App Name
# OAuth 配置(可选)
GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret
GITHUB_CLIENT_ID=your-github-client-id
GITHUB_CLIENT_SECRET=your-github-client-secret4. 用户注册
const result = await authHandler.handleRegister({
email: '[email protected]',
name: 'John Doe',
password: 'SecurePassword123'
});
if (result.success) {
console.log('注册成功:', result.user);
console.log('访问令牌:', result.access_token);
} else {
console.error('注册失败:', result.error);
}5. 用户登录
const result = await authHandler.handleLogin({
email: '[email protected]',
password: 'SecurePassword123'
});
if (result.success) {
console.log('登录成功:', result.user);
console.log('访问令牌:', result.access_token);
} else {
console.error('登录失败:', result.error);
}6. 游客登录 🆕
const result = await authHandler.handleGuestLogin({
device_id: 'device_123', // 可选
session_duration: 86400 // 可选,默认24小时
});
if (result.success) {
console.log('游客登录成功:', result.user);
console.log('用户类型:', result.user.user_type); // 'guest'
}7. 角色权限检查 🆕
// 检查用户是否有特定角色
const hasRole = await authHandler.handleCheckRole(userId, 'admin');
console.log('是否为管理员:', hasRole.data.has_role);
// 检查用户角色等级
const hasLevel = await authHandler.handleCheckRoleLevel(userId, 80);
console.log('是否达到管理员等级:', hasLevel.data.has_min_level);📚 完整 API 文档
AuthHandler 方法
👤 用户管理
// 用户注册
handleRegister(data: CreateUserRequest): Promise<AuthResponse>
// 用户登录
handleLogin(data: LoginRequest, clientInfo?: ClientInfo): Promise<AuthResponse>
// 游客登录 🆕
handleGuestLogin(data: GuestLoginRequest): Promise<AuthResponse>
// 用户登出
handleLogout(sessionId: string): Promise<AuthResponse>
// 更新用户信息
handleUpdateUser(userId: string, data: UpdateUserRequest): Promise<AuthResponse>
// 修改密码
handleChangePassword(userId: string, data: ChangePasswordRequest): Promise<AuthResponse>🎫 会话管理
// 验证会话
handleValidateSession(token: string): Promise<AuthResponse>
// 刷新会话
handleRefreshSession(refreshToken: string): Promise<AuthResponse>✨ Magic Link
// 发送 Magic Link
handleSendMagicLink(data: MagicLinkRequest): Promise<AuthResponse>
// 验证 Magic Link
handleVerifyMagicLink(token: string): Promise<AuthResponse>🔗 OAuth
// OAuth 登录
handleOAuthLogin(data: OAuthLoginRequest, clientInfo?: ClientInfo): Promise<AuthResponse>👥 角色权限 🆕
// 检查用户角色
handleCheckRole(userId: string, roleName: string): Promise<AuthResponse>
// 检查角色等级
handleCheckRoleLevel(userId: string, minLevel: number): Promise<AuthResponse>数据类型
用户类型
interface User {
id: string;
email?: string; // 游客用户可以没有邮箱
email_verified: boolean;
name?: string;
avatar_url?: string;
user_type: 'user' | 'guest'; // 🆕 用户类型
is_active: boolean;
created_at: string;
updated_at: string;
last_login_at?: string;
login_count: number;
expires_at?: string; // 🆕 游客用户过期时间
}角色类型 🆕
interface Role {
id: string;
name: string; // 'super_admin', 'admin', 'user', 'guest'
display_name: string; // '超级管理员', '管理员', '注册用户', '游客用户'
description?: string;
level: number; // 权限等级:100, 80, 50, 10
is_system: boolean; // 是否为系统角色
is_active: boolean;
created_at: string;
updated_at: string;
}请求类型
// 游客登录请求 🆕
interface GuestLoginRequest {
device_id?: string; // 设备标识
session_duration?: number; // 会话持续时间(秒)
}
// 游客升级请求 🆕
interface GuestUpgradeRequest {
email: string;
name?: string;
password?: string;
}
// 角色分配请求 🆕
interface AssignRoleRequest {
user_id: string;
role_ids: string[];
expires_at?: string;
}🗄️ 数据库设置
1. 运行迁移脚本
# 使用 Cloudflare D1 CLI
wrangler d1 execute your-database --file=./node_modules/@saleandwin/auth/migrations.sql
# 或直接执行 SQL
cat ./node_modules/@saleandwin/auth/migrations.sql | sqlite3 your-database.db2. 数据库表结构
核心表
- users - 用户表(支持游客用户)
- sessions - 会话表
- oauth_accounts - OAuth 账户表
- email_verifications - 邮箱验证表
角色权限表 🆕
- roles - 角色表(预设4个系统角色)
- user_roles - 用户角色关联表
预设角色
| 角色名 | 显示名称 | 等级 | 描述 | |--------|----------|------|------| | super_admin | 超级管理员 | 100 | 拥有最高权限 | | admin | 管理员 | 80 | 系统管理权限 | | user | 注册用户 | 50 | 普通用户权限 | | guest | 游客用户 | 10 | 基础浏览权限 |
⚙️ 配置选项
interface AuthConfig {
// 必需配置
jwt_secret: string;
// 会话配置
session_duration?: number; // 会话持续时间(秒)
max_login_attempts?: number; // 最大登录尝试次数
lockout_duration?: number; // 锁定持续时间(秒)
// 验证配置
password_reset_duration?: number; // 密码重置有效期
email_verification_duration?: number; // 邮箱验证有效期
magic_link_duration?: number; // Magic Link 有效期
// OAuth 配置
oauth?: {
google?: OAuthProviderConfig;
github?: OAuthProviderConfig;
microsoft?: OAuthProviderConfig;
discord?: OAuthProviderConfig;
twitter?: OAuthProviderConfig;
};
// 邮件配置
email?: {
resend_api_key: string;
from_email: string;
from_name?: string;
};
}
interface OAuthProviderConfig {
client_id: string;
client_secret: string;
redirect_uri: string;
scope?: string;
}"password": "SecurePassword123", "remember_me": false }
### Get Current User
```http
GET /api/auth/me
Authorization: Bearer <access_token>Update User Profile
PUT /api/auth/me
Authorization: Bearer <access_token>
Content-Type: application/json
{
"name": "Updated Name",
"avatar_url": "https://example.com/avatar.jpg"
}Send Email Verification
POST /api/auth/send-verification
Content-Type: application/json
{
"email": "[email protected]"
}Verify Email
POST /api/auth/verify-email
Content-Type: application/json
{
"code": "123456"
}Send Magic Link
POST /api/auth/magic-link
Content-Type: application/json
{
"email": "[email protected]",
"redirect_uri": "https://yourapp.com/dashboard"
}Change Password
POST /api/auth/change-password
Authorization: Bearer <access_token>
Content-Type: application/json
{
"current_password": "OldPassword123",
"new_password": "NewPassword123"
}Logout
POST /api/auth/logout
Authorization: Bearer <access_token>🔧 Next.js 集成示例
API 路由示例
// app/api/auth/register/route.ts
import { AuthHandler } from '@saleandwin/auth';
import { NextRequest, NextResponse } from 'next/server';
import { authConfig } from '@/lib/auth-config';
export async function POST(request: NextRequest) {
try {
const authHandler = await AuthHandler.createInstance(authConfig);
const data = await request.json();
const result = await authHandler.handleRegister(data);
if (result.success) {
return NextResponse.json(result, { status: 201 });
} else {
return NextResponse.json(result, { status: 400 });
}
} catch (error) {
return NextResponse.json(
{ success: false, error: '服务器内部错误' },
{ status: 500 }
);
}
}中间件权限控制
// middleware.ts
import { NextRequest, NextResponse } from 'next/server';
import { AuthHandler } from '@saleandwin/auth';
export async function middleware(request: NextRequest) {
// 检查管理员路由权限
if (request.nextUrl.pathname.startsWith('/dashboard/admin')) {
const token = request.cookies.get('auth-token')?.value;
if (!token) return NextResponse.redirect(new URL('/login', request.url));
const authHandler = await AuthHandler.createInstance(authConfig);
const roleCheck = await authHandler.handleCheckRoleLevel(userId, 80);
if (!roleCheck.data?.has_min_level) {
return NextResponse.redirect(new URL('/dashboard', request.url));
}
}
return NextResponse.next();
}📖 使用示例
详细的使用示例请查看 examples/ 目录:
- Next.js 基础集成 - 完整的 Next.js 项目集成示例
- 角色权限管理 - 角色权限系统的使用方法
- 游客登录功能 - 游客登录的完整实现
🛡️ 安全最佳实践
- 密码安全: 使用强密码策略,密码使用 bcrypt 加密
- 会话管理: 定期刷新令牌,设置合理的过期时间
- 输入验证: 所有输入都经过 Zod 验证
- 错误处理: 不暴露敏感信息的错误消息
- 速率限制: 实施登录尝试限制和锁定机制
- HTTPS: 生产环境必须使用 HTTPS
- 环境变量: 敏感配置使用环境变量存储
🔄 错误处理
所有 API 方法都返回统一的响应格式:
interface AuthResponse {
success: boolean;
user?: User;
session?: SessionInfo;
access_token?: string;
refresh_token?: string;
expires_in?: number;
message?: string;
error?: string;
data?: any; // 通用数据字段
}🚀 开发
# 安装依赖
pnpm install
# 运行测试
pnpm test
# 构建
pnpm build
# 类型检查
pnpm type-check📄 许可证
MIT
🤝 贡献
欢迎提交 Issue 和 Pull Request!
📞 支持
如有问题,请通过以下方式联系:
- 提交 GitHub Issue
- 查看 文档示例
- 参考 最佳实践
