以下是一个完整的原生 JavaScript AJAX 实现,演示如何将 Token 添加到 Authorization 头部的示例:
html复制代码
AJAX Token 示例
AJAX Token 示例
javascript复制代码
// ajaxWithAuth.js
const API_BASE_URL = 'https://api.example.com';
export default {
/**
* 发送带认证的 AJAX 请求
* @param {string} method - HTTP 方法 (GET, POST, PUT, DELETE)
* @param {string} endpoint - API 端点
* @param {object} [data] - 请求数据
* @returns {Promise} 返回 Promise
*/
request(method, endpoint, data = null) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
const url = `${API_BASE_URL}${endpoint}`;
const token = this.getAuthToken();
xhr.open(method, url, true);
// 设置头部
xhr.setRequestHeader('Authorization', `Bearer ${token}`);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.onload = function() {
if (xhr.status >= 200 && xhr.status < 300) {
try {
resolve(JSON.parse(xhr.responseText));
} catch (e) {
resolve(xhr.responseText);
}
} else {
reject({
status: xhr.status,
statusText: xhr.statusText
});
}
};
xhr.onerror = function() {
reject({
status: 0,
statusText: '网络错误'
});
};
xhr.send(data ? JSON.stringify(data) : null);
});
},
// 获取认证 Token
getAuthToken() {
// 实际实现从安全存储获取
return localStorage.getItem('authToken') ||
sessionStorage.getItem('authToken') ||
'';
},
// 封装常用方法
get(endpoint) {
return this.request('GET', endpoint);
},
post(endpoint, data) {
return this.request('POST', endpoint, data);
},
put(endpoint, data) {
return this.request('PUT', endpoint, data);
},
delete(endpoint) {
return this.request('DELETE', endpoint);
}
};
html复制代码
javascript复制代码
// 安全增强版
const ajaxSecure = {
// ... 基础代码同上 ...
request(method, endpoint, data = null) {
return new Promise((resolve, reject) => {
// ... 同上 ...
// 添加安全头部
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.setRequestHeader('X-CSRF-Protection', this.getCSRFToken());
// 添加请求时间戳防止缓存
const timestamp = new Date().getTime();
const finalUrl = endpoint.includes('?')
? `${url}&_t=${timestamp}`
: `${url}?_t=${timestamp}`;
xhr.open(method, finalUrl, true);
// ... 其余代码 ...
});
},
// 获取 CSRF Token
getCSRFToken() {
const cookieValue = document.cookie
.split('; ')
.find(row => row.startsWith('XSRF-TOKEN='))
?.split('=')[1];
return cookieValue || '';
},
// 自动处理 Token 刷新
async requestWithRefresh(method, endpoint, data) {
try {
return await this.request(method, endpoint, data);
} catch (error) {
if (error.status === 401 && !endpoint.includes('/auth/refresh')) {
await this.refreshToken();
return this.request(method, endpoint, data);
}
throw error;
}
},
// 刷新 Token
async refreshToken() {
const refreshToken = localStorage.getItem('refreshToken');
if (!refreshToken) throw new Error('无可用刷新令牌');
try {
const response = await this.request('POST', '/auth/refresh', {
refreshToken
});
this.saveTokens(response);
return true;
} catch (error) {
this.clearTokens();
throw error;
}
},
// 安全保存 Token
saveTokens(authData) {
// 使用安全存储方式
localStorage.setItem('authToken', authData.accessToken);
// 刷新令牌使用 HTTP Only Cookie 存储(由服务器设置)
document.cookie = `refreshToken=${authData.refreshToken}; Secure; HttpOnly; SameSite=Strict; path=/`;
},
// 清除 Token
clearTokens() {
localStorage.removeItem('authToken');
document.cookie = 'refreshToken=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;';
}
};
mermaid复制代码导出svg
Token 存储安全
javascript复制代码
// 使用加密存储(浏览器扩展)
async function secureSetItem(key, value) {
if (window.crypto && window.crypto.subtle) {
const encrypted = await encryptData(value);
localStorage.setItem(key, encrypted);
} else {
// 回退方案:会话存储 + Base64
sessionStorage.setItem(key, btoa(unescape(encodeURIComponent(value))));
}
}
添加请求签名
javascript复制代码
function signRequest(method, url, body) {
const timestamp = Date.now();
const nonce = Math.random().toString(36).substring(2, 12);
const dataToSign = `${method}|${url}|${timestamp}|${nonce}|${body ? JSON.stringify(body) : ''}`;
const hmac = CryptoJS.HmacSHA256(dataToSign, SECRET_KEY);
return {
'X-Signature': hmac.toString(CryptoJS.enc.Base64),
'X-Timestamp': timestamp,
'X-Nonce': nonce
};
}
双重 Token 验证
javascript复制代码
function setAuthHeaders(xhr) {
const token = getAuthToken();
xhr.setRequestHeader('Authorization', `Bearer ${token}`);
// 添加设备指纹验证
const deviceId = generateDeviceId();
xhr.setRequestHeader('X-Device-ID', deviceId);
}
function generateDeviceId() {
// 基于浏览器指纹生成唯一ID
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
ctx.fillText('ID', 10, 10);
return canvas.toDataURL().hashCode();
}
这个实现展示了如何在原生 AJAX 请求中添加认证 Token,并提供了企业级的安全增强措施。实际项目中,建议结合具体框架使用更高级的 HTTP 客户端(如 Axios),但理解底层原理对于处理特殊场景非常重要。