diff --git a/.env b/.env index 5bf9e95..a4fb8f9 100644 --- a/.env +++ b/.env @@ -1 +1,2 @@ -VITE_SV_HOST="http://localhost:3000" \ No newline at end of file +VITE_SV_HOST="http://localhost:3000" +VITE_JWT_TOKEN="phuocntbasdasasdasd" \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index d671642..eeb2682 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "@tailwindcss/vite": "^4.1.13", "antd": "^5.27.4", "axios": "^1.12.2", + "jose": "^6.1.0", "json-server": "^1.0.0-beta.3", "react": "^19.1.1", "react-dom": "^19.1.1", @@ -4157,6 +4158,15 @@ "jiti": "lib/jiti-cli.mjs" } }, + "node_modules/jose": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.1.0.tgz", + "integrity": "sha512-TTQJyoEoKcC1lscpVDCSsVgYzUDg/0Bt3WE//WiTPK6uOCQC2KZS4MpugbMWt/zyjkopgZoXhZuCi00gLudfUA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", diff --git a/package.json b/package.json index b5aed0a..ff8cdfd 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "@tailwindcss/vite": "^4.1.13", "antd": "^5.27.4", "axios": "^1.12.2", + "jose": "^6.1.0", "json-server": "^1.0.0-beta.3", "react": "^19.1.1", "react-dom": "^19.1.1", diff --git a/src/apis/core/user.api.ts b/src/apis/core/user.api.ts index 69d9567..e2cb097 100644 --- a/src/apis/core/user.api.ts +++ b/src/apis/core/user.api.ts @@ -2,6 +2,7 @@ import axios from "axios" import type { User } from "../../types/user.type" import { message } from "antd" import { ApiUtil } from "../../utils/api.util" +import * as jose from 'jose' export interface UserSignInDTO { emailOrUserName: string @@ -16,10 +17,7 @@ export interface UserFindAllDTO { } export const UserApi = { - signIn: async (data: UserSignInDTO): Promise<{ - message: string - data: any - }> => { + signIn: async (data: UserSignInDTO) => { let userData = await axios.get(`${import.meta.env.VITE_SV_HOST}/users?email=${data.emailOrUserName}`) if (userData.data.length == 0) { userData = await axios.get(`${import.meta.env.VITE_SV_HOST}/users?userName=${data.emailOrUserName}`) @@ -36,10 +34,7 @@ export const UserApi = { data: null }) } - return { - message: "Đăng nhập thành công!", - data: userData.data[0] as User - } + return createToken(userData.data[0].id) } }, signUp: async (data: User) => { @@ -106,5 +101,59 @@ export const UserApi = { findAll: async (query?: UserFindAllDTO) => { let result = await axios.get(`${import.meta.env.VITE_SV_HOST}/users?` + ApiUtil.writeQuery(query)) return result.data + }, + me: async (token: string) => { + let tokenData = await decodeToken(token) + + if (!tokenData) { + throw ({ + message: "Token không chính xác!" + }) + } + + let { userId } = tokenData; + + let getUserByIdRes = await axios.get(`${import.meta.env.VITE_SV_HOST}/users/${userId}`) + + if (!getUserByIdRes.data) { + throw ({ + message: "Lỗi lấy dữ liệu" + }) + } + + let data = await new Promise((resolve) => { + setTimeout(() => { + resolve(getUserByIdRes.data) + }, 1000) + }) + + return data + } +} + + +async function createToken(userId: string) { + const secret = new TextEncoder().encode(import.meta.env.VITE_JWT_TOKEN); + + const token = await new jose.SignJWT({ userId }) + .setProtectedHeader({ alg: 'HS256' }) + .setIssuedAt() + .setExpirationTime('2h') + .sign(secret); + return token +} + +async function decodeToken(token: string) { + try { + const secret = new TextEncoder().encode(import.meta.env.VITE_JWT_TOKEN); + + const { payload } = await jose.jwtVerify(token, secret, { + algorithms: ['HS256'], + }); + + return payload; + } catch (error) { + console.error('Token không hợp lệ hoặc đã hết hạn:', error); + return null; } } \ No newline at end of file diff --git a/src/pages/admin/auth/ProtectedAdmin.tsx b/src/pages/admin/auth/ProtectedAdmin.tsx index d4543ff..6d0d254 100644 --- a/src/pages/admin/auth/ProtectedAdmin.tsx +++ b/src/pages/admin/auth/ProtectedAdmin.tsx @@ -14,7 +14,7 @@ export default function ProtectedAdmin( return store.user }) - + /* Đã đăng nhập và là master hoặc admin */ if (userStore.data?.role == UserRole.MASTER || userStore.data?.role == UserRole.ADMIN) { return ( <> @@ -23,7 +23,8 @@ export default function ProtectedAdmin( ) } - if (!userStore.data?.role) { + /* chưa đăng nhập */ + if (!userStore.data && !userStore.loading) { return (