- vừa được xem lúc

Phần 2: Authentication Trong Micro Frontend Với Nx Workspace - "Dễ Như Ăn Kẹo"

0 0 3

Người đăng: Huỳnh Trọng Thoại

Theo Viblo Asia

Chào mừng bạn trở lại với series "Micro Frontend Với Nx Workspace"! Sau phần 1 về setup cơ bản, hôm nay chúng ta sẽ cùng "ăn gà" với chủ đề Authentication - bài toán khiến nhiều dev "đau đầu" khi làm micro frontend.

I. "Bi kịch" của dev khi làm auth với Micro Frontend 😅

Bạn đã bao giờ gặp phải những tình huống "dở khóc dở cười" này chưa?

  • "Đăng nhập cả ngày không hết": User đăng nhập app A xong, qua app B lại phải đăng nhập tiếp. Cứ như đi làm mà phải trình thẻ 5 lần vậy!

  • "Token như ma": Biến mất sau mỗi lần refresh, để rồi user phải đăng nhập lại. Chắc token sợ bị hack nên tự động ẩn mình?

  • "Config như đàn gà con": Mỗi micro app một config auth y chang nhau. Sửa một chỗ phải sửa 10 chỗ, đúng kiểu "sửa lỗi này sinh lỗi kia"!

Đừng lo! Hôm nay mình sẽ cùng bạn "trị" mấy con bug khó ưa này một cách "ngon lành" nhất!

II. 3 Cách "đối phó" với Auth - Chọn cách nào đây? 🤔

Kiểu "Mạnh ai nấy chạy" (Anti-Pattern)

<Auth0Provider domain="..." clientId="..."> <App />
</Auth0Provider>

🔹 Ưu điểm:

  • Code nhanh như "mì ăn liền"
  • Không phụ thuộc vào ai cả

💥 Nhược điểm:

  • User phải đăng nhập nhiều lần (user chửi thề)
  • Token "biến mất" khi chuyển app
  • Sửa 1 chỗ = sửa 10 chỗ (đau đầu x3)

Kiểu "Chuyền điện thoại" (Event-based)

// Host app phát event
window.dispatchEvent(new CustomEvent('auth-update', { detail: { user, isAuthenticated }
})); // Host app
<Auth0Provider {...config}> <MicroAppLoader> <Dashboard auth={authProps} /> </MicroAppLoader>
</Auth0Provider> // Micro app nhận
window.addEventListener('auth-update', (e) => { updateAuthState(e.detail);
});

🔹 Ưu điểm:

  • Nhẹ như lông hồng
  • Linh hoạt với mọi framework

💥 Nhược điểm:

  • Khó debug khi có bug
  • Dễ thành "ma trận" events

Kiểu "Ông trùm lo hết" (Host Provider) - RECOMMENDED! 🎯

// Host app
<Auth0Provider {...config}> <MicroAppLoader> <Dashboard auth={authProps} /> </MicroAppLoader>
</Auth0Provider>

🔹 Ưu điểm:

  • Single Sign-On mượt như silk
  • Token refresh tập trung
  • Config 1 chỗ, dùng mọi nơi

💥 Nhược điểm:

  • Cần thiết kế kỹ từ đầu
  • Phụ thuộc vào host app

👉 Kết luận: Nếu muốn ngủ ngon, hãy chọn cách 3! 😴

III. "Chân kinh" triển khai với Auth0 + Nx 🚀

Bước 1: Setup Auth0 Trên Dashboard

  • Vào Auth0 Dashboard

  • Chọn SPA Application và React vì host app đang viết bằng nó. Lúc này bạn sẽ thấy màn hình sẽ như này Screenshot 2025-03-30 at 15.35.41.png

  • Tiếp tục chọn Continue đến khi bạn thấy màn hình này: Screenshot 2025-03-30 at 15.37.51.png

  • Nhấn vào nút Create Application để tạo ứng dụng mới hoặc vào mục Applications bên sidebar.

  • Cấu hình Applications/Settings

