Files
cstb-next/docs/web-integration-example.md
2025-11-05 11:21:13 +08:00

272 lines
7.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 网页端集成示例代码
本文档提供网页端https://cstb.upup.cool/)实现登录/注册回调的示例代码。
## 登录页面示例
`auth/login` 页面中:
```typescript
'use client'
import { useState } from 'react'
import { createClient } from '@/utils/supabase/client'
import { useSearchParams } from 'next/navigation'
export default function LoginPage() {
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const [loading, setLoading] = useState(false)
const searchParams = useSearchParams()
const redirectTo = searchParams.get('redirect') // 应该是 'cstb://auth'
const supabase = createClient()
const handleLogin = async (e: React.FormEvent) => {
e.preventDefault()
setLoading(true)
try {
const { data, error } = await supabase.auth.signInWithPassword({
email,
password,
})
if (error) {
alert(`登录失败: ${error.message}`)
setLoading(false)
return
}
if (data.session) {
// 如果有 redirect 参数,说明是从应用跳转过来的
if (redirectTo) {
// 构建 deep-link URL
const redirectUrl = new URL(redirectTo)
redirectUrl.searchParams.set('access_token', data.session.access_token)
redirectUrl.searchParams.set('refresh_token', data.session.refresh_token)
// 重定向到应用
window.location.href = redirectUrl.toString()
} else {
// 正常网页端跳转
window.location.href = '/'
}
}
} catch (error) {
console.error('Login error:', error)
alert('登录时发生错误')
setLoading(false)
}
}
return (
<form onSubmit={handleLogin}>
<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="密码"
required
/>
<button type="submit" disabled={loading}>
{loading ? '登录中...' : '登录'}
</button>
</form>
)
}
```
## 注册页面示例
`auth/signup` 页面中:
```typescript
'use client'
import { useState } from 'react'
import { createClient } from '@/utils/supabase/client'
import { useSearchParams } from 'next/navigation'
export default function SignupPage() {
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const [confirmPassword, setConfirmPassword] = useState('')
const [loading, setLoading] = useState(false)
const searchParams = useSearchParams()
const redirectTo = searchParams.get('redirect') // 应该是 'cstb://auth'
const supabase = createClient()
const handleSignup = async (e: React.FormEvent) => {
e.preventDefault()
if (password !== confirmPassword) {
alert('两次输入的密码不一致')
return
}
setLoading(true)
try {
const { data, error } = await supabase.auth.signUp({
email,
password,
})
if (error) {
alert(`注册失败: ${error.message}`)
setLoading(false)
return
}
if (data.session) {
// 如果有 redirect 参数,说明是从应用跳转过来的
if (redirectTo) {
// 构建 deep-link URL
const redirectUrl = new URL(redirectTo)
redirectUrl.searchParams.set('access_token', data.session.access_token)
redirectUrl.searchParams.set('refresh_token', data.session.refresh_token)
// 重定向到应用
window.location.href = redirectUrl.toString()
} else {
// 正常网页端跳转
alert('注册成功!请检查邮箱验证链接。')
window.location.href = '/'
}
} else {
// 需要邮箱验证
alert('注册成功!请检查邮箱中的验证链接。')
if (!redirectTo) {
window.location.href = '/'
}
}
} catch (error) {
console.error('Signup error:', error)
alert('注册时发生错误')
setLoading(false)
}
}
return (
<form onSubmit={handleSignup}>
<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="密码"
required
/>
<input
type="password"
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.target.value)}
placeholder="确认密码"
required
/>
<button type="submit" disabled={loading}>
{loading ? '注册中...' : '注册'}
</button>
</form>
)
}
```
## 使用 OAuth 提供商的示例
如果使用第三方登录(如 Google、GitHub 等):
```typescript
const handleOAuthLogin = async (provider: 'google' | 'github') => {
const { data, error } = await supabase.auth.signInWithOAuth({
provider,
options: {
redirectTo: redirectTo || `${window.location.origin}/auth/callback`,
},
})
if (error) {
alert(`登录失败: ${error.message}`)
return
}
// OAuth 会重定向到回调页面,在回调页面中处理
}
```
## 回调页面处理
如果需要处理 OAuth 回调:
```typescript
// auth/callback/page.tsx
'use client'
import { useEffect } from 'react'
import { createClient } from '@/utils/supabase/client'
import { useSearchParams } from 'next/navigation'
export default function CallbackPage() {
const searchParams = useSearchParams()
const redirectTo = searchParams.get('redirect') // 从应用跳转时的原始 redirect
useEffect(() => {
const handleCallback = async () => {
const supabase = createClient()
const { data: { session }, error } = await supabase.auth.getSession()
if (error) {
console.error('Error getting session:', error)
return
}
if (session) {
// 如果是从应用跳转过来的,重定向回应用
if (redirectTo) {
const redirectUrl = new URL(redirectTo)
redirectUrl.searchParams.set('access_token', session.access_token)
redirectUrl.searchParams.set('refresh_token', session.refresh_token)
window.location.href = redirectUrl.toString()
} else {
// 正常网页端跳转
window.location.href = '/'
}
}
}
void handleCallback()
}, [redirectTo])
return <div>...</div>
}
```
## 注意事项
1. **安全性**: 确保只在 HTTPS 环境下使用,避免 token 泄露
2. **错误处理**: 始终处理登录/注册失败的情况
3. **用户体验**: 在重定向前显示加载状态
4. **验证**: 如果启用了邮箱验证,需要处理未验证的情况
## 测试步骤
1. 在应用中使用 `https://cstb.upup.cool/auth/login?redirect=cstb://auth` 打开登录页面
2. 完成登录后,应该自动跳转回应用
3. 检查应用是否成功接收并设置了 session