ปรับ frontend

This commit is contained in:
admin
2025-10-01 13:53:46 +07:00
parent 5cac3bdabf
commit 2215633fb9
7 changed files with 269 additions and 213 deletions

View File

@@ -0,0 +1,69 @@
//File: frontend/app/_auth/drivers/cookieDriver.js
const API = process.env.NEXT_PUBLIC_API_BASE;
let accessToken = null;
let refreshToken = null;
function load() {
if (typeof window === 'undefined') return;
accessToken = localStorage.getItem('access_token');
refreshToken = localStorage.getItem('refresh_token');
}
function save(a, r) {
if (typeof window === 'undefined') return;
if (a) { accessToken = a; localStorage.setItem('access_token', a); }
if (r) { refreshToken = r; localStorage.setItem('refresh_token', r); }
}
function clear() {
if (typeof window === 'undefined') return;
accessToken = null; refreshToken = null;
localStorage.removeItem('access_token'); localStorage.removeItem('refresh_token');
}
export default {
mode: 'bearer',
async login({ username, password }) {
const r = await fetch(`${API}/api/auth/login`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password })
});
if (!r.ok) throw new Error(`Login failed: ${r.status}`);
const j = await r.json();
if (!j?.access_token) throw new Error('No access_token');
save(j.access_token, j.refresh_token);
return true;
},
async me() {
load();
const headers = this.authHeaders();
const r = await fetch(`${API}/api/auth/me`, { headers });
if (r.status === 401 && await this.refresh()) {
const r2 = await fetch(`${API}/api/auth/me`, { headers: this.authHeaders() });
if (!r2.ok) return { ok: false };
return r2.json();
}
if (!r.ok) return { ok: false };
return r.json();
},
async refresh() {
load();
if (!refreshToken) return false;
const r = await fetch(`${API}/api/auth/refresh`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ refresh_token: refreshToken })
});
if (!r.ok) { clear(); return false; }
const j = await r.json();
if (!j?.access_token) return false;
save(j.access_token, j.refresh_token ?? refreshToken);
return true;
},
authHeaders(h = {}) {
load();
return accessToken ? { ...h, Authorization: `Bearer ${accessToken}` } : h;
},
credentials() { return 'omit'; },
async logout() { clear(); }
};

View File

@@ -0,0 +1,34 @@
//File: frontend/app/_auth/drivers/cookieDriver.js
const API = process.env.NEXT_PUBLIC_API_BASE;
export default {
mode: 'cookie',
async login({ username, password }) {
const r = await fetch(`${API}/api/auth/login`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include', // สำคัญสำหรับคุกกี้
body: JSON.stringify({ username, password })
});
if (!r.ok) throw new Error(`Login failed: ${r.status}`);
return true; // คุกกี้ถูกตั้งแล้วโดย backend
},
async me() {
const r = await fetch(`${API}/api/auth/me`, { credentials: 'include' });
if (!r.ok) return { ok: false };
return r.json();
},
async refresh() {
// ถ้า backend ออก access ใหม่ผ่าน refresh (ในคุกกี้) ก็เรียกได้
const r = await fetch(`${API}/api/auth/refresh`, {
method: 'POST',
credentials: 'include'
});
return r.ok;
},
authHeaders(h = {}) { return h; }, // คุกกี้ไม่ต้องใส่ Authorization
credentials() { return 'include'; },
async logout() {
await fetch(`${API}/api/auth/logout`, { method: 'POST', credentials: 'include' });
}
};