Allowed Callback URLs: - http://localhost:4200 Allowed Logout URLs: - http://localhost:4200 Allowed Web Origins: - http://localhost:4200 Advanced Settings: - Refresh Token Rotation: Enabled
  • Tạo API Audience (nếu cần gọi backend API):

    • Vào "Applications" → "APIs" → "Create API"

    • Đặt tên và identifier (ví dụ: https://api.your-app.com)

    • Chọn signing algorithm là RS256

  • Làm theo phần Quick Setup bạn sẽ có đc Auth Config. Lưu nó vào env file

NX_AUTH0_DOMAIN=your-tenant.auth0.com
NX_AUTH0_CLIENT_ID=your-client-id-from-auth0-dashboard
NX_AUTH0_AUDIENCE=https://api.your-app.com # Nếu dùng API

Bước 2: Tạo Auth Library trong Nx

  • Cài đặt thư viện
# Thêm Auth0 React SDK vào host app
nx add @auth0/auth0-react --project=host # Thêm thư viện types (nếu dùng TypeScript)
npm install --save-dev @types/auth0__auth0-react nx generate @nx/react:library auth --directory=libs/shared --importPath=@your-org/shared-auth

Cấu trúc thư viện:

libs/shared/auth/
├── src/
│ ├── lib/
│ │ ├── auth-context.tsx
│ │ ├── auth-guard.tsx
│ │ └── use-auth.ts
│ └── index.ts

Bước 3: Triển khai Auth Provide

// libs/shared/auth/src/lib/auth-context.tsx
import { createContext, useContext } from 'react';
import { useAuth0, Auth0ContextInterface } from '@auth0/auth0-react'; type AuthContextType = Auth0ContextInterface; const AuthContext = createContext<AuthContextType | null>(null); export const AuthProvider = ({ children }: { children: React.ReactNode }) => { const auth = useAuth0(); return <AuthContext.Provider value={auth}>{children}</AuthContext.Provider>;
}; export const useAuth = () => { const context = useContext(AuthContext); if (!context) { throw new Error('useAuth must be used within AuthProvider'); } return context;
};

Bước 4: Sử dụng trong Host App

// apps/host/src/app/app.tsx
import { Auth0Provider } from '@auth0/auth0-react';
import { AuthProvider } from '@your-org/shared-auth'; function App() { return ( <Auth0Provider domain={import.meta.env.VITE_AUTH0_DOMAIN} clientId={import.meta.env.VITE_AUTH0_CLIENT_ID} authorizationParams={{ redirect_uri: window.location.origin, audience: import.meta.env.VITE_AUTH0_AUDIENCE, }} cacheLocation="localstorage" useRefreshTokens > <AuthProvider> {/* App layout và routes */} </AuthProvider> </Auth0Provider> );
}

Bước 5: Sử dụng trong Micro Apps

// apps/micro-app/src/components/user-profile.tsx
import { useAuth } from '@your-org/shared-auth'; function UserProfile() { const { user, isAuthenticated, loginWithRedirect } = useAuth(); if (!isAuthenticated) { return <button onClick={() => loginWithRedirect()}>Login</button>; } return <div>Hello, {user.name}</div>;
}

IV. Best Practices cho Production

Token Auto-Refresh

Thêm vào AuthService class:

// libs/shared/auth/src/lib/auth-context.tsx
useEffect(() => { const interval = setInterval(async () => { try { await getAccessTokenSilently({ cacheMode: 'off', detailedResponse: true, }); } catch (error) { console.error('Token refresh failed:', error); clearInterval(interval); } }, 5 * 60 * 1000); // 5 phút return () => clearInterval(interval);
}, [getAccessTokenSilently]);

Route Guarding

  • Tạo component libs/auth/src/lib/AuthGuard.tsx:
// libs/shared/auth/src/lib/auth-guard.tsx
export const AuthGuard = ({ children }: { children: React.ReactNode }) => { const { isAuthenticated, isLoading, loginWithRedirect } = useAuth(); useEffect(() => { if (!isLoading && !isAuthenticated) { loginWithRedirect({ appState: { returnTo: window.location.pathname }, }); } }, [isLoading, isAuthenticated]); if (isLoading) { return <LoadingSpinner />; } return isAuthenticated ? children : null;
}; // Sử dụng trong routes
<Route path="/dashboard" element={ <AuthGuard> <DashboardPage /> </AuthGuard> }
/>

Error Handling

// libs/shared/auth/src/lib/error-boundary.tsx
export const AuthErrorBoundary = ({ children }: { children: React.ReactNode }) => { const { error } = useAuth(); if (error) { return ( <div> <h1>Authentication Error</h1> <p>{error.message}</p> <button onClick={() => window.location.reload()}>Retry</button> </div> ); } return children;
};

IV. Kết luận - "Đánh bại" auth khó nhằn! 🏆

Giờ thì bạn đã có đủ "vũ khí" để:

✅ Triển khai auth tập trung

✅ Xử lý token "cứng"

✅ Cho user trải nghiệm mượt mà

Nhớ nhé:

"Làm auth mà không dùng shared library giống như đi đánh nhau mà quên mang vũ khí!" 😂

Chúc bạn triển khai auth thành công và... ít bug nhất có thể! 🐧

Bình luận

Bài viết tương tự

- vừa được xem lúc

Thủ thuật nhỏ để căn chỉnh image với object-fit

Chào các bạn,. Có lẽ trong hành trình code của các bạn thì không ít lần gặp vấn đề méo ảnh do fix cứng cả width, height của ảnh nhỉ? Hoặc kể cả khi bạn set value cho 1 thuộc tính weigth hoặc height còn thuộc tính còn lại để auto thì nhiều lúc ảnh cũng không được hiển thị toàn vẹn cho lắm.

0 0 50

- vừa được xem lúc

Tìm hiểu về CSS framework - Bulma

Mở đầu:. Mấy bữa nay đang lướt web thấy có giới thiệu framework bulma này, được mọi người giới thiệu gọn nhẹ và dễ sử dụng, nên mình mới tìm hiểu thử và hôm nay xin viết 1 bài viết giới thiệu sơ qua với các bạn.

0 0 38

- vừa được xem lúc

Một số mẹo vặt "hay ho" của ES6 có thể bạn chưa biết - Phần 4

Xin chào, ở 3 bài trước của series "Một số mẹo vặt "hay ho" của ES6", mình đã chia sẻ 1 số tips/tricks nhỏ với ES6, hy vọng ít nhiều nó sẽ có ích với các bạn khi áp dụng vào thực tế. Hôm nay, xin mời các bạn theo dõi phần 4 của series này.

0 0 46

- vừa được xem lúc

Tìm hiểu về Jest Mocks Test phía frontend

Giới thiệu. Chắc hẳn không ai phủ nhận rằng UnitTest là 1 phần quan trọng trong giai đoạn phát triển phần mềm, đảm bảo cho code được coverage tránh các bug không mong muốn.

0 0 36

- vừa được xem lúc

Convert từ SVG sang Icon Font như thế nào?

Chào các bạn. Như câu hỏi trên title của bài viết, hôm nay mình sẽ hướng dẫn các bạn cách convert 1 file svg 1 cách khá đơn giản và vô cùng tiện lợi cho các bạn. https://icomoon.io/app/#/select.

0 0 54

- vừa được xem lúc

Một vài thủ thuật làm việc với các dạng layout - Phần 4

. Chào mọi người, cũng đã lâu rồi mình không thấy nhau. Để tiếp tục với series's về các dạng layout hôm nay mình sẽ chia sẻ thêm một trick thú vị nữa về step layout.

0 0 47