Files
SoonDesign/frontend-web/js/common/auth-session.js
T
24kycj 88c6ce8ccc 重构 monorepo 并完善网页端订阅与首页体验
- 迁移为 frontend-web、frontend-electron、backend-web 与 docker 部署结构
- 网页端:订阅门禁二次弹窗、套餐/支付组件化、顶栏分组对齐
- 首页:最近文件与模板库布局优化,缩略图对齐,下载与删除操作
- 新增管理后台、支付与云端文件 API,更新 README 与项目规范

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-08 18:17:39 +08:00

108 lines
3.4 KiB
JavaScript

(function () {
'use strict';
var refreshPromise = null;
function getAccessToken() {
try { return localStorage.getItem('soon_access') || ''; } catch (e) { return ''; }
}
function getRefreshToken() {
try { return localStorage.getItem('soon_refresh') || ''; } catch (e) { return ''; }
}
function clearSession() {
try {
localStorage.removeItem('soon_access');
localStorage.removeItem('soon_refresh');
} catch (e) { /* ignore */ }
}
function getApiBase() {
var cfg = (typeof window !== 'undefined' && window.SOON_DEPLOY_CONFIG && window.SOON_DEPLOY_CONFIG.api_v1_base);
if (cfg) return String(cfg).replace(/\/+$/, '');
if (typeof window !== 'undefined' && window.location) {
return window.location.origin + '/api/v1';
}
return '/api/v1';
}
function redirectToLogin() {
var path = 'login.web.html';
try {
var current = window.location.pathname.replace(/^.*\/pages\//, '').replace(/^\//, '');
if (current && current.indexOf('login.web.html') !== 0) {
var redirect = typeof soonSafeRedirect === 'function'
? soonSafeRedirect(current + window.location.search, 'index.web.html')
: 'index.web.html';
path = 'login.web.html?redirect=' + encodeURIComponent(redirect);
}
} catch (e) { /* use default */ }
window.location.href = path;
}
function refreshAccessToken() {
if (refreshPromise) return refreshPromise;
var refresh = getRefreshToken();
if (!refresh) {
return Promise.reject(new Error('no_refresh_token'));
}
refreshPromise = fetch(getApiBase() + '/auth/refresh', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ refresh_token: refresh }),
}).then(function (r) {
return r.json().then(function (j) {
if (!r.ok || !j.ok || !j.data || !j.data.access_token) {
throw new Error(j.message || 'refresh_failed');
}
localStorage.setItem('soon_access', j.data.access_token);
if (j.data.refresh_token) {
localStorage.setItem('soon_refresh', j.data.refresh_token);
}
return j.data.access_token;
});
}).finally(function () {
refreshPromise = null;
});
return refreshPromise;
}
function soonAuthedFetch(url, opts) {
opts = opts || {};
var headers = Object.assign({}, opts.headers || {});
var token = getAccessToken();
if (token) {
headers['Authorization'] = 'Bearer ' + token;
} else {
delete headers['Authorization'];
delete headers['authorization'];
}
opts.headers = headers;
var fullUrl = url;
if (url.indexOf('http') !== 0) {
fullUrl = getApiBase() + '/' + String(url).replace(/^\/+/, '');
}
return fetch(fullUrl, opts).then(function (response) {
if (response.status !== 401) return response;
return refreshAccessToken().then(function (newToken) {
var retryHeaders = Object.assign({}, opts.headers || {});
retryHeaders['Authorization'] = 'Bearer ' + newToken;
var retryOpts = Object.assign({}, opts, { headers: retryHeaders });
return fetch(fullUrl, retryOpts);
}).catch(function () {
clearSession();
redirectToLogin();
return response;
});
});
}
window.soonAuthedFetch = soonAuthedFetch;
window.soonClearAuthSession = clearSession;
window.soonGetAccessToken = getAccessToken;
window.soonRedirectToLogin = redirectToLogin;
})();