general

其他语言:English·Deutsch

-- title: "认证与安全" description: "TanStack Ship 认证系统,支持 Google OAuth SSO、邮箱/密码登录、JWT 会话管理和基于角色的访问控制(RBAC)。" category: auth order: 1 icon: shield features:

  • Google OAuth 2.0 单点登录集成
  • 邮箱和密码认证,基于 bcrypt 的密码哈希
  • 服务端 JWT 令牌验证的安全会话管理
  • 基于角色的访问控制(RBAC),支持用户和管理员角色
  • 账户安全设置和个人资料管理
  • 邮箱验证与密码重置流程
  • 基于邀请的团队注册机制

概述

TanStack Ship 的认证与安全系统提供了一个全面的、生产就绪的用户身份管理解决方案。它支持多种认证方式,包括 Google OAuth 2.0 单点登录和传统的邮箱/密码登录,所有功能都建立在服务端令牌验证的安全会话管理基础之上。

访问控制在应用的每一层强制执行——从 TanStack Router(React Router 的类型安全演进)的路由守卫到 API 级别的授权检查。RBAC(基于角色的访问控制)系统确保用户只能访问其角色对应的资源,同时管理员拥有有效管理平台所需的工具。

作为 TanStack Ship 平台的一部分,认证模块与账单系统(订阅权限控制)、邀请系统(团队增长)和管理面板(用户管理)紧密集成。

认证流程

认证系统支持多种登录方式,全部汇聚到统一的会话管理层:

设计理念

认证系统基于三个核心安全原则构建:

  • 纵深防御 — 访问控制在多个独立层面强制执行:路由守卫、API 授权和 UI 级别渲染。即使某一层被攻破,其他层仍然有效。与 Auth0 或 Clerk 等将认证外部化到第三方域的一体化认证提供商不同,我们的方案将会话验证完全保留在您基础设施内部的服务端,核心安全决策不依赖外部服务。
  • 最小权限 — 用户被分配其角色所需的最低权限。RBAC 系统确保标准用户无法访问管理功能,API 端点在执行每个操作前验证权限。
  • 服务端信任 — 所有会话验证在服务端完成。JWT 令牌使用服务端密钥签名,存储在 HTTP-only Cookie 中,在每个受保护请求上验证。客户端检查仅用于 UX——真正的安全在服务端执行。

核心能力

Google OAuth 2.0 集成

用户可以通过 Google 账号使用 OAuth 2.0 授权码流程登录。实现遵循 Google 推荐的安全实践,包括通过 state 参数进行 CSRF 保护,以及 PKCE(Proof Key for Code Exchange)增强安全性。

OAuth 流程:

  1. 用户在 /login 页面点击"使用 Google 登录"
  2. 应用重定向到 Google 的 OAuth 授权页面,使用配置的范围(openid、email、profile)
  3. 用户在 Google 域上授予权限
  4. /api/auth/callback 授权回调将授权码交换为令牌
  5. 服务器创建或更新用户记录并签发会话令牌
  6. 用户被重定向到已认证的仪表板

OAuth 回调端点验证 state 参数以防止 CSRF 攻击,并无缝处理新用户创建和现有用户登录。

邮箱与密码认证

具备企业级安全的传统邮箱/密码认证:

  • 密码哈希 — 所有密码使用 bcrypt 进行哈希,采用可配置的成本因子
  • 注册流程 — 新用户通过邮箱、密码和可选的邀请码注册
  • 邮箱验证 — 验证过的邮箱地址是访问受保护功能的必要条件
  • 密码重置 — 基于安全令牌的密码重置流程,带过期机制
  • 输入验证 — 使用 Zod schema 在服务端进行邮箱格式和密码强度验证

认证系统在任何阶段都不存储明文密码。整个注册和登录流程遵循 OWASP 认证最佳实践设计。

会话管理

会话通过存储在 HTTP-only cookie 中的服务端 JWT 令牌进行管理:

  • 安全令牌 — JWT 使用服务端密钥签名,包含用户 ID、角色和过期声明
  • 服务端验证 — 每个受保护路由在服务端验证令牌的有效性和过期时间
  • 可配置过期 — 会话 TTL 可通过环境变量配置
  • 登出 — 登出时令牌失效,清除服务端会话

会话中间件作为 TanStack Router 的 loader 守卫实现,确保未认证用户在渲染任何受保护内容之前被重定向到登录页面。

基于角色的访问控制(RBAC)

两个内置角色提供了清晰的访问边界:

  • 用户 — 标准访问权限,可使用仪表板、账单管理、个人资料设置和功能使用
  • 管理员 — 完全访问权限,可管理管理面板、用户管理、账单管理、系统配置和分析仪表板

