Files
hair/static/client_auth.js
T

65 lines
2.1 KiB
JavaScript

(() => {
const form = document.getElementById("client-auth");
const message = document.getElementById("client-auth-status");
const button = form.querySelector("button");
let accessToken;
let refreshToken;
let accessExpiry = 0;
async function requestToken(operation, data) {
const response = await fetch("/api/v1/auth/" + operation, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data),
});
const result = await response.json();
if (!response.ok || result.code !== 0) throw new Error(result.message || "鉴权失败");
accessToken = result.data.access_token;
accessExpiry = Date.now() + result.data.expires_in * 1000;
return result.data;
}
form.addEventListener("submit", async (event) => {
event.preventDefault();
button.disabled = true;
const data = new FormData(form);
try {
const result = await requestToken("login", {
username: data.get("username"),
password: data.get("password"),
});
refreshToken = result.refresh_token;
message.textContent = "已登录。访问令牌过期时会自动刷新。";
} catch (error) {
message.textContent = error.message;
} finally {
form.elements.namedItem("password").value = "";
button.disabled = false;
}
});
async function refresh() {
if (!refreshToken) throw new Error("请先登录,再提交图片。");
try {
await requestToken("refresh", { refresh_token: refreshToken });
} catch (error) {
accessToken = refreshToken = undefined;
message.textContent = "请重新登录。";
throw error;
}
}
window.hairClientFetch = async (path, options) => {
if (Date.now() >= accessExpiry || !accessToken) await refresh();
const send = () => {
const headers = new Headers(options.headers);
headers.set("Authorization", "Bearer " + accessToken);
return fetch(path, { ...options, headers });
};
const response = await send();
if (response.status !== 401) return response;
await refresh();
return send();
};
})();