如何在Supabase中预验证重置密码Token,无效时跳转登录页?
Supabase重置密码页面前置Token验证实现方案
核心思路
在重置密码页面渲染前,从URL提取Token,调用Supabase官方验证接口校验Token有效性:
- 验证通过:正常展示重置密码表单
- 验证失败/无Token:立即跳转至登录页面
具体实现步骤
- 提取URL中的Token:从页面URL的查询参数中获取
token(Supabase默认重置密码链接的参数名为token)。 - 调用Supabase Token验证接口:使用Supabase Auth模块的
verifyOtp方法,指定type: 'recovery'(重置密码Token属于恢复类OTP),验证Token的有效性。 - 根据验证结果处理页面逻辑:无Token/验证失败直接跳转登录页;验证通过则渲染重置密码表单,后续提交新密码时可直接调用
updateUser接口(验证通过后Supabase会生成临时会话)。
代码示例
React 前端验证
import { useEffect, useState } from 'react'; import { supabase } from '../utils/supabaseClient'; import { useNavigate } from 'react-router-dom'; const ResetPasswordPage = () => { const navigate = useNavigate(); const [loading, setLoading] = useState(true); useEffect(() => { const checkTokenValidity = async () => { const params = new URLSearchParams(window.location.search); const token = params.get('token'); if (!token) { navigate('/login'); return; } try { const { error } = await supabase.auth.verifyOtp({ token, type: 'recovery' }); if (error) navigate('/login'); } catch (err) { console.error('Token验证失败:', err); navigate('/login'); } finally { setLoading(false); } }; checkTokenValidity(); }, [navigate]); if (loading) return <div>加载中...</div>; return ( <div className="reset-password-form"> <h2>重置密码</h2> <form onSubmit={async (e) => { e.preventDefault(); const newPassword = e.target.password.value; const { error } = await supabase.auth.updateUser({ password: newPassword }); if (error) alert('密码重置失败:' + error.message); else { alert('密码重置成功'); navigate('/login'); } }}> <input type="password" name="password" placeholder="设置新密码" required /> <button type="submit">确认重置</button> </form> </div> ); }; export default ResetPasswordPage;
纯 JavaScript 验证
document.addEventListener('DOMContentLoaded', async () => { const params = new URLSearchParams(window.location.search); const token = params.get('token'); if (!token) { window.location.href = '/login.html'; return; } try { const { error } = await supabase.auth.verifyOtp({ token, type: 'recovery' }); if (error) { window.location.href = '/login.html'; } else { // 显示重置密码表单 document.getElementById('reset-form').style.display = 'block'; } } catch (err) { console.error('Token验证出错:', err); window.location.href = '/login.html'; } });
Next.js 服务器端验证(更安全)
// pages/reset-password.js import { supabase } from '../utils/supabaseClient'; import { useRouter } from 'next/router'; export async function getServerSideProps(context) { const { token } = context.query; if (!token) { return { redirect: { destination: '/login', permanent: false } }; } try { const { error } = await supabase.auth.verifyOtp({ token, type: 'recovery' }); if (error) return { redirect: { destination: '/login', permanent: false } }; } catch (err) { return { redirect: { destination: '/login', permanent: false } }; } return { props: { token } }; } export default function ResetPasswordPage() { const router = useRouter(); const handleSubmit = async (e) => { e.preventDefault(); const newPassword = e.target.password.value; const { error } = await supabase.auth.updateUser({ password: newPassword }); if (error) alert('密码重置失败:' + error.message); else { alert('密码重置成功'); router.push('/login'); } }; return ( <div> <h2>重置密码</h2> <form onSubmit={handleSubmit}> <input type="password" name="password" placeholder="设置新密码" required /> <button type="submit">确认重置</button> </form> </div> ); }
注意事项
- 确保Supabase客户端已正确初始化,包含Auth模块配置
verifyOtp的type必须设为recovery,否则无法正确验证重置密码Token- 验证过程中显示加载状态,避免用户重复操作
- 跳转登录前可提示模糊错误信息(如“链接已失效,请重新申请重置密码”),不要泄露Token具体错误细节
- Supabase重置密码Token默认有效期为1小时,验证时会自动判断是否过期
内容的提问来源于stack exchange,提问作者lodey
相关产品推荐
相关产品推荐

