Giới thiệu OAuth 2.0 và OpenID Connect
OAuth 2.0 là khung ủy quyền cho phép các ứng dụng của bên thứ ba thay mặt người dùng truy cập các tài nguyên hạn chế mà không làm lộ thông tin đăng nhập của người dùng. OpenID Connect là lớp nhận dạng được xây dựng trên OAuth 2.0 để cung cấp khả năng xác thực. Cùng nhau, họ có thể xác thực người dùng một cách an toàn và cho phép truy cập vào các tài nguyên được bảo vệ.
Bài viết này sẽ chỉ cho bạn cách triển khai OAuth 2.0 và OpenID Connect trong ứng dụng Node.js Express của bạn. Đơn giản hóa quy trình với Passport.js, một phần mềm trung gian phổ biến để xác thực.
điều kiện tiên quyết
Trước khi bắt đầu, hãy đảm bảo rằng bạn đã cài đặt các phần mềm sau trên máy của mình:
- Node.js (v14 trở lên)
- npm (v6 trở lên)
- Trình chỉnh sửa mã (chẳng hạn như Visual Studio Code)
Thiết lập ứng dụng Node.js Express
Đầu tiên, tạo một thư mục mới cho dự án của bạn và điều hướng đến nó trong thiết bị đầu cuối của bạn. Sau đó sử dụng npm để khởi tạo dự án của bạn.
1 2 3 4 | <span class="token function">mkdir</span> oauth-openid-nodejs <span class="token builtin class-name">cd</span> oauth-openid-nodejs <span class="token function">npm</span> init -y |
Cài đặt phụ thuộc
Sau đó cài đặt các gói cần thiết.
1 2 | <span class="token function">npm</span> <span class="token function">install</span> express passport passport-openidconnect dotenv |
Tạo một máy chủ Express
Tạo tệp index.js
trong thư mục gốc của dự án và thêm mã để định cấu hình máy chủ Express cơ bản.
1 2 3 4 5 6 7 8 9 10 11 12 | <span class="token keyword">const</span> express <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">'express'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> app <span class="token operator">=</span> <span class="token function">express</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> app <span class="token punctuation">.</span> <span class="token function">get</span> <span class="token punctuation">(</span> <span class="token string">'/'</span> <span class="token punctuation">,</span> <span class="token punctuation">(</span> <span class="token parameter">req <span class="token punctuation">,</span> res</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> res <span class="token punctuation">.</span> <span class="token function">send</span> <span class="token punctuation">(</span> <span class="token string">'OAuth 2.0とOpenID Connectデモへようこそ!'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token constant">PORT</span> <span class="token operator">=</span> process <span class="token punctuation">.</span> env <span class="token punctuation">.</span> <span class="token constant">PORT</span> <span class="token operator">||</span> <span class="token number">3000</span> <span class="token punctuation">;</span> app <span class="token punctuation">.</span> <span class="token function">listen</span> <span class="token punctuation">(</span> <span class="token constant">PORT</span> <span class="token punctuation">,</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console <span class="token punctuation">.</span> <span class="token function">log</span> <span class="token punctuation">(</span> <span class="token template-string"><span class="token template-punctuation string">`</span> <span class="token string">Server running on http://localhost:</span> <span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span> <span class="token constant">PORT</span> <span class="token interpolation-punctuation punctuation">}</span></span> <span class="token template-punctuation string">`</span></span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
Cách sử dụng OpenID Connect với Passport.js
Cài đặt hộ chiếu.js
Trước tiên, hãy tạo tệp .env
trong thư mục gốc của dự án để lưu trữ id ứng dụng khách, bí mật ứng dụng khách và url gọi lại. Chúng được cung cấp bởi nhà cung cấp xác thực bạn đã chọn (Google, Facebook, v.v.).
1 2 3 4 | CLIENT_ID=your_client_id CLIENT_SECRET=your_client_secret CALLBACK_URL=http://localhost:3000/auth/callback |
Tiếp theo, tạo tệp passport-setup.js
trong thư mục gốc của dự án và thêm mã để định cấu hình Passport.js bằng chiến lược OpenID Connect.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | <span class="token keyword">const</span> passport <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">'passport'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> OidcStrategy <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">'passport-openidconnect'</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> Strategy <span class="token punctuation">;</span> <span class="token keyword">const</span> dotenv <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">'dotenv'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> dotenv <span class="token punctuation">.</span> <span class="token function">config</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> passport <span class="token punctuation">.</span> <span class="token function">use</span> <span class="token punctuation">(</span> <span class="token keyword">new</span> <span class="token class-name">OidcStrategy</span> <span class="token punctuation">(</span> <span class="token punctuation">{</span> issuer <span class="token operator">:</span> <span class="token string">'https://your-auth-provider.com'</span> <span class="token punctuation">,</span> clientID <span class="token operator">:</span> process <span class="token punctuation">.</span> env <span class="token punctuation">.</span> <span class="token constant">CLIENT_ID</span> <span class="token punctuation">,</span> clientSecret <span class="token operator">:</span> process <span class="token punctuation">.</span> env <span class="token punctuation">.</span> <span class="token constant">CLIENT_SECRET</span> <span class="token punctuation">,</span> callbackURL <span class="token operator">:</span> process <span class="token punctuation">.</span> env <span class="token punctuation">.</span> <span class="token constant">CALLBACK_URL</span> <span class="token punctuation">,</span> scope <span class="token operator">:</span> <span class="token string">'openid profile email'</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">(</span> <span class="token parameter">accessToken <span class="token punctuation">,</span> refreshToken <span class="token punctuation">,</span> profile <span class="token punctuation">,</span> done</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token function">done</span> <span class="token punctuation">(</span> <span class="token keyword">null</span> <span class="token punctuation">,</span> profile <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> passport <span class="token punctuation">.</span> <span class="token function">serializeUser</span> <span class="token punctuation">(</span> <span class="token punctuation">(</span> <span class="token parameter">user <span class="token punctuation">,</span> done</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">done</span> <span class="token punctuation">(</span> <span class="token keyword">null</span> <span class="token punctuation">,</span> user <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> passport <span class="token punctuation">.</span> <span class="token function">deserializeUser</span> <span class="token punctuation">(</span> <span class="token punctuation">(</span> <span class="token parameter">user <span class="token punctuation">,</span> done</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">done</span> <span class="token punctuation">(</span> <span class="token keyword">null</span> <span class="token punctuation">,</span> user <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> module <span class="token punctuation">.</span> exports <span class="token operator">=</span> passport <span class="token punctuation">;</span> |
Thay thế https://your-auth-provider.com
bằng URL của nhà phát hành thích hợp cho nhà cung cấp xác thực bạn đã chọn.
Cập nhật máy chủ tốc hành
Tiếp theo, cập nhật tệp index.js
để bao gồm cài đặt Passport.js và OpenID Connect.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | <span class="token keyword">const</span> express <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">'express'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> passport <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">'./passport-setup'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> session <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">'express-session'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> app <span class="token operator">=</span> <span class="token function">express</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">// Expressでセッションミドルウェアを使用するように設定</span> app <span class="token punctuation">.</span> <span class="token function">use</span> <span class="token punctuation">(</span> <span class="token function">session</span> <span class="token punctuation">(</span> <span class="token punctuation">{</span> secret <span class="token operator">:</span> <span class="token string">'your-session-secret'</span> <span class="token punctuation">,</span> resave <span class="token operator">:</span> <span class="token boolean">false</span> <span class="token punctuation">,</span> saveUninitialized <span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">// Passport.jsとセッションサポートを初期化</span> app <span class="token punctuation">.</span> <span class="token function">use</span> <span class="token punctuation">(</span> passport <span class="token punctuation">.</span> <span class="token function">initialize</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> app <span class="token punctuation">.</span> <span class="token function">use</span> <span class="token punctuation">(</span> passport <span class="token punctuation">.</span> <span class="token function">session</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> app <span class="token punctuation">.</span> <span class="token function">get</span> <span class="token punctuation">(</span> <span class="token string">'/'</span> <span class="token punctuation">,</span> <span class="token punctuation">(</span> <span class="token parameter">req <span class="token punctuation">,</span> res</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> res <span class="token punctuation">.</span> <span class="token function">send</span> <span class="token punctuation">(</span> <span class="token string">'OAuth 2.0とOpenID Connectデモへようこそ!'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">// OAuth 2.0認証のためのルートを追加</span> app <span class="token punctuation">.</span> <span class="token function">get</span> <span class="token punctuation">(</span> <span class="token string">'/auth'</span> <span class="token punctuation">,</span> passport <span class="token punctuation">.</span> <span class="token function">authenticate</span> <span class="token punctuation">(</span> <span class="token string">'openidconnect'</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">// OAuth 2.0コールバックのためのルートを追加</span> app <span class="token punctuation">.</span> <span class="token function">get</span> <span class="token punctuation">(</span> <span class="token string">'/auth/callback'</span> <span class="token punctuation">,</span> passport <span class="token punctuation">.</span> <span class="token function">authenticate</span> <span class="token punctuation">(</span> <span class="token string">'openidconnect'</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> failureRedirect <span class="token operator">:</span> <span class="token string">'/login'</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token punctuation">(</span> <span class="token parameter">req <span class="token punctuation">,</span> res</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> res <span class="token punctuation">.</span> <span class="token function">redirect</span> <span class="token punctuation">(</span> <span class="token string">'/profile'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">// ユーザープロファイルのためのルートを追加</span> app <span class="token punctuation">.</span> <span class="token function">get</span> <span class="token punctuation">(</span> <span class="token string">'/profile'</span> <span class="token punctuation">,</span> <span class="token punctuation">(</span> <span class="token parameter">req <span class="token punctuation">,</span> res</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> <span class="token operator">!</span> req <span class="token punctuation">.</span> user <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> res <span class="token punctuation">.</span> <span class="token function">redirect</span> <span class="token punctuation">(</span> <span class="token string">'/login'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> res <span class="token punctuation">.</span> <span class="token function">send</span> <span class="token punctuation">(</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">こんにちは、</span> <span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span> req <span class="token punctuation">.</span> user <span class="token punctuation">.</span> displayName <span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">さん!</span> <span class="token template-punctuation string">`</span></span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">// ログインページのためのルートを追加</span> app <span class="token punctuation">.</span> <span class="token function">get</span> <span class="token punctuation">(</span> <span class="token string">'/login'</span> <span class="token punctuation">,</span> <span class="token punctuation">(</span> <span class="token parameter">req <span class="token punctuation">,</span> res</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> res <span class="token punctuation">.</span> <span class="token function">send</span> <span class="token punctuation">(</span> <span class="token string">'<a href="/auth">アイデンティティプロバイダーでログイン</a>'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token constant">PORT</span> <span class="token operator">=</span> process <span class="token punctuation">.</span> env <span class="token punctuation">.</span> <span class="token constant">PORT</span> <span class="token operator">||</span> <span class="token number">3000</span> <span class="token punctuation">;</span> app <span class="token punctuation">.</span> <span class="token function">listen</span> <span class="token punctuation">(</span> <span class="token constant">PORT</span> <span class="token punctuation">,</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console <span class="token punctuation">.</span> <span class="token function">log</span> <span class="token punctuation">(</span> <span class="token template-string"><span class="token template-punctuation string">`</span> <span class="token string">Server running on http://localhost:</span> <span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span> <span class="token constant">PORT</span> <span class="token interpolation-punctuation punctuation">}</span></span> <span class="token template-punctuation string">`</span></span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
thử nghiệm ứng dụng
Bạn hiện đã sẵn sàng thử nghiệm ứng dụng Node.js Express của mình bằng OAuth 2.0 và OpenID Connect. Để khởi động máy chủ, hãy chạy lệnh sau:
1 2 | node index.js |
Trỏ trình duyệt của bạn tới http://localhost:3000/login
và nhấp vào liên kết “Đăng nhập bằng Nhà cung cấp Nhận dạng”. Bạn sẽ được chuyển hướng đến trang đăng nhập của nhà cung cấp xác thực của bạn. Sau khi đăng nhập, bạn sẽ được chuyển hướng đến /profile
route và thấy lời chào cá nhân với tên hiển thị của bạn.
bản tóm tắt
Trong bài viết này, chúng tôi đã trình bày cách triển khai OAuth 2.0 và OpenID Connect trong ứng dụng Node.js Express bằng Passport.js. Phương pháp xác thực an toàn này cho phép người dùng xác thực mà không để lộ thông tin đăng nhập của họ cho các ứng dụng, dẫn đến quy trình xác thực an toàn và đáng tin cậy hơn.
Khi triển khai ứng dụng của bạn vào sản xuất, hãy nhớ thay thế thông tin cấu hình mẫu (URL của nhà phát hành, ID ứng dụng khách, Bí mật ứng dụng khách, v.v.) bằng thông tin nhà cung cấp xác thực thực tế của bạn.
cuối cùng
Tôi luôn mắc nợ. Tôi hy vọng bạn thích bài viết này và học được một cái gì đó mới.
Hẹn gặp lại các bạn trong bài viết tiếp theo! Nếu bạn thích bài viết này, hãy nhấn “THÍCH” và đăng ký để ủng hộ tôi. Cảm ơn rất nhiều.