This commit is contained in:
Eric
2026-02-09 11:24:51 +08:00
commit f2173a9fa9
491 changed files with 43791 additions and 0 deletions

View File

@@ -0,0 +1,101 @@
/**
* 认证核心逻辑
* 实现OAuth2授权码模式的完整流程
*/
import { EventType, RouterInfo, SDKConfig, UserInfo } from '../types';
import { Storage } from '../utils/storage';
/**
* 认证核心类
*/
export declare class Auth {
private config;
private tokenManager;
private httpClient;
private storage;
private eventHandlers;
private userInfoCache;
/**
* 构造函数
* @param storage 存储实例
*/
constructor(storage: Storage);
/**
* 初始化SDK配置
* @param config SDK配置选项
*/
init(config: SDKConfig): void;
getToken(): string | null;
/**
* 触发登录流程
* @param redirectUri 可选的重定向URL覆盖初始化时的配置
*/
login(redirectUri?: string): Promise<void>;
/**
* 退出登录
*/
logout(): Promise<void>;
/**
* 处理授权回调
* @returns Promise<UserInfo> 用户信息
*/
handleCallback(): Promise<void>;
getRoutes(): Promise<RouterInfo>;
/**
* 获取用户信息
* @returns UserInfo 用户信息
*/
getUserInfo(): UserInfo;
/**
* 检查用户是否有指定角色
* @param role 角色编码或角色编码列表
* @returns Promise<boolean> 是否有指定角色
*/
hasRole(role: string | string[]): Promise<boolean>;
/**
* 检查用户是否有所有指定角色
* @param roles 角色编码列表
* @returns Promise<boolean> 是否有所有指定角色
*/
hasAllRoles(roles: string[]): Promise<boolean>;
/**
* 检查用户是否有指定权限
* @param permission 权限标识或权限标识列表
* @returns Promise<boolean> 是否有指定权限
*/
hasPermission(permission: string | string[]): Promise<boolean>;
/**
* 检查用户是否有所有指定权限
* @param permissions 权限标识列表
* @returns Promise<boolean> 是否有所有指定权限
*/
hasAllPermissions(permissions: string[]): Promise<boolean>;
/**
* 检查用户是否已认证
* @returns boolean 是否已认证
*/
isAuthenticated(): boolean;
/**
* 事件监听
* @param event 事件类型
* @param callback 回调函数
*/
on(event: EventType, callback: Function): void;
/**
* 移除事件监听
* @param event 事件类型
* @param callback 回调函数
*/
off(event: EventType, callback: Function): void;
/**
* 触发事件
* @param event 事件类型
* @param data 事件数据
*/
private emit;
/**
* 检查当前URL是否为授权回调
* @returns boolean 是否为授权回调
*/
isCallback(): boolean;
}
//# sourceMappingURL=auth.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/core/auth.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAC,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAC,MAAM,UAAU,CAAC;AAGpE,OAAO,EAAC,OAAO,EAAC,MAAM,kBAAkB,CAAC;AAGzC;;GAEG;AACH,qBAAa,IAAI;IACf,OAAO,CAAC,MAAM,CAA0B;IACxC,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,aAAa,CAInB;IACF,OAAO,CAAC,aAAa,CAAyB;IAE9C;;;OAGG;gBACS,OAAO,EAAE,OAAO;IAQ5B;;;OAGG;IACH,IAAI,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI;IAM7B,QAAQ,IAAG,MAAM,GAAG,IAAI;IAIxB;;;OAGG;IACG,KAAK,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAchD;;OAEG;IACG,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAe7B;;;OAGG;IACG,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAsC/B,SAAS,IAAI,OAAO,CAAC,UAAU,CAAC;IAYtC;;;OAGG;IACF,WAAW,IAAI,QAAQ;IAOxB;;;;OAIG;IACG,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC;IAiBxD;;;;OAIG;IACG,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC;IAWpD;;;;OAIG;IACG,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC;IAiBpE;;;;OAIG;IACG,iBAAiB,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC;IAYhE;;;OAGG;IACH,eAAe,IAAI,OAAO;IAK1B;;;;OAIG;IACH,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI;IAI9C;;;;OAIG;IACH,GAAG,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI;IAI/C;;;;OAIG;IACH,OAAO,CAAC,IAAI;IAUZ;;;OAGG;IACH,UAAU,IAAI,OAAO;CAGtB"}

