좋습니다! 빌드 파일을 직접 분석해서 axios 인스턴스를 찾아보겠습니다.
```javascript
// Snippet: Analyze Build File and Inject Token
(async function analyzeBuildAndInject() {
const accessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...';
const refreshToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...';
console.log('🔧 빌드 파일 분석 시작...\n');
// 1. Storage 설정
localStorage.setItem('accessToken', accessToken);
localStorage.setItem('refreshToken', refreshToken);
sessionStorage.setItem('accessToken', accessToken);
console.log('✅ Storage 설정 완료\n');
// 2. 빌드 파일에서 axios 모듈 ID 찾기
console.log('🔍 빌드 파일 분석 중...');
try {
const response = await fetch('/static/js/main.230ab913.js');
const buildCode = await response.text();
// axios 관련 패턴 검색
const patterns = [
/\.defaults\.headers\.common/g,
/Authorization.*Bearer/g,
/\.reissue\(/g,
/accessToken.*refreshToken/g
];
console.log('📊 빌드 파일 분석 결과:');
patterns.forEach((pattern, i) => {
const matches = buildCode.match(pattern);
console.log(` 패턴 ${i + 1}: ${matches ? matches.length + '개 발견' : '없음'}`);
});
} catch (e) {
console.log('⚠️ 빌드 파일 직접 분석 실패:', e.message);
}
// 3. Webpack 청크 캐시 직접 접근
console.log('\n🎯 Webpack 청크 캐시 탐색...');
// webpack의 모듈 캐시는 보통 이런 변수명을 사용
const possibleWebpackVars = [
'__webpack_require__',
'webpackChunk',
'webpackJsonp',
'__webpack_modules__'
];
let webpackCache = null;
for (let varName of possibleWebpackVars) {
if (window[varName]) {
console.log(`✅ ${varName} 발견`);
webpackCache = window[varName];
break;
}
}
// window에서 webpack 청크 배열 찾기
for (let key in window) {
try {
if (Array.isArray(window[key]) && window[key].length > 0) {
const first = window[key][0];
if (Array.isArray(first) && typeof first[1] === 'object') {
console.log(`✅ Webpack 청크 배열 발견: window.${key}`);
webpackCache = window[key];
break;
}
}
} catch (e) {}
}
// 4. 모든 전역 변수에서 axios 찾기 (더 깊게)
console.log('\n🔎 전역 변수 심층 탐색...');
let axiosInstances = [];
function deepSearch(obj, path = '', depth = 0, visited = new WeakSet()) {
if (depth > 5 || !obj || typeof obj !== 'object') return;
if (visited.has(obj)) return;
visited.add(obj);
try {
// axios 인스턴스 체크
if (obj.defaults?.headers?.common !== undefined) {
axiosInstances.push({ obj, path });
return;
}
// interceptors가 있으면 axios일 가능성 높음
if (obj.interceptors?.request || obj.interceptors?.response) {
axiosInstances.push({ obj, path });
return;
}
// create 메서드가 있으면 axios 생성자일 수 있음
if (typeof obj.create === 'function' && obj.defaults) {
axiosInstances.push({ obj, path });
return;
}
// 재귀 탐색
for (let key in obj) {
try {
if (key.length < 50) { // 너무 긴 키는 스킵
deepSearch(obj[key], path ? `${path}.${key}` : key, depth + 1, visited);
}
} catch (e) {}
}
} catch (e) {}
}
console.log(' window 객체 탐색 중...');
deepSearch(window);
console.log(`\n📦 발견된 axios 인스턴스: ${axiosInstances.length}개`);
// 5. 발견된 모든 axios에 토큰 설정
if (axiosInstances.length > 0) {
axiosInstances.forEach(({ obj, path }, index) => {
try {
if (obj.defaults?.headers?.common) {
obj.defaults.headers.common['Authorization'] = `Bearer ${accessToken}`;
obj.defaults.headers.common.authorization = `Bearer ${accessToken}`;
console.log(`✅ ${index + 1}. ${path || 'Unknown'} - 헤더 설정 완료`);
console.log(` 기존 Authorization:`, obj.defaults.headers.common.Authorization);
}
if (obj.defaults?.headers) {
obj.defaults.headers['Authorization'] = `Bearer ${accessToken}`;
}
} catch (e) {
console.warn(`⚠️ ${index + 1}. 설정 실패:`, e.message);
}
});
} else {
console.log('⚠️ axios 인스턴스를 찾지 못했습니다');
}
// 6. Object.getOwnPropertyNames로 숨겨진 속성 찾기
console.log('\n🔬 Object 속성 탐색...');
const allProps = Object.getOwnPropertyNames(window);
const suspiciousProps = allProps.filter(prop =>
prop.includes('axios') ||
prop.includes('api') ||
prop.includes('request') ||
prop.length === 1 || // 난독화된 단일 문자 변수
/^[a-z]$/.test(prop) // 소문자 한 글자
);
console.log('의심스러운 전역 변수:', suspiciousProps.slice(0, 20));
suspiciousProps.forEach(prop => {
try {
const obj = window[prop];
if (obj?.defaults?.headers?.common) {
obj.defaults.headers.common['Authorization'] = `Bearer ${accessToken}`;
console.log(`✅ window.${prop} - 토큰 설정 완료`);
}
} catch (e) {}
});
// 7. 네트워크 요청 인터셉트 (최후의 수단)
console.log('\n🎣 네트워크 인터셉터 설정...');
const originalFetch = window.fetch;
window.fetch = function(url, options = {}) {
// 헤더 강제 추가
if (!options.headers) {
options.headers = {};
}
if (typeof options.headers === 'object') {
if (!options.headers.Authorization && !options.headers.authorization) {
options.headers.Authorization = `Bearer ${accessToken}`;
console.log(`🔐 fetch 토큰 주입: ${url}`);
}
}
return originalFetch.call(this, url, options);
};
const XHR = XMLHttpRequest.prototype;
const originalOpen = XHR.open;
const originalSend = XHR.send;
XHR.open = function(method, url) {
this._url = url;
this._method = method;
return originalOpen.apply(this, arguments);
};
XHR.send = function() {
this.setRequestHeader('Authorization', `Bearer ${accessToken}`);
console.log(`🔐 XHR 토큰 주입: ${this._method} ${this._url}`);
return originalSend.apply(this, arguments);
};
console.log('✅ 네트워크 인터셉터 설정 완료');
// 8. 상태 요약
console.log('\n📊 === 최종 상태 ===');
console.log('✅ localStorage:', localStorage.getItem('accessToken') ? '설정됨' : '없음');
console.log('✅ axios 인스턴스:', axiosInstances.length + '개 발견');
console.log('✅ 네트워크 인터셉터:', '활성화');
console.log('📍 현재 경로:', window.location.pathname);
// 9. 대시보드로 이동 시도
console.log('\n🚀 대시보드로 이동 시도...');
// 방법 1: React Router history API
if (window.history) {
setTimeout(() => {
window.history.pushState({}, '', '/dashboard');
window.dispatchEvent(new PopStateEvent('popstate'));
console.log('✅ history.pushState 실행');
}, 1000);
}
// 방법 2: 페이지 이동
setTimeout(() => {
console.log('🔄 페이지 새로고침...');
window.location.href = '/dashboard';
}, 3000);
console.log('\n✨ 완료! 3초 후 자동 이동합니다.');
console.log('💡 이동하지 않으면 수동으로 /dashboard를 입력하세요');
})();
```
## 추가: 실시간 모니터링 스크립트
```javascript
// Snippet 2: Real-time Monitor
(function monitorRequests() {
console.log('📡 === 실시간 네트워크 모니터링 시작 ===\n');
const accessToken = localStorage.getItem('accessToken');
console.log('현재 토큰:', accessToken ? '있음 (' + accessToken.substring(0, 30) + '...)' : '없음');
// fetch 모니터링
const originalFetch = window.fetch;
window.fetch = function(...args) {
const [url, options] = args;
console.log('\n🌐 FETCH 요청:');
console.log(' URL:', url);
console.log(' Headers:', options?.headers);
console.log(' Authorization:', options?.headers?.Authorization || options?.headers?.authorization || '❌ 없음');
return originalFetch.apply(this, args)
.then(response => {
console.log(' 응답 상태:', response.status);
if (response.status === 401) {
console.error(' ❌ 401 Unauthorized - 토큰 문제!');
}
return response;
})
.catch(error => {
console.error(' ❌ 요청 실패:', error);
throw error;
});
};
// XHR 모니터링
const XHR = XMLHttpRequest.prototype;
const originalOpen = XHR.open;
const originalSend = XHR.send;
const originalSetRequestHeader = XHR.setRequestHeader;
XHR.open = function(method, url) {
this._url = url;
this._method = method;
this._headers = {};
return originalOpen.apply(this, arguments);
};
XHR.setRequestHeader = function(header, value) {
this._headers[header] = value;
return originalSetRequestHeader.apply(this, arguments);
};
XHR.send = function() {
console.log('\n🌐 XHR 요청:');
console.log(' Method:', this._method);
console.log(' URL:', this._url);
console.log(' Headers:', this._headers);
console.log(' Authorization:', this._headers.Authorization || '❌ 없음');
this.addEventListener('load', function() {
console.log(' 응답 상태:', this.status);
if (this.status === 401) {
console.error(' ❌ 401 Unauthorized - 토큰 문제!');
}
});
return originalSend.apply(this, arguments);
};
console.log('✅ 모니터링 활성화');
console.log('💡 이제 로그인을 시도하거나 페이지를 새로고침하세요');
})();
```
## 실행 순서
1. **Snippet 2 실행** (모니터링 먼저)
2. 페이지 새로고침하거나 /dashboard 이동
3. Console에서 어떤 요청이 실패하는지 확인
4. **Snippet 1 실행** (토큰 주입)
5. 결과 확인
**Console에 나오는 로그를 공유해주시면 더 정확한 해결책을 드릴 수 있습니다!**
특히 이런 정보가 중요합니다:
- "발견된 axios 인스턴스: X개" ← 이게 0개인지?
- 401 에러가 어떤 API에서 발생하는지?
- Authorization 헤더가 실제로 추가되는지?
카테고리 없음