mirror of https://github.com/veypi/OneAuth.git
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
116 lines
2.5 KiB
JavaScript
116 lines
2.5 KiB
JavaScript
|
7 months ago
|
/*
|
||
|
|
* auth.js
|
||
|
|
* Copyright (C) 2025 veypi <i@veypi.com>
|
||
|
|
*
|
||
|
|
* Distributed under terms of the MIT license.
|
||
|
|
*/
|
||
|
|
|
||
|
|
class TokenService {
|
||
|
|
constructor() {
|
||
|
|
this.tokenKey = 'access';
|
||
|
|
this.refreshTokenKey = 'refresh';
|
||
|
|
}
|
||
|
|
|
||
|
|
setToken(token) {
|
||
|
|
localStorage.setItem(this.tokenKey, token);
|
||
|
|
}
|
||
|
|
|
||
|
|
getToken() {
|
||
|
|
return localStorage.getItem(this.tokenKey);
|
||
|
|
}
|
||
|
|
|
||
|
|
setRefreshToken(refreshToken) {
|
||
|
|
localStorage.setItem(this.refreshTokenKey, refreshToken);
|
||
|
|
}
|
||
|
|
|
||
|
|
getRefreshToken() {
|
||
|
|
return localStorage.getItem(this.refreshTokenKey);
|
||
|
|
}
|
||
|
|
|
||
|
|
clearTokens() {
|
||
|
|
localStorage.removeItem(this.tokenKey);
|
||
|
|
localStorage.removeItem(this.refreshTokenKey);
|
||
|
|
}
|
||
|
|
|
||
|
|
hasToken() {
|
||
|
|
return !!this.getToken();
|
||
|
|
}
|
||
|
|
|
||
|
|
parseToken(token) {
|
||
|
|
try {
|
||
|
|
if (!token) return null;
|
||
|
|
const base64Url = token.split('.')[1];
|
||
|
|
const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
|
||
|
|
return JSON.parse(window.atob(base64));
|
||
|
|
} catch (error) {
|
||
|
|
console.error('Token解析失败:', error);
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
__cache = null
|
||
|
|
body() {
|
||
|
|
if (!this.__cache) {
|
||
|
|
this.__cache = this.parseToken(this.getToken());
|
||
|
|
}
|
||
|
|
return this.__cache
|
||
|
|
}
|
||
|
|
logout(root) {
|
||
|
|
console.log(this)
|
||
|
|
root = root || this.__root
|
||
|
|
this.clearTokens();
|
||
|
|
location.href = root + '/login?redirect=' + window.location.pathname;
|
||
|
|
}
|
||
|
|
|
||
|
|
__root = ''
|
||
|
|
async refreshToken(root) {
|
||
|
|
root = root || this.__root
|
||
|
|
this.__root = root
|
||
|
|
const refreshToken = this.getRefreshToken();
|
||
|
|
if (!refreshToken) {
|
||
|
|
// this.logout()
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
try {
|
||
|
|
let data = await fetch(root + '/api/token', {
|
||
|
|
method: 'post',
|
||
|
|
headers: { 'Content-Type': 'application/json' },
|
||
|
|
body: JSON.stringify({ refresh: refreshToken })
|
||
|
|
}).then(res => res.json())
|
||
|
|
if (data.code === 0) {
|
||
|
|
this.setToken(data.data);
|
||
|
|
} else {
|
||
|
|
this.clearTokens()
|
||
|
|
}
|
||
|
|
} catch (e) {
|
||
|
|
console.error('Token刷新失败:', e);
|
||
|
|
this.clearTokens()
|
||
|
|
// logout();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
isExpired() {
|
||
|
|
const decoded = this.body();
|
||
|
|
if (!decoded) return true;
|
||
|
|
|
||
|
|
const currentTime = Date.now() / 1000;
|
||
|
|
return decoded.exp < currentTime;
|
||
|
|
}
|
||
|
|
fetch() {
|
||
|
|
let that = this
|
||
|
|
return (url, options) => {
|
||
|
|
const token = that.getToken();
|
||
|
|
if (token) {
|
||
|
|
if (!options) {
|
||
|
|
options = {};
|
||
|
|
}
|
||
|
|
if (!options.headers) {
|
||
|
|
options.headers = {};
|
||
|
|
}
|
||
|
|
options.headers.Authorization = `Bearer ${token}`;
|
||
|
|
}
|
||
|
|
return fetch(url, options);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
export default new TokenService();
|