View File

@@ -0,0 +1,241 @@
/**
* 认证核心逻辑
* 实现OAuth2授权码模式的完整流程
*/
import { TokenManager } from './token';
import { HttpClient } from './http';
import { buildQueryParams, isCallbackUrl, parseQueryParams } from '../utils/url';
/**
* 认证核心类
*/
export class Auth {
/**
* 构造函数
* @param storage 存储实例
*/
constructor(storage) {
this.config = null;
this.eventHandlers = {
login: [],
logout: [],
tokenExpired: []
};
this.userInfoCache = null;
this.storage = storage;
// 先创建HttpClient初始时tokenManager为undefined
this.httpClient = new HttpClient(() => this.tokenManager.getToken() || null);
// 然后创建TokenManager
this.tokenManager = new TokenManager(storage);
}
/**
* 初始化SDK配置
* @param config SDK配置选项
*/
init(config) {
this.config = config;
// 设置租户ID到HTTP客户端
this.httpClient.setTenantId(config.tenantId);
}
getToken() {
return this.tokenManager.getToken();
}
/**
* 触发登录流程
* @param redirectUri 可选的重定向URL覆盖初始化时的配置
*/
async login(redirectUri) {
if (!this.config) {
throw new Error('SDK not initialized');
}
const registrationId = this.config.registrationId || 'idp';
const basepath = this.config.basepath || '';
const path = `${basepath}/oauth2/authorization/${registrationId}`;
const tokenResponse = await this.httpClient.get(path, { needAuth: false });
const redirect = tokenResponse.data.redirect_url;
const params = parseQueryParams(redirect);
this.storage.set(params.state, window.location.href);
window.location.href = redirect;
}
/**
* 退出登录
*/
async logout() {
if (!this.config) {
throw new Error('SDK not initialized');
}
// 清除本地存储的Token和用户信息
this.tokenManager.clearToken();
this.userInfoCache = null;
this.storage.remove('userInfo');
const basepath = this.config.basepath || '';
await this.httpClient.post(`${basepath}/logout`, null, { needAuth: true });
// 触发退出事件
this.emit('logout');
window.location.href = this.config.idpLogoutUrl + '?redirect=' + this.config.homePage;
}
/**
* 处理授权回调
* @returns Promise<UserInfo> 用户信息
*/
async handleCallback() {
if (!this.config) {
throw new Error('SDK not initialized');
}
const params = parseQueryParams();
// 检查是否有错误
if (params.error) {
throw new Error(`Authorization error: ${params.error} - ${params.error_description || ''}`);
}
// 检查是否有授权码
if (!params.code) {
throw new Error('Authorization code not found');
}
const registrationId = this.config.registrationId || 'idp';
const basepath = this.config.basepath || '';
const callback = `${basepath}/login/oauth2/code/${registrationId}${buildQueryParams(params)}`;
const tokenResponse = await this.httpClient.get(callback, {
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
needAuth: false
});
// 触发登录事件
this.emit('login');
this.storage.set('userInfo', tokenResponse.data.data);
this.tokenManager.saveToken(tokenResponse.headers['authorization'] || tokenResponse.headers['Authorization']);
let url = this.config.homePage;
if (params.state) {
url = this.storage.get(params.state) || url;
}
window.location.href = url;
}
async getRoutes() {
if (!this.config) {
throw new Error('SDK not initialized');
}
const basepath = this.config.basepath || '';
const tokenResponse = await this.httpClient.get(`${basepath}/idp/routes`, { needAuth: true });
if (tokenResponse.status === 401) {
await this.logout();
}
return tokenResponse.data.data;
}
/**
* 获取用户信息
* @returns UserInfo 用户信息
*/
getUserInfo() {
return this.storage.get("userInfo");
}
/**
* 检查用户是否有指定角色
* @param role 角色编码或角色编码列表
* @returns Promise<boolean> 是否有指定角色
*/
async hasRole(role) {
if (!this.isAuthenticated()) {
return false;
}
const userInfo = this.storage.get("userInfo");
const roleCodes = userInfo.roles || [];
if (Array.isArray(role)) {
// 检查是否有任一角色
return role.some(r => roleCodes.includes(r));
}
// 检查是否有单个角色
return roleCodes.includes(role);
}
/**
* 检查用户是否有所有指定角色
* @param roles 角色编码列表
* @returns Promise<boolean> 是否有所有指定角色
*/
async hasAllRoles(roles) {
if (!this.isAuthenticated()) {
return false;
}
const userInfo = this.storage.get("userInfo");
const roleCodes = userInfo.roles || [];
// 检查是否有所有角色
return roles.every(r => roleCodes.includes(r));
}
/**
* 检查用户是否有指定权限
* @param permission 权限标识或权限标识列表
* @returns Promise<boolean> 是否有指定权限
*/
async hasPermission(permission) {
if (!this.isAuthenticated()) {
return false;
}
const userInfo = this.storage.get("userInfo");
const permissions = userInfo.permissions || [];
if (Array.isArray(permission)) {
// 检查是否有任一权限
return permission.some(p => permissions.includes(p));
}
// 检查是否有单个权限
return permissions.includes(permission);
}
/**
* 检查用户是否有所有指定权限
* @param permissions 权限标识列表
* @returns Promise<boolean> 是否有所有指定权限
*/
async hasAllPermissions(permissions) {
if (!this.isAuthenticated()) {
return false;
}
const userInfo = this.storage.get("userInfo");
const userPermissions = userInfo.permissions || [];
// 检查是否有所有权限
return permissions.every(p => userPermissions.includes(p));
}
/**
* 检查用户是否已认证
* @returns boolean 是否已认证
*/
isAuthenticated() {
// 检查Token是否存在且未过期
return !!this.tokenManager.getToken();
}
/**
* 事件监听
* @param event 事件类型
* @param callback 回调函数
*/
on(event, callback) {
this.eventHandlers[event].push(callback);
}
/**
* 移除事件监听
* @param event 事件类型
* @param callback 回调函数
*/
off(event, callback) {
this.eventHandlers[event] = this.eventHandlers[event].filter(handler => handler !== callback);
}
/**
* 触发事件
* @param event 事件类型
* @param data 事件数据
*/
emit(event, data) {
this.eventHandlers[event].forEach(handler => {
try {
handler(data);
}
catch (error) {
console.error(`Error in ${event} event handler:`, error);
}
});
}
/**
* 检查当前URL是否为授权回调
* @returns boolean 是否为授权回调
*/
isCallback() {
return isCallbackUrl();
}
}
//# sourceMappingURL=auth.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,155 @@
/**
* HTTP客户端
* 用于与后端API进行通信
*/
/**
* HTTP请求方法类型
*/
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
/**
* HTTP请求选项
*/
export interface HttpRequestOptions {
/** 请求方法 */
method: HttpMethod;
/** 请求URL */
url: string;
/** 请求头 */
headers?: Record<string, string>;
/** 请求体 */
body?: any;
/** 是否需要认证 */
needAuth?: boolean;
}
/**
* HTTP响应类型
*/
export interface HttpResponse<T = any> {
/** 状态码 */
status: number;
/** 状态文本 */
statusText: string;
/** 响应体 */
data: T;
/** 响应头 */
headers: Record<string, string>;
}
/**
* HTTP错误类型
*/
export declare class HttpError extends Error {
/** 状态码 */
status: number;
/** 状态文本 */
statusText: string;
/** 错误数据 */
data: any;
/**
* 构造函数
* @param message 错误信息
* @param status 状态码
* @param statusText 状态文本
* @param data 错误数据
*/
constructor(message: string, status: number, statusText: string, data: any);
}
/**
* HTTP客户端类
*/
export declare class HttpClient {
private tokenGetter?;
private tenantId?;
/**
* 构造函数
* @param logout
* @param tokenGetter Token获取函数
*/
constructor(tokenGetter?: () => string | null);
/**
* 设置Token获取函数
* @param tokenGetter Token获取函数
*/
setTokenGetter(tokenGetter: () => string | null): void;
/**
* 设置租户ID
* @param tenantId 租户ID
*/
setTenantId(tenantId?: string): void;
/**
* 发送HTTP请求
* @param options 请求选项
* @returns Promise<HttpResponse<T>> 响应结果
*/
request<T = any>(options: HttpRequestOptions): Promise<HttpResponse<T>>;
/**
* 处理响应数据
* @param response 响应对象
* @param responseData 响应数据
* @returns HttpResponse<T> 处理后的响应
*/
private handleResponse;
/**
* 检查是否为业务响应结构
* @param responseData 响应数据
* @returns boolean 是否为业务响应结构
*/
private isBusinessResponse;
/**
* 获取错误信息
* @param responseData 响应数据
* @returns string 错误信息
*/
private getErrorMessage;
/**
* GET请求
* @param url 请求URL
* @param options 请求选项
* @returns Promise<HttpResponse<T>> 响应结果
*/
get<T = any>(url: string, options?: Omit<HttpRequestOptions, 'method' | 'url'>): Promise<HttpResponse<T>>;
/**
* POST请求
* @param url 请求URL
* @param body 请求体
* @param options 请求选项
* @returns Promise<HttpResponse<T>> 响应结果
*/
post<T = any>(url: string, body?: any, options?: Omit<HttpRequestOptions, 'method' | 'url' | 'body'>): Promise<HttpResponse<T>>;
/**
* PUT请求
* @param url 请求URL
* @param body 请求体
* @param options 请求选项
* @returns Promise<HttpResponse<T>> 响应结果
*/
put<T = any>(url: string, body?: any, options?: Omit<HttpRequestOptions, 'method' | 'url' | 'body'>): Promise<HttpResponse<T>>;
/**
* DELETE请求
* @param url 请求URL
* @param options 请求选项
* @returns Promise<HttpResponse<T>> 响应结果
*/
delete<T = any>(url: string, options?: Omit<HttpRequestOptions, 'method' | 'url'>): Promise<HttpResponse<T>>;
/**
* PATCH请求
* @param url 请求URL
* @param body 请求体
* @param options 请求选项
* @returns Promise<HttpResponse<T>> 响应结果
*/
patch<T = any>(url: string, body?: any, options?: Omit<HttpRequestOptions, 'method' | 'url' | 'body'>): Promise<HttpResponse<T>>;
/**
* 解析响应体
* @param response 响应对象
* @returns Promise<any> 解析后的响应体
*/
private parseResponse;
/**
* 解析响应头
* @param headers 响应头对象
* @returns Record<string, string> 解析后的响应头
*/
private parseHeaders;
}
export {};
//# sourceMappingURL=http.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/core/http.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,274 @@
/**
* HTTP客户端
* 用于与后端API进行通信
*/
/**
* HTTP错误类型
*/
export class HttpError extends Error {
/**
* 构造函数
* @param message 错误信息
* @param status 状态码
* @param statusText 状态文本
* @param data 错误数据
*/
constructor(message, status, statusText, data) {
super(message);
this.name = 'HttpError';
this.status = status;
this.statusText = statusText;
this.data = data;
}
}
/**
* HTTP客户端类
*/
export class HttpClient {
/**
* 构造函数
* @param logout
* @param tokenGetter Token获取函数
*/
constructor(tokenGetter) {
this.tokenGetter = tokenGetter;
}
/**
* 设置Token获取函数
* @param tokenGetter Token获取函数
*/
setTokenGetter(tokenGetter) {
this.tokenGetter = tokenGetter;
}
/**
* 设置租户ID
* @param tenantId 租户ID
*/
setTenantId(tenantId) {
this.tenantId = tenantId;
}
/**
* 发送HTTP请求
* @param options 请求选项
* @returns Promise<HttpResponse<T>> 响应结果
*/
async request(options) {
const { method, url, headers = {}, body, needAuth = true } = options;
// 构建请求头
const requestHeaders = {
'Content-Type': 'application/json',
...headers
};
// 添加认证头
const addAuthHeader = () => {
if (needAuth && this.tokenGetter) {
const token = this.tokenGetter();
if (token) {
requestHeaders.Authorization = `${token}`;
}
}
};
// 添加租户ID头
if (this.tenantId) {
requestHeaders['tenant-id'] = this.tenantId;
}
addAuthHeader();
// 构建请求配置
const fetchOptions = {
method,
headers: requestHeaders,
credentials: 'include' // 包含cookie
};
// 添加请求体
if (body && (method === 'POST' || method === 'PUT' || method === 'PATCH')) {
fetchOptions.body = typeof body === 'string' ? body : JSON.stringify(body);
}
try {
// 发送请求
const response = await fetch(url, fetchOptions);
const responseData = await this.parseResponse(response);
// 检查响应状态
if (!response.ok) {
// 如果是401错误尝试刷新Token并重试
if (response.status === 401) {
return {
status: response.status,
statusText: response.statusText,
data: '',
headers: this.parseHeaders(response.headers)
};
}
// 其他错误,直接抛出
const errorMsg = this.getErrorMessage(responseData);
throw new HttpError(errorMsg, response.status, response.statusText, responseData);
}
// 处理成功响应的业务逻辑
return this.handleResponse(response, responseData);
}
catch (error) {
if (error instanceof HttpError) {
throw error;
}
// 网络错误或其他错误
throw new HttpError(error instanceof Error ? error.message : 'Network Error', 0, 'Network Error', null);
}
}
/**
* 处理响应数据
* @param response 响应对象
* @param responseData 响应数据
* @returns HttpResponse<T> 处理后的响应
*/
handleResponse(response, responseData) {
// 检查是否为业务响应结构
if (this.isBusinessResponse(responseData)) {
// 业务响应结构:{ code, msg, data }
const { code, msg, data } = responseData;
// 检查业务状态码
if (code !== 0 && code !== 200 && code !== '0' && code !== '200') {
// 业务错误抛出HttpError
throw new HttpError(msg || `Business Error: ${code}`, response.status, response.statusText, responseData);
}
// 业务成功返回data字段作为实际数据
return {
status: response.status,
statusText: response.statusText,
data: data,
headers: this.parseHeaders(response.headers)
};
}
// 非业务响应结构,直接返回原始数据
return {
status: response.status,
statusText: response.statusText,
data: responseData,
headers: this.parseHeaders(response.headers)
};
}
/**
* 检查是否为业务响应结构
* @param responseData 响应数据
* @returns boolean 是否为业务响应结构
*/
isBusinessResponse(responseData) {
return typeof responseData === 'object' &&
responseData !== null &&
('code' in responseData) &&
('msg' in responseData) &&
('data' in responseData);
}
/**
* 获取错误信息
* @param responseData 响应数据
* @returns string 错误信息
*/
getErrorMessage(responseData) {
// 如果是业务响应结构
if (this.isBusinessResponse(responseData)) {
return responseData.msg || `Business Error: ${responseData.code}`;
}
// 其他错误结构
return responseData.message || responseData.error || `HTTP Error`;
}
/**
* GET请求
* @param url 请求URL
* @param options 请求选项
* @returns Promise<HttpResponse<T>> 响应结果
*/
async get(url, options) {
return this.request({
method: 'GET',
url,
...options
});
}
/**
* POST请求
* @param url 请求URL
* @param body 请求体
* @param options 请求选项
* @returns Promise<HttpResponse<T>> 响应结果
*/
async post(url, body, options) {
return this.request({
method: 'POST',
url,
body,
...options
});
}
/**
* PUT请求
* @param url 请求URL
* @param body 请求体
* @param options 请求选项
* @returns Promise<HttpResponse<T>> 响应结果
*/
async put(url, body, options) {
return this.request({
method: 'PUT',
url,
body,
...options
});
}
/**
* DELETE请求
* @param url 请求URL
* @param options 请求选项
* @returns Promise<HttpResponse<T>> 响应结果
*/
async delete(url, options) {
return this.request({
method: 'DELETE',
url,
...options
});
}
/**
* PATCH请求
* @param url 请求URL
* @param body 请求体
* @param options 请求选项
* @returns Promise<HttpResponse<T>> 响应结果
*/
async patch(url, body, options) {
return this.request({
method: 'PATCH',
url,
body,
...options
});
}
/**
* 解析响应体
* @param response 响应对象
* @returns Promise<any> 解析后的响应体
*/
async parseResponse(response) {
const contentType = response.headers.get('content-type') || '';
if (contentType.includes('application/json')) {
return response.json();
}
else if (contentType.includes('text/')) {
return response.text();
}
else {
return response.blob();
}
}
/**
* 解析响应头
* @param headers 响应头对象
* @returns Record<string, string> 解析后的响应头
*/
parseHeaders(headers) {
const result = {};
headers.forEach((value, key) => {
result[key] = value;
});
return result;
}
}
//# sourceMappingURL=http.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,32 @@
/**
* Token管理模块
* 负责Token的存储、获取、刷新和过期处理
*/
import { Storage } from '../utils/storage';
/**
* Token管理类
*/
export declare class TokenManager {
private storage;
/**
* 构造函数
* @param storage 存储实例
* @param httpClient HTTP客户端实例
*/
constructor(storage: Storage);
/**
* 存储Token信息
* @param tokenInfo Token信息
*/
saveToken(tokenInfo: string): void;
/**
* 获取Token信息
* @returns TokenInfo | null Token信息
*/
getToken(): string | null;
/**
* 清除Token信息
*/
clearToken(): void;
}
//# sourceMappingURL=token.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"token.d.ts","sourceRoot":"","sources":["../../src/core/token.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAE3C;;GAEG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,OAAO,CAAU;IAEzB;;;;OAIG;gBACS,OAAO,EAAE,OAAO;IAI5B;;;OAGG;IACH,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAIlC;;;OAGG;IACH,QAAQ,IAAI,MAAM,GAAG,IAAI;IAIzB;;OAEG;IACH,UAAU,IAAI,IAAI;CAGnB"}

View File

@@ -0,0 +1,38 @@
/**
* Token管理模块
* 负责Token的存储、获取、刷新和过期处理
*/
/**
* Token管理类
*/
export class TokenManager {
/**
* 构造函数
* @param storage 存储实例
* @param httpClient HTTP客户端实例
*/
constructor(storage) {
this.storage = storage;
}
/**
* 存储Token信息
* @param tokenInfo Token信息
*/
saveToken(tokenInfo) {
this.storage.set('token', tokenInfo);
}
/**
* 获取Token信息
* @returns TokenInfo | null Token信息
*/
getToken() {
return this.storage.get('token');
}
/**
* 清除Token信息
*/
clearToken() {
this.storage.remove('token');
}
}
//# sourceMappingURL=token.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"token.js","sourceRoot":"","sources":["../../src/core/token.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH;;GAEG;AACH,MAAM,OAAO,YAAY;IAGvB;;;;OAIG;IACH,YAAY,OAAgB;QAC1B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED;;;OAGG;IACH,SAAS,CAAC,SAAiB;QACzB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IACvC,CAAC;IAED;;;OAGG;IACH,QAAQ;QACN,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACnC,CAAC;IAED;;OAEG;IACH,UAAU;QACR,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC/B,CAAC;CACF"}