Files
kevisual-query-login/dist/query-login.js
2025-03-21 21:34:26 +08:00

319 lines
8.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// src/query-login.ts
import { Query } from "@kevisual/query";
import { setBaseResponse } from "@kevisual/query/query";
// src/login-cache.ts
import { MyCache } from "@kevisual/cache";
var LoginCacheStore = class {
cache;
name;
cacheData;
constructor(name) {
this.cache = new MyCache(name);
this.cacheData = {
loginUsers: [],
user: void 0,
id: void 0,
accessToken: void 0,
refreshToken: void 0
};
this.name = name;
}
/**
* 设置缓存
* @param key
* @param value
* @returns
*/
async set(key, value) {
await this.cache.set(key, value);
return value;
}
/**
* 删除缓存
*/
async del() {
await this.cache.del();
}
get(key) {
return this.cache.get(key);
}
async init() {
this.cacheData = await this.get(this.name) || {
loginUsers: [],
user: null,
id: null,
accessToken: null,
refreshToken: null
};
}
/**
* 设置当前用户
* @param user
*/
async setLoginUser(user) {
const has = this.cacheData.loginUsers.find((u) => u.id === user.id);
if (has) {
this.cacheData.loginUsers = this.cacheData?.loginUsers?.filter((u) => u?.id && u.id !== user.id);
}
this.cacheData.loginUsers.push(user);
this.cacheData.user = user.user;
this.cacheData.id = user.id;
this.cacheData.accessToken = user.accessToken;
this.cacheData.refreshToken = user.refreshToken;
await this.set(this.name, this.cacheData);
}
getCurrentUser() {
const cacheData = this.cacheData;
return Promise.resolve(cacheData.user);
}
getCurrentUserList() {
return Promise.resolve(this.cacheData.loginUsers.filter((u) => u?.id));
}
getRefreshToken() {
const cacheData = this.cacheData;
return Promise.resolve(cacheData.refreshToken || "");
}
getAccessToken() {
const cacheData = this.cacheData;
return Promise.resolve(cacheData.accessToken || "");
}
async clearCurrentUser() {
const user = await this.getCurrentUser();
const has = this.cacheData.loginUsers.find((u) => u.id === user.id);
if (has) {
this.cacheData.loginUsers = this.cacheData?.loginUsers?.filter((u) => u?.id && u.id !== user.id);
}
this.cacheData.user = void 0;
this.cacheData.id = void 0;
this.cacheData.accessToken = void 0;
this.cacheData.refreshToken = void 0;
await this.set(this.name, this.cacheData);
}
async clearAll() {
this.cacheData.loginUsers = [];
this.cacheData.user = void 0;
this.cacheData.id = void 0;
this.cacheData.accessToken = void 0;
this.cacheData.refreshToken = void 0;
await this.set(this.name, this.cacheData);
}
};
// src/query-login.ts
var QueryLogin = class {
query;
cache;
isBrowser;
load;
storage;
onLoad;
constructor(opts) {
this.query = opts?.query || new Query();
this.cache = new LoginCacheStore("login");
this.isBrowser = opts?.isBrowser ?? true;
this.init();
this.onLoad = opts?.onLoad;
this.storage = opts?.storage || localStorage;
}
setQuery(query) {
this.query = query;
}
async init() {
await this.cache.init();
this.load = true;
this.onLoad?.();
}
async post(data, opts) {
return this.query.post({ path: "user", ...data }, opts);
}
/**
* 登录,
* @param data
* @returns
*/
async login(data) {
const res = await this.post({ key: "login", ...data });
if (res.code === 200) {
const { accessToken, refreshToken } = res?.data || {};
this.storage.setItem("token", accessToken || "");
await this.beforeSetLoginUser({ accessToken, refreshToken });
}
return res;
}
/**
* 登陆成功,需要获取用户信息进行缓存
* @param param0
*/
async beforeSetLoginUser({ accessToken, refreshToken, check401 }) {
if (accessToken && refreshToken) {
const resUser = await this.getMe(accessToken, check401);
if (resUser.code === 200) {
const user = resUser.data;
if (user) {
this.cache.setLoginUser({
user,
id: user.id,
accessToken,
refreshToken
});
} else {
console.error("\u767B\u5F55\u5931\u8D25");
}
}
}
}
async queryRefreshToken(refreshToken) {
const _refreshToken = refreshToken || this.cache.getRefreshToken();
let data = { refreshToken: _refreshToken };
if (!_refreshToken) {
await this.cache.clearCurrentUser();
return {
code: 401,
message: "\u8BF7\u5148\u767B\u5F55",
data: {}
};
}
return this.post(
{ key: "refreshToken", data },
{
afterResponse: async (response, ctx) => {
setBaseResponse(response);
return response;
}
}
);
}
/**
* 检查401错误并刷新token, 如果refreshToken存在则刷新token, 否则返回401
* @param response
* @param ctx
* @param refetch
* @returns
*/
async afterCheck401ToRefreshToken(response, ctx, refetch) {
const that = this;
if (response?.code === 401) {
const hasRefreshToken = await that.cache.getRefreshToken();
if (hasRefreshToken) {
const res = await that.queryRefreshToken(hasRefreshToken);
if (res.code === 200) {
const { accessToken, refreshToken } = res?.data || {};
that.storage.setItem("token", accessToken || "");
await that.beforeSetLoginUser({ accessToken, refreshToken, check401: false });
if (refetch && ctx && ctx.req && ctx.req.url && ctx.fetch) {
await new Promise((resolve) => setTimeout(resolve, 1500));
const url = ctx.req?.url;
const body = ctx.req?.body;
const headers = ctx.req?.headers;
const res2 = await ctx.fetch(url, {
method: "POST",
body,
headers: { ...headers, Authorization: `Bearer ${accessToken}` }
});
setBaseResponse(res2);
return res2;
}
} else {
that.storage.removeItem("token");
await that.cache.clearCurrentUser();
}
return res;
}
}
return response;
}
/**
* 获取用户信息
* @param token
* @returns
*/
async getMe(token, check401 = true) {
const _token = token || this.storage.getItem("token");
const that = this;
return that.post(
{ key: "me" },
{
beforeRequest: async (config) => {
if (config.headers) {
config.headers["Authorization"] = `Bearer ${_token}`;
}
return config;
},
afterResponse: async (response, ctx) => {
if (response?.code === 401 && check401) {
return await that.afterCheck401ToRefreshToken(response, ctx);
}
return response;
}
}
);
}
/**
* 请求更新,切换用户, 使用switchUser
* @param username
* @returns
*/
async postSwitchUser(username) {
return this.post({ key: "switchCheck", data: { username } });
}
/**
* 切换用户
* @param username
* @returns
*/
async switchUser(username) {
const localUserList = await this.cache.getCurrentUserList();
const user = localUserList.find((userItem) => userItem.user.username === username);
if (user) {
this.storage.setItem("token", user.accessToken || "");
await this.beforeSetLoginUser({ accessToken: user.accessToken, refreshToken: user.refreshToken });
return {
code: 200,
data: {
accessToken: user.accessToken,
refreshToken: user.refreshToken
},
success: true,
message: "\u5207\u6362\u7528\u6237\u6210\u529F"
};
}
const res = await this.postSwitchUser(username);
if (res.code === 200) {
const { accessToken, refreshToken } = res?.data || {};
this.storage.setItem("token", accessToken || "");
await this.beforeSetLoginUser({ accessToken, refreshToken });
}
return res;
}
async logout() {
this.storage.removeItem("token");
this.cache.del();
return this.post({ key: "logout" });
}
async hasUser(username) {
const that = this;
return this.post(
{
path: "org",
key: "hasUser",
data: {
username
}
},
{
afterResponse: async (response, ctx) => {
if (response?.code === 401) {
const res = await that.afterCheck401ToRefreshToken(response, ctx, true);
return res;
}
return response;
}
}
);
}
};
export {
QueryLogin
};