实现Chrome扩展与Next.js Web应用的登录状态同步
Chrome扩展与Next Auth Web应用登录状态同步方案
已经拿到Web应用传来的access token后,扩展内的认证流程核心是持久化存储token、验证有效性、维护登录态、请求时携带token,具体步骤如下:
1. 持久化存储Access Token
把接收到的token和过期时间存储到Chrome扩展的本地存储中,确保页面刷新或扩展重启后能恢复状态:
// 在扩展的背景页/服务工作者中监听Web应用的消息 chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { if (message.type === 'SYNC_LOGIN_TOKEN') { // 存储token及过期时间(如果Next Auth返回了expires_in) chrome.storage.local.set({ accessToken: message.accessToken, expiresAt: Date.now() + (message.expiresIn || 3600) * 1000, // 默认1小时过期 refreshToken: message.refreshToken // 如果有refresh token也一起存 }, () => { // 触发扩展内的登录状态更新逻辑 updateAuthState(true); }); } });
2. 验证Token有效性(可选但推荐)
使用Next Auth的会话验证端点或服务商的token校验接口,确保存储的token未失效:
async function validateAccessToken(accessToken) { try { // 调用Next Auth的会话接口验证token const res = await fetch('/api/auth/session', { headers: { 'Authorization': `Bearer ${accessToken}` } }); return res.ok; } catch (err) { console.error('Token验证失败:', err); return false; } }
3. 扩展内维护登录状态
在扩展的popup、content script等页面初始化时,读取存储的token并判断登录状态:
// popup页面初始化时检查登录状态 document.addEventListener('DOMContentLoaded', async () => { const { accessToken, expiresAt } = await chrome.storage.local.get(['accessToken', 'expiresAt']); if (accessToken && expiresAt > Date.now()) { const isValid = await validateAccessToken(accessToken); if (isValid) { // 渲染已登录UI renderLoggedInUI(); } else { // token无效,清理存储 chrome.storage.local.remove(['accessToken', 'expiresAt', 'refreshToken']); renderLoggedOutUI(); } } else { renderLoggedOutUI(); } });
4. 处理Token过期与刷新
如果Next Auth返回了refresh token,实现自动刷新逻辑,避免用户重复登录:
async function refreshAuthToken() { const { refreshToken } = await chrome.storage.local.get('refreshToken'); if (!refreshToken) return false; try { const res = await fetch('/api/auth/token', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ grant_type: 'refresh_token', refresh_token: refreshToken, client_id: 'your-next-auth-client-id' // 按需填写 }) }); const data = await res.json(); if (data.access_token) { await chrome.storage.local.set({ accessToken: data.access_token, expiresAt: Date.now() + data.expires_in * 1000, refreshToken: data.refresh_token || refreshToken }); return true; } return false; } catch (err) { console.error('Token刷新失败:', err); return false; } }
5. 扩展内API请求携带Token
所有需要认证的接口请求,都在请求头中携带存储的access token:
async function fetchProtectedResource() { const { accessToken } = await chrome.storage.local.get('accessToken'); if (!accessToken) throw new Error('用户未登录'); const res = await fetch('https://your-api.com/protected-endpoint', { headers: { 'Authorization': `Bearer ${accessToken}` } }); if (!res.ok) { // 若返回401,尝试刷新token后重试 const refreshed = await refreshAuthToken(); if (refreshed) return fetchProtectedResource(); throw new Error('认证失败'); } return res.json(); }
内容的提问来源于stack exchange,提问作者sid
相关产品推荐
相关产品推荐