访问控制在多层面强制执行:

  • 路由层面 — TanStack Router loader 在渲染受保护页面之前检查用户角色
  • API 层面 — 服务端函数在执行操作前验证权限
  • UI 层面 — 组件有条件地渲染仅管理员可见的菜单和操作

RBAC 系统是可扩展的——可以通过数据库 schema 和权限中间件添加额外的角色。

账户安全与个人资料管理

用户可以通过仪表板管理其安全设置:

  • 个人资料信息更新(姓名、头像、联系邮箱)
  • 密码更改(需当前密码验证)
  • 已关联 Google 账户管理
  • 账户删除(带确认流程)

示例 — 带 Google OAuth 的登录组件:

tsx
import { useNavigate } from '@tanstack/react-router'

export function LoginPage() {
  const navigate = useNavigate()

  const handleGoogleLogin = () => {
    window.location.href = '/api/auth/google'
  }

  const handleEmailLogin = async (e: React.FormEvent) => {
    e.preventDefault()
    const form = new FormData(e.target as HTMLFormElement)
    const res = await fetch('/api/auth/login', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        email: form.get('email'),
        password: form.get('password'),
      }),
    })
    if (res.ok) navigate({ to: '/dashboard' })
  }

  return (
    <div>
      <button onClick={handleGoogleLogin}>使用 Google 登录</button>
      <hr />
      <form onSubmit={handleEmailLogin}>
        <input name="email" type="email" placeholder="邮箱" required />
        <input name="password" type="password" placeholder="密码" required />
        <button type="submit">登录</button>
      </form>
    </div>
  )
}

最佳实践

密码策略执行

实施强密码策略,要求最小长度(12+ 字符)、混合大小写、数字和特殊字符。在客户端和服务端都使用 Zod 验证 schema,在注册期间提供即时反馈。

OAuth State 参数验证

始终在 OAuth 回调中验证 state 参数以防止 CSRF 攻击。系统为每个认证请求生成唯一的 state 值,并在回调时验证其匹配。

权限提升时的会话轮换

每当用户角色变更或执行敏感操作(密码更改、邮箱更新)时,签发新的会话令牌。这限制了被盗令牌的可利用窗口。

认证端点的限流

对登录、注册和密码重置端点应用限流,防止暴力破解攻击。系统的中间件可以跟踪每个 IP 地址的失败尝试次数,并临时阻止过多请求。


常见问题

如何为我的域名设置 Google OAuth? 在 Google Cloud Console 创建一个项目,配置 OAuth 授权页面,使用域名的回调 URL(https://yourdomain.com/api/auth/callback)创建凭据,然后在 .dev.vars 文件中设置客户端 ID 和密钥。

能否添加更多 OAuth 提供商,如 GitHub 或 Microsoft? 可以。认证架构支持多个 OAuth 提供商。每个提供商需要自己的回调端点和凭据配置。用户数据库 schema 支持每个用户账户关联多个提供商 ID。

会话持续多长时间? 会话 TTL 可通过 JWT_EXPIRES_IN 环境变量配置。默认为 7 天。活跃用户的会话可以在每次认证请求时延长。

JWT 过期时会发生什么? 会话中间件检测到过期令牌后,会将用户重定向到登录页面,并显示会话过期提示。用户可以重新认证以获得新的会话令牌。

能否禁用邮箱/密码登录,仅使用 OAuth? 可以。认证系统是模块化的。您可以通过移除相应的路由处理器和 UI 组件来禁用邮箱/密码登录。登录页面将自动适应,仅显示已配置的认证方式。

用户角色最初如何分配? 新用户默认分配 user 角色。管理员提升可以通过数据库直接操作、初始超级管理员种子脚本或管理员管理界面完成。

基于邀请的注册是如何工作的? 现有用户可以通过邀请系统生成邀请码。新用户可以使用邀请码注册,这会将他们与邀请用户关联,并可选择分配预定义角色。


配置

在 .dev.vars 中配置以下环境变量:

GOOGLE_CLIENT_ID=xxx.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=GOCSPX-...
JWT_SECRET=your-secure-secret-key-min-32-chars
JWT_EXPIRES_IN=7d

对于 Google OAuth,在 Google Cloud Console 创建一个项目,配置 OAuth 授权页面,然后将您的回调 URL 添加到授权重定向 URI 中。


集成点

认证系统与以下 TanStack Ship 平台模块集成:

  • 账单系统 — 订阅状态与用户账户关联;高级功能访问受活跃订阅限制
  • 邀请系统 — 新用户可通过邀请码被邀请;被邀请用户自动与邀请者关联
  • 管理面板 — 管理员角色授予用户管理、系统配置和分析的访问权限
  • 仪表板路由 — 会话中间件保护所有仪表板路由,将未认证用户重定向到登录页面
  • 活动与优惠 — 领取促销优惠和应用折扣码需要用户认证
  • 博客 CMS — 作者和编辑是具有内容管理权限的认证用户