在 React 中使用 Supabase 认证
Learn how to use Supabase Auth with React.js.
快速入门 #
🌐 Quickstart
使用 Vite 模板创建一个 React 应用。
1npm create vite@latest my-app -- --template react进入 React 应用并安装 Supabase 库。
1cd my-app && npm install @supabase/supabase-js将 .env.example 重命名为 .env.local 并填写你的 Supabase 连接变量:
获取 API 详情 #
🌐 Get API details
要与数据库表中的数据进行交互,你可以使用封装了自动生成的数据 API 端点的客户端库,并使用来自项目 Connect 对话框的项目 URL 和密钥进行认证。
🌐 To interact with data in database tables, you use the client libraries that wrap the auto-generated Data API endpoints, authenticating using the Project URL and key from the project Connect dialog.
阅读 API 密钥文档 以全面了解所有密钥类型、用途以及在哪里可以找到它们。
1VITE_SUPABASE_URL=your-project-url2VITE_SUPABASE_PUBLISHABLE_KEY=your-publishable-key-or-anon-key探索适用于你 Supabase 应用的即插即用 UI 组件。
基于 shadcn/ui 构建的 UI 组件,通过一个命令连接到 Supabase。
🌐 UI components built on shadcn/ui that connect to Supabase via a single command.
探索组件在 App.jsx 中,使用你的项目 URL 和密钥创建一个 Supabase 客户端。
这段代码在 App.jsx 中使用 getClaims 方法来验证本地 JWT,然后再显示已登录的用户。
1import './index.css'2import { useState, useEffect } from 'react'3import { createClient } from '@supabase/supabase-js'45const supabase = createClient(6 import.meta.env.VITE_SUPABASE_URL,7 import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY8)910export default function App() {11 const [loading, setLoading] = useState(false)12 const [email, setEmail] = useState('')13 const [claims, setClaims] = useState(null)1415 // Check URL params on initial render16 const params = new URLSearchParams(window.location.search)17 const hasTokenHash = params.get('token_hash')1819 const [verifying, setVerifying] = useState(!!hasTokenHash)20 const [authError, setAuthError] = useState(null)21 const [authSuccess, setAuthSuccess] = useState(false)2223 useEffect(() => {24 // Check if we have token_hash in URL (magic link callback)25 const params = new URLSearchParams(window.location.search)26 const token_hash = params.get('token_hash')27 const type = params.get('type')2829 if (token_hash) {30 // Verify the OTP token31 supabase.auth32 .verifyOtp({33 token_hash,34 type: type || 'email',35 })36 .then(({ error }) => {37 if (error) {38 setAuthError(error.message)39 } else {40 setAuthSuccess(true)41 // Clear URL params42 window.history.replaceState({}, document.title, '/')43 }44 setVerifying(false)45 })46 }4748 // Check for existing session using getClaims49 supabase.auth.getClaims().then(({ data: { claims } }) => {50 setClaims(claims)51 })5253 // Listen for auth changes54 const {55 data: { subscription },56 } = supabase.auth.onAuthStateChange(() => {57 supabase.auth.getClaims().then(({ data: { claims } }) => {58 setClaims(claims)59 })60 })6162 return () => subscription.unsubscribe()63 }, [])6465 const handleLogin = async (event) => {66 event.preventDefault()67 setLoading(true)68 const { error } = await supabase.auth.signInWithOtp({69 email,70 options: {71 emailRedirectTo: window.location.origin,72 },73 })74 if (error) {75 alert(error.error_description || error.message)76 } else {77 alert('Check your email for the login link!')78 }79 setLoading(false)80 }8182 const handleLogout = async () => {83 await supabase.auth.signOut()84 setClaims(null)85 }8687 // Show verification state88 if (verifying) {89 return (90 <div>91 <h1>Authentication</h1>92 <p>Confirming your magic link...</p>93 <p>Loading...</p>94 </div>95 )96 }9798 // Show auth error99 if (authError) {100 return (101 <div>102 <h1>Authentication</h1>103 <p>✗ Authentication failed</p>104 <p>{authError}</p>105 <button106 onClick={() => {107 setAuthError(null)108 window.history.replaceState({}, document.title, '/')109 }}110 >111 Return to login112 </button>113 </div>114 )115 }116117 // Show auth success (briefly before claims load)118 if (authSuccess && !claims) {119 return (120 <div>121 <h1>Authentication</h1>122 <p>✓ Authentication successful!</p>123 <p>Loading your account...</p>124 </div>125 )126 }127128 // If user is logged in, show welcome screen129 if (claims) {130 return (131 <div>132 <h1>Welcome!</h1>133 <p>You are logged in as: {claims.email}</p>134 <button onClick={handleLogout}>Sign Out</button>135 </div>136 )137 }138139 // Show login form140 return (141 <div>142 <h1>Supabase + React</h1>143 <p>Sign in via magic link with your email below</p>144 <form onSubmit={handleLogin}>145 <input146 type="email"147 placeholder="Your email"148 value={email}149 required={true}150 onChange={(e) => setEmail(e.target.value)}151 />152 <button disabled={loading}>153 {loading ? <span>Loading</span> : <span>Send magic link</span>}154 </button>155 </form>156 </div>157 )158}