ฟังก์ชัน จดจำฉัน ด้วย JWT
This commit is contained in:
parent
f615e51c5c
commit
98fcaeba3f
@ -102,7 +102,7 @@ export default function LoginForm() {
|
|||||||
{/* Checkbox และ Link ลืมรหัสผ่าน */}
|
{/* Checkbox และ Link ลืมรหัสผ่าน */}
|
||||||
<div className='flex justify-between items-center text-sm mt-6'>
|
<div className='flex justify-between items-center text-sm mt-6'>
|
||||||
<label className="flex items-center space-x-2 text-gray-600">
|
<label className="flex items-center space-x-2 text-gray-600">
|
||||||
<input type="checkbox" className="checkbox checkbox-primary checkbox-sm" />
|
<input type="checkbox" className="checkbox checkbox-primary checkbox-sm" {...register('remember_me')}/>
|
||||||
<span>จดจำฉัน</span>
|
<span>จดจำฉัน</span>
|
||||||
</label>
|
</label>
|
||||||
<Link to="/forgot-password">
|
<Link to="/forgot-password">
|
||||||
|
|||||||
@ -15,8 +15,18 @@ const API_BASE_URL = import.meta.env.VITE_API_BASE_URL;
|
|||||||
* แปลง Object ให้เป็นฟอร์มข้อมูล (x-www-form-urlencoded)
|
* แปลง Object ให้เป็นฟอร์มข้อมูล (x-www-form-urlencoded)
|
||||||
*/
|
*/
|
||||||
const toFormUrlEncoded = (data) => {
|
const toFormUrlEncoded = (data) => {
|
||||||
|
// วนซ้ำ key และ encode
|
||||||
return Object.keys(data)
|
return Object.keys(data)
|
||||||
.map(key => encodeURIComponent(key) + '=' + encodeURIComponent(data[key]))
|
.map(key => {
|
||||||
|
let value = data[key];
|
||||||
|
// รับค่า remember_me (boolean) มาแปลงเป็น String 'true'
|
||||||
|
if (value === true) {
|
||||||
|
value = 'true';
|
||||||
|
} else if (value === false) {
|
||||||
|
value = 'false'; // หรือจะส่งเฉพาะเมื่อเป็น true ก็ได้
|
||||||
|
}
|
||||||
|
return encodeURIComponent(key) + '=' + encodeURIComponent(value);
|
||||||
|
})
|
||||||
.join('&');
|
.join('&');
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -121,6 +131,8 @@ export const useLoginMutation = () => {
|
|||||||
|
|
||||||
// 1. จัดการ Token และ User Data
|
// 1. จัดการ Token และ User Data
|
||||||
localStorage.setItem('token', data.access_token);
|
localStorage.setItem('token', data.access_token);
|
||||||
|
// บันทึก Refresh Token แยกต่างหาก
|
||||||
|
localStorage.setItem('refresh_token', data.refresh_token);
|
||||||
localStorage.setItem('user', JSON.stringify(data.user));
|
localStorage.setItem('user', JSON.stringify(data.user));
|
||||||
localStorage.setItem('role', data.role); // บันทึก Role ที่ถูกต้อง
|
localStorage.setItem('role', data.role); // บันทึก Role ที่ถูกต้อง
|
||||||
|
|
||||||
@ -251,3 +263,21 @@ export const useConfirmPasswordReset = () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ฟังก์ชันสำหรับเรียก API เพื่อต่ออายุ Access Token ด้วย Refresh Token
|
||||||
|
*/
|
||||||
|
export const refreshAccessToken = async () => {
|
||||||
|
const refresh = localStorage.getItem('refresh_token'); // เก็บ Refresh Token แยกต่างหาก
|
||||||
|
|
||||||
|
if (!refresh) {
|
||||||
|
throw new Error("Refresh token not found.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await axios.post(`${API_BASE_URL}/api/v1/auth/jwt/refresh/`, {
|
||||||
|
refresh: refresh,
|
||||||
|
});
|
||||||
|
|
||||||
|
// คืนค่า Access Token ใหม่
|
||||||
|
return response.data.access;
|
||||||
|
};
|
||||||
@ -1,6 +1,7 @@
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { getStore } from '../app/store';
|
import { getStore } from '../app/store';
|
||||||
import { logout } from '../features/auth/authSlice';
|
import { logout } from '../features/auth/authSlice';
|
||||||
|
import { refreshAccessToken } from './authApi';
|
||||||
|
|
||||||
// REGEX ตรวจจับตัวเลขที่ใหญ่เกิน 15 หลัก (ซึ่งเกินขีดจำกัดความปลอดภัยของ JS)
|
// REGEX ตรวจจับตัวเลขที่ใหญ่เกิน 15 หลัก (ซึ่งเกินขีดจำกัดความปลอดภัยของ JS)
|
||||||
const bigIntRegex = /"id":(\d{15,})/g;
|
const bigIntRegex = /"id":(\d{15,})/g;
|
||||||
@ -55,8 +56,37 @@ axiosClient.interceptors.request.use(
|
|||||||
|
|
||||||
axiosClient.interceptors.response.use(
|
axiosClient.interceptors.response.use(
|
||||||
(response) => response,
|
(response) => response,
|
||||||
(error) => {
|
async (error) => {
|
||||||
const status = error.response ? error.response.status : null;
|
const status = error.response ? error.response.status : null;
|
||||||
|
const originalRequest = error.config;
|
||||||
|
|
||||||
|
// ถ้าเป็น 401 และ Request นั้นยังไม่ถูกลอง Refresh
|
||||||
|
if (status === 401 && !originalRequest._retry) {
|
||||||
|
|
||||||
|
originalRequest._retry = true; // ตั้ง Flag ว่ากำลังจะลอง Refresh
|
||||||
|
|
||||||
|
const storeInstance = getStore();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 1. เรียกฟังก์ชัน Refresh Token
|
||||||
|
const newAccessToken = await refreshAccessToken();
|
||||||
|
|
||||||
|
// 2. บันทึก Access Token ใหม่
|
||||||
|
localStorage.setItem('token', newAccessToken);
|
||||||
|
|
||||||
|
// 3. อัปเดต Header ของ Request เดิม
|
||||||
|
originalRequest.headers.Authorization = `Bearer ${newAccessToken}`;
|
||||||
|
|
||||||
|
// 4. ลองเรียก Request เดิมซ้ำอีกครั้ง
|
||||||
|
return axiosClient(originalRequest);
|
||||||
|
|
||||||
|
} catch (refreshError) {
|
||||||
|
// หาก Refresh Token ล้มเหลว (หมดอายุ 30 วันแล้ว)
|
||||||
|
console.error("JWT Refresh Failed. Logging out.", refreshError);
|
||||||
|
storeInstance.dispatch(logout()); // บังคับ Logout
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ถ้าได้รับ 401 หรือ 403 (Token หมดอายุ/ไม่มีสิทธิ์)
|
// ถ้าได้รับ 401 หรือ 403 (Token หมดอายุ/ไม่มีสิทธิ์)
|
||||||
if (status === 401 || status === 403) {
|
if (status === 401 || status === 403) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user