I. Giới thiệu
Hầu hết hệ thống ứng dụng back-end, tính năng xác thực và phân quyền người dùng đều phải có. Ví dụ, khi tạo một website, đương nhiên bạn cần phải xây dựng tính năng đăng ký, đăng nhập, phân quyền admin, mod, member… Có một một số kỹ thuật giúp bạn xây dựng tính năng này, ví dụ: dùng Sessions, hoặc mới hơn là JWT.
Qua bài viết này, chúng ta sẽ cùng nhau xây dựng một ví dụ ứng dụng Node.js + MongoDB hỗ trợ tính năng User Authentication (đăng ký, đăng nhập) và Authorization bằng JSONWebToken (JWT).
II. Sự khác nhau “Authentication” và “Authorization”
Nghe hai thuật ngữ này có vẻ giống nhau đúng không? Tuy nhiên, chúng hơi khác một chút. Mình sẽ không đi sâu vào chi tiết hoạt động của chúng. Phần này, mình chỉ muốn làm nổi bật đặc điểm để bạn phân biệt Authentication và Authorization.
1.1. Authentication
Authentication là quá trình hệ thống kiểm tra, xác định danh tính của người dùng hoặc một hệ thống khác đang truy cập vào hệ thống hiện tại.
Hiểu nôm na, quá trình Authentication đi tìm câu trả lời cho câu hỏi: “Bạn là ai?”
Quá trình Authentication rất thông dụng, hầu hết các CMS liên quan tới quản lý nội dung, tương tác với người dùng đều có. Hiện nay, authentication xác thực chủ yếu dựa trên hai thông tin: tên người dùng và mật khẩu.
1.2. Authorization
Tương tự, quá trình authorization để trả lời cho câu hỏi: “Bạn được phép làm gì?“.
Về mặt kỹ thuật, quá trình authorization thường được thực hiện sau khi quá trình authentication kết thức. Tức là, sau khi biết bạn là ai rồi thì bước tiếp theo xác định bạn được phép làm gì trong hệ thống.
III. Token Based Authentication
So với kỹ thuật xác thực dựa trên Session, bạn cần phải lưu Session vào Cookie. Lợi thế lớn nhất của Token-base authentication là lưu JSON Web Token (JWT) trên client như: Local Storage trên Browser, Keychain trong iOS app hay SharedPreferences trong ứng dụng Android, .v.v…
Vì vậy, chúng ta không cần phải xây dựng một dự án vệ tinh hoặc một module xác thực bổ sung để hỗ trợ cho ứng dụng không dùng trên trình duyệt (ví dụ như các ứng dụng mobile Android, iOS…)
Dưới đây là sơ đồ luồng hoạt động của JWT.
Có 3 thành phần quan trọng của JWT:
- Header
- Payload
- Signature
Chúng được kết hợp với nhau tạo thành một cấu trúc tiêu chuẩn:
1 2 | header<span class="token punctuation">.</span>payload<span class="token punctuation">.</span>signature |
Ứng dụng Client thường đính kèm mã JWT vào header với tiền tố Bearer:
1 2 | Authorization<span class="token punctuation">:</span> Bearer <span class="token punctuation">[</span>header<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token punctuation">[</span>payload<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token punctuation">[</span>signature<span class="token punctuation">]</span> |
Hoặc chỉ cần thêm một trường x-access-token trong header
1 2 | x<span class="token operator">-</span>access<span class="token operator">-</span>token<span class="token punctuation">:</span> <span class="token punctuation">[</span>header<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token punctuation">[</span>payload<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token punctuation">[</span>signature<span class="token punctuation">]</span> |
IV. Thực hành Node.js & MongoDB User Authentication
Sau khi tìm hiểu xong lý thuyết, giờ là lúc bắt tay vào thực hành. Chúng ta sẽ xây dựng một ứng dụng Node.js + Express với tính năng user authentication + authorization, trong đó:
- Người dùng có thể đăng ký tài khoản mới hoặc đăng nhập nếu đã có tài khoản.
- Phân quyền tài khoản người dùng theo role (admin, moderator, user). Với mỗi role, người dùng có quyền khác nhau để truy cập vào tài nguyên.
Đây là danh sách những APIs cần thiết:
V. Flow chương trình cho tính năng Signup & Login
Dưới đây là diagram miêu tả quy trình mà ứng dụng Node.js sẽ thực hiện cho các tính năng Authentication (User Registration, User Login) và Authorization (phân quyền).
Một JWT hợp lệ để truy cập vào tài nguyên hệ thống phải có trường x-access-token trong Header của HTTP.
VI. Node.js Express Architecture cho Authentication & Authorization
Hình dưới đây mô tả tổng quan kiến trúc ứng dụng sử dụng Node.js + Express cho authentication & authorization.
Thông qua Express, các HTTP request hợp lệ và đúng với route đã thiết kế (xem lại bảng 3.1- danh sách các API sử dụng trong app) sẽ được kiểm tra bởi CORS Middleware trước khi vào Security layer.
Security layer bao gồm:
- JWT Authentication Middleware: có nhiệm vụ xác minh SignUp, chuỗi token.
- Authorization Middleware: Kiểm tra role của người dùng đăng nhập với các thông tin được lưu trong cơ sở dữ liệu.
Nếu gặp bất kỳ lỗi nào trong toàn bộ quá trình trên sẽ lập tức phản hồi lại cho client dưới dạng HTTP response (error code).
Các kỹ thuật được sử dụng ví dụ này (phiên bản có thể khác trong tương lai nhưng chắc không vấn đề gì đâu):
- Express 4.17.1
- bcryptjs 2.4.3
- jsonwebtoken 8.5.1
- mongoose 5.9.1
- MongoDB
Yêu cầu môi trường phát triển, bạn cần phải cài đặt trước những phần mềm sau:
- Nodejs: Hướng dẫn cài đặt Node + Npm chi tiết
- MongoDB: đây là phần mềm quản trị cơ sở dữ liệu.
- Tải và cài đặt Visual code hoặc Sublime Text 3: dùng để viết code nhanh hơn
VII. Cấu trúc thư mục dự án
Dưới đây là cấu trúc thư mục mã nguồn của dự án trong bài viết này:
VIII. Tạo dự án NodeJS
Để bắt đầu, chúng ta cần tạo mới một dự án NodeJS. Phần này thì mình sẽ không hướng dẫn lại nữa, bạn có thể tham khảo cách làm chi tiết tại đây: Tạo dự án NodeJS
Khi tạo dự án mới xong, bạn cần tạo thêm các thư viện cần thiết: express, cors, body-parser, mongoose, jsonwebtoken và bcryptjs.
Sử dụng npm để cài đặt chúng, gõ lệnh sau:
1 2 | npm install express mongoose body<span class="token operator">-</span>parser cors jsonwebtoken bcryptjs <span class="token operator">--</span>save |
Nội dung package.json của dự án như sau:
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 | <span class="token punctuation">{</span> <span class="token double-quoted-string string">"name"</span><span class="token punctuation">:</span> <span class="token double-quoted-string string">"authentication-authorization-nodejs-jwt-mongodb"</span><span class="token punctuation">,</span> <span class="token double-quoted-string string">"version"</span><span class="token punctuation">:</span> <span class="token double-quoted-string string">"1.0.0"</span><span class="token punctuation">,</span> <span class="token double-quoted-string string">"description"</span><span class="token punctuation">:</span> <span class="token double-quoted-string string">"Node.js + MongoDB: JWT Authentication & Authorization"</span><span class="token punctuation">,</span> <span class="token double-quoted-string string">"main"</span><span class="token punctuation">:</span> <span class="token double-quoted-string string">"server.js"</span><span class="token punctuation">,</span> <span class="token double-quoted-string string">"scripts"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token double-quoted-string string">"test"</span><span class="token punctuation">:</span> <span class="token double-quoted-string string">"echo "Error: no test specified" && exit 1"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token double-quoted-string string">"keywords"</span><span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token double-quoted-string string">"node.js"</span><span class="token punctuation">,</span> <span class="token double-quoted-string string">"express"</span><span class="token punctuation">,</span> <span class="token double-quoted-string string">"jwt"</span><span class="token punctuation">,</span> <span class="token double-quoted-string string">"authentication"</span><span class="token punctuation">,</span> <span class="token double-quoted-string string">"mongodb"</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token double-quoted-string string">"author"</span><span class="token punctuation">:</span> <span class="token double-quoted-string string">"bezkoder.com"</span><span class="token punctuation">,</span> <span class="token double-quoted-string string">"license"</span><span class="token punctuation">:</span> <span class="token double-quoted-string string">"ISC"</span><span class="token punctuation">,</span> <span class="token double-quoted-string string">"dependencies"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token double-quoted-string string">"bcryptjs"</span><span class="token punctuation">:</span> <span class="token double-quoted-string string">"^2.4.3"</span><span class="token punctuation">,</span> <span class="token double-quoted-string string">"body-parser"</span><span class="token punctuation">:</span> <span class="token double-quoted-string string">"^1.19.0"</span><span class="token punctuation">,</span> <span class="token double-quoted-string string">"cors"</span><span class="token punctuation">:</span> <span class="token double-quoted-string string">"^2.8.5"</span><span class="token punctuation">,</span> <span class="token double-quoted-string string">"express"</span><span class="token punctuation">:</span> <span class="token double-quoted-string string">"^4.17.1"</span><span class="token punctuation">,</span> <span class="token double-quoted-string string">"jsonwebtoken"</span><span class="token punctuation">:</span> <span class="token double-quoted-string string">"^8.5.1"</span><span class="token punctuation">,</span> <span class="token double-quoted-string string">"mongoose"</span><span class="token punctuation">:</span> <span class="token double-quoted-string string">"^5.9.1"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
IX. Thiết lập Express web server
Trong thư mục gốc của dự án, tạo thêm tệp server.js có nội dung như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | <span class="token keyword">const</span> express <span class="token operator">=</span> <span class="token keyword">require</span><span class="token punctuation">(</span><span class="token double-quoted-string string">"express"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> bodyParser <span class="token operator">=</span> <span class="token keyword">require</span><span class="token punctuation">(</span><span class="token double-quoted-string string">"body-parser"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> cors <span class="token operator">=</span> <span class="token keyword">require</span><span class="token punctuation">(</span><span class="token double-quoted-string string">"cors"</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 keyword">var</span> corsOptions <span class="token operator">=</span> <span class="token punctuation">{</span> origin<span class="token punctuation">:</span> <span class="token double-quoted-string string">"http://localhost:8081"</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> app<span class="token punctuation">.</span><span class="token keyword">use</span><span class="token punctuation">(</span><span class="token function">cors</span><span class="token punctuation">(</span>corsOptions<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// parse requests of content-type - application/json</span> app<span class="token punctuation">.</span><span class="token keyword">use</span><span class="token punctuation">(</span>bodyParser<span class="token punctuation">.</span><span class="token function">json</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">// parse requests of content-type - application/x-www-form-urlencoded</span> app<span class="token punctuation">.</span><span class="token keyword">use</span><span class="token punctuation">(</span>bodyParser<span class="token punctuation">.</span><span class="token function">urlencoded</span><span class="token punctuation">(</span><span class="token punctuation">{</span> extended<span class="token punctuation">:</span> <span class="token boolean constant">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">// simple route</span> app<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token double-quoted-string string">"/"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span>req<span class="token punctuation">,</span> res<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">{</span> res<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">{</span> message<span class="token punctuation">:</span> <span class="token double-quoted-string string">"Welcome to VNTALKING application."</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 punctuation">;</span> <span class="token comment">// set port, listen for requests</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">8080</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 operator">></span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>`Server is running on port <span class="token variable">$</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 punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> |
Mình sẽ giải thích một chút về đoạn code trong server.js:
- Chúng ta import Express để tạo REST API
- Thư viện body-parser được dùng để parse các request vào body object.
- Import thư viện cors cung cấp Express middleware dùng để bật tính năng CORS
Cuối cùng, bạn có thể chạy thử ứng dụng bằng lệnh: npm start
Truy cập vào trình duyệt theo đường dẫn: http://localhost:8080/
X. Cấu hình kết nối MongoDB
Trong thư mục app, tạo riêng một thư mục mới, đặt tên là config. Thư mục này sẽ chứa tất cả các tệp liên quan tới cấu hình ứng dụng.
Trong thư mục config, bạn tạo tệp db.config.js để thêm các thông tin cài đặt cơ sở dữ liệu MongoDB cho ứng dụng:
1 2 3 4 5 | module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token constant">HOST</span><span class="token punctuation">:</span> <span class="token double-quoted-string string">"localhost"</span><span class="token punctuation">,</span> <span class="token constant">PORT</span><span class="token punctuation">:</span> <span class="token number">27017</span><span class="token punctuation">,</span> <span class="token constant">DB</span><span class="token punctuation">:</span> <span class="token double-quoted-string string">"vntalking_db"</span> |
XI. Định nghĩa Mongoose Model
Trong thư mục model, bạn tạo User và Role model như sau:
models/role.model.js
1 2 3 4 5 6 7 8 9 | <span class="token keyword">const</span> mongoose <span class="token operator">=</span> <span class="token keyword">require</span><span class="token punctuation">(</span><span class="token double-quoted-string string">"mongoose"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> Role <span class="token operator">=</span> mongoose<span class="token punctuation">.</span><span class="token function">model</span><span class="token punctuation">(</span> <span class="token double-quoted-string string">"Role"</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">mongoose<span class="token punctuation">.</span>Schema</span><span class="token punctuation">(</span><span class="token punctuation">{</span> name<span class="token punctuation">:</span> String <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> Role<span class="token punctuation">;</span> |
models/user.model.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <span class="token keyword">const</span> mongoose <span class="token operator">=</span> <span class="token keyword">require</span><span class="token punctuation">(</span><span class="token double-quoted-string string">"mongoose"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> User <span class="token operator">=</span> mongoose<span class="token punctuation">.</span><span class="token function">model</span><span class="token punctuation">(</span> <span class="token double-quoted-string string">"User"</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">mongoose<span class="token punctuation">.</span>Schema</span><span class="token punctuation">(</span><span class="token punctuation">{</span> username<span class="token punctuation">:</span> String<span class="token punctuation">,</span> email<span class="token punctuation">:</span> String<span class="token punctuation">,</span> password<span class="token punctuation">:</span> String<span class="token punctuation">,</span> roles<span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> type<span class="token punctuation">:</span> mongoose<span class="token punctuation">.</span>Schema<span class="token punctuation">.</span>Types<span class="token punctuation">.</span>ObjectId<span class="token punctuation">,</span> ref<span class="token punctuation">:</span> <span class="token double-quoted-string string">"Role"</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 punctuation">;</span> module<span class="token punctuation">.</span>exports <span class="token operator">=</span> User<span class="token punctuation">;</span> |
Các Mongoose Models này sẽ đại diện cho collection được tạo trong MongoDB. Khi bạn chạy chương trình, Mongoose sẽ tự động tạo hai collections có tên là: users và roles.
Sau khi đã khai báo xong, bạn không cần thiết phải tạo các hàm CRUD (đọc ghi cơ sở dữ liệu) vì Mongoose đã hỗ trợ sẵn rồi. Ví dụ:
- Tạo mới một User: có hàm object.save()
- Tìm một User theo Id: Sử dụng User.findById(id)
- Tìm User theo email: User.findOne({ email: … })
- Tìm tất cả roles: Role.find({…})
Những chức năng sẽ được chúng ta sử dụng trong Controllers. Cứ bình tĩnh nhé.
XII. Khởi tạo Mongoose
Bây giờ chúng ta tạo app/models/index.js với nội dung sau:
1 2 3 4 5 6 7 8 9 | <span class="token keyword">const</span> mongoose <span class="token operator">=</span> <span class="token keyword">require</span><span class="token punctuation">(</span><span class="token single-quoted-string string">'mongoose'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> mongoose<span class="token punctuation">.</span>Promise <span class="token operator">=</span> <span class="token keyword">global</span><span class="token punctuation">.</span>Promise<span class="token punctuation">;</span> <span class="token keyword">const</span> db <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span> db<span class="token punctuation">.</span>mongoose <span class="token operator">=</span> mongoose<span class="token punctuation">;</span> db<span class="token punctuation">.</span>user <span class="token operator">=</span> <span class="token keyword">require</span><span class="token punctuation">(</span><span class="token double-quoted-string string">"./user.model"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> db<span class="token punctuation">.</span>role <span class="token operator">=</span> <span class="token keyword">require</span><span class="token punctuation">(</span><span class="token double-quoted-string string">"./role.model"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> db<span class="token punctuation">.</span><span class="token constant">ROLES</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token double-quoted-string string">"user"</span><span class="token punctuation">,</span> <span class="token double-quoted-string string">"admin"</span><span class="token punctuation">,</span> <span class="token double-quoted-string string">"moderator"</span><span class="token punctuation">]</span><span class="token punctuation">;</span> module<span class="token punctuation">.</span>exports <span class="token operator">=</span> db<span class="token punctuation">;</span> |
Mở lại tệp server.js để thêm đoạn mã sau để mở kết nối Mongoose với cơ sở dữ liệu MongoDB.
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 50 | <span class="token punctuation">.</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 keyword">use</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 punctuation">;</span> <span class="token keyword">const</span> db <span class="token operator">=</span> <span class="token keyword">require</span><span class="token punctuation">(</span><span class="token double-quoted-string string">"./app/models"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> Role <span class="token operator">=</span> db<span class="token punctuation">.</span>role<span class="token punctuation">;</span> db<span class="token punctuation">.</span>mongoose <span class="token punctuation">.</span><span class="token function">connect</span><span class="token punctuation">(</span>`mongodb<span class="token punctuation">:</span><span class="token comment">//${dbConfig.HOST}:${dbConfig.PORT}/${dbConfig.DB}`, {</span> useNewUrlParser<span class="token punctuation">:</span> <span class="token boolean constant">true</span><span class="token punctuation">,</span> useUnifiedTopology<span class="token punctuation">:</span> <span class="token boolean constant">true</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</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 double-quoted-string string">"Successfully connect to MongoDB."</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">initial</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 punctuation">.</span><span class="token keyword">catch</span><span class="token punctuation">(</span>err <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token double-quoted-string string">"Connection error"</span><span class="token punctuation">,</span> err<span class="token punctuation">)</span><span class="token punctuation">;</span> process<span class="token punctuation">.</span><span class="token keyword">exit</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 punctuation">;</span> <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span> <span class="token keyword">function</span> <span class="token function">initial</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> Role<span class="token punctuation">.</span><span class="token function">estimatedDocumentCount</span><span class="token punctuation">(</span><span class="token punctuation">(</span>err<span class="token punctuation">,</span> count<span class="token punctuation">)</span> <span class="token operator">=</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>err <span class="token operator">&&</span> count <span class="token operator">===</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">new</span> <span class="token class-name">Role</span><span class="token punctuation">(</span><span class="token punctuation">{</span> name<span class="token punctuation">:</span> <span class="token double-quoted-string string">"user"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">save</span><span class="token punctuation">(</span>err <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</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 double-quoted-string string">"error"</span><span class="token punctuation">,</span> err<span class="token punctuation">)</span><span class="token punctuation">;</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 double-quoted-string string">"added 'user' to roles collection"</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">new</span> <span class="token class-name">Role</span><span class="token punctuation">(</span><span class="token punctuation">{</span> name<span class="token punctuation">:</span> <span class="token double-quoted-string string">"moderator"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">save</span><span class="token punctuation">(</span>err <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</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 double-quoted-string string">"error"</span><span class="token punctuation">,</span> err<span class="token punctuation">)</span><span class="token punctuation">;</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 double-quoted-string string">"added 'moderator' to roles collection"</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">new</span> <span class="token class-name">Role</span><span class="token punctuation">(</span><span class="token punctuation">{</span> name<span class="token punctuation">:</span> <span class="token double-quoted-string string">"admin"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">save</span><span class="token punctuation">(</span>err <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</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 double-quoted-string string">"error"</span><span class="token punctuation">,</span> err<span class="token punctuation">)</span><span class="token punctuation">;</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 double-quoted-string string">"added 'admin' to roles collection"</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 punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Hàm initial() cho phép chúng ta thêm dữ liệu 3 roles vào trong cơ sở dữ liệu, nếu trong DB có rồi thì bỏ qua.
XIII. Cấu hình Auth Key
Các hàm jsonwebtoken như: verify(), sign() sẽ cần tới một secret key để encode hay decode chuỗi token.
Trong thư mục app/config, tạo thêm auth.config.js với nội dung sau:
1 2 3 4 | module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token punctuation">{</span> secret<span class="token punctuation">:</span> <span class="token double-quoted-string string">"vntalking-secret-key"</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> |
Trong đó, bạn có thể tạo chuối secret bất kỳ cho riêng bạn.
XIV. Tạo các hàm middleware
Quá trình để verify một hành động trong SignUp, chúng ta cần làm 2 việc:
Kiểm tra xem tên người dùng, email có bị trùng lặp trong DB hay không?
Kiểm tra xem role đăng ký có hợp lệ hay không?
middlewares/verifySignUp.js
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 50 51 | <span class="token keyword">const</span> db <span class="token operator">=</span> <span class="token keyword">require</span><span class="token punctuation">(</span><span class="token double-quoted-string string">"../models"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token constant">ROLES</span> <span class="token operator">=</span> db<span class="token punctuation">.</span><span class="token constant">ROLES</span><span class="token punctuation">;</span> <span class="token keyword">const</span> User <span class="token operator">=</span> db<span class="token punctuation">.</span>user<span class="token punctuation">;</span> checkDuplicateUsernameOrEmail <span class="token operator">=</span> <span class="token punctuation">(</span>req<span class="token punctuation">,</span> res<span class="token punctuation">,</span> next<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">{</span> <span class="token comment">// Username</span> User<span class="token punctuation">.</span><span class="token function">findOne</span><span class="token punctuation">(</span><span class="token punctuation">{</span> username<span class="token punctuation">:</span> req<span class="token punctuation">.</span>body<span class="token punctuation">.</span>username <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">exec</span><span class="token punctuation">(</span><span class="token punctuation">(</span>err<span class="token punctuation">,</span> user<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span> res<span class="token punctuation">.</span><span class="token function">status</span><span class="token punctuation">(</span><span class="token number">500</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token punctuation">{</span> message<span class="token punctuation">:</span> err <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>user<span class="token punctuation">)</span> <span class="token punctuation">{</span> res<span class="token punctuation">.</span><span class="token function">status</span><span class="token punctuation">(</span><span class="token number">400</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token punctuation">{</span> message<span class="token punctuation">:</span> <span class="token double-quoted-string string">"Failed! Username is already in use!"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">// Email</span> User<span class="token punctuation">.</span><span class="token function">findOne</span><span class="token punctuation">(</span><span class="token punctuation">{</span> email<span class="token punctuation">:</span> req<span class="token punctuation">.</span>body<span class="token punctuation">.</span>email <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">exec</span><span class="token punctuation">(</span><span class="token punctuation">(</span>err<span class="token punctuation">,</span> user<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span> res<span class="token punctuation">.</span><span class="token function">status</span><span class="token punctuation">(</span><span class="token number">500</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token punctuation">{</span> message<span class="token punctuation">:</span> err <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>user<span class="token punctuation">)</span> <span class="token punctuation">{</span> res<span class="token punctuation">.</span><span class="token function">status</span><span class="token punctuation">(</span><span class="token number">400</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token punctuation">{</span> message<span class="token punctuation">:</span> <span class="token double-quoted-string string">"Failed! Email is already in use!"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">next</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 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> checkRolesExisted <span class="token operator">=</span> <span class="token punctuation">(</span>req<span class="token punctuation">,</span> res<span class="token punctuation">,</span> next<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>req<span class="token punctuation">.</span>body<span class="token punctuation">.</span>roles<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">for</span> <span class="token punctuation">(</span>let i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> req<span class="token punctuation">.</span>body<span class="token punctuation">.</span>roles<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token constant">ROLES</span><span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span>req<span class="token punctuation">.</span>body<span class="token punctuation">.</span>roles<span class="token punctuation">[</span>i<span class="token punctuation">]</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">status</span><span class="token punctuation">(</span><span class="token number">400</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token punctuation">{</span> message<span class="token punctuation">:</span> `Failed<span class="token operator">!</span> Role <span class="token variable">$</span><span class="token punctuation">{</span>req<span class="token punctuation">.</span>body<span class="token punctuation">.</span>roles<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">}</span> does not exist<span class="token operator">!</span>` <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token function">next</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> verifySignUp <span class="token operator">=</span> <span class="token punctuation">{</span> checkDuplicateUsernameOrEmail<span class="token punctuation">,</span> checkRolesExisted <span class="token punctuation">}</span><span class="token punctuation">;</span> module<span class="token punctuation">.</span>exports <span class="token operator">=</span> verifySignUp<span class="token punctuation">;</span> |
Để xử lý việc Authentication & Authorization, chúng ta cần tạo các hàm sau:
- Kiểm tra token có hợp lệ hay không? Chúng ta có thể lấy thông tin token trong trường x-access-token của Header HTTP, sau đó chuyển cho hàm verify() xử lý.
- Kiểm tra role đăng ký đã có role chưa hay là trống?
middlewares/authJwt.js
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 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | <span class="token keyword">const</span> jwt <span class="token operator">=</span> <span class="token keyword">require</span><span class="token punctuation">(</span><span class="token double-quoted-string string">"jsonwebtoken"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> config <span class="token operator">=</span> <span class="token keyword">require</span><span class="token punctuation">(</span><span class="token double-quoted-string string">"../config/auth.config.js"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> db <span class="token operator">=</span> <span class="token keyword">require</span><span class="token punctuation">(</span><span class="token double-quoted-string string">"../models"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> User <span class="token operator">=</span> db<span class="token punctuation">.</span>user<span class="token punctuation">;</span> <span class="token keyword">const</span> Role <span class="token operator">=</span> db<span class="token punctuation">.</span>role<span class="token punctuation">;</span> verifyToken <span class="token operator">=</span> <span class="token punctuation">(</span>req<span class="token punctuation">,</span> res<span class="token punctuation">,</span> next<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">{</span> let token <span class="token operator">=</span> req<span class="token punctuation">.</span>headers<span class="token punctuation">[</span><span class="token double-quoted-string string">"x-access-token"</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>token<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">status</span><span class="token punctuation">(</span><span class="token number">403</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token punctuation">{</span> message<span class="token punctuation">:</span> <span class="token double-quoted-string string">"No token provided!"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> jwt<span class="token punctuation">.</span><span class="token function">verify</span><span class="token punctuation">(</span>token<span class="token punctuation">,</span> config<span class="token punctuation">.</span>secret<span class="token punctuation">,</span> <span class="token punctuation">(</span>err<span class="token punctuation">,</span> decoded<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>err<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">status</span><span class="token punctuation">(</span><span class="token number">401</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token punctuation">{</span> message<span class="token punctuation">:</span> <span class="token double-quoted-string string">"Unauthorized!"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> req<span class="token punctuation">.</span>userId <span class="token operator">=</span> decoded<span class="token punctuation">.</span>id<span class="token punctuation">;</span> <span class="token function">next</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 punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> isAdmin <span class="token operator">=</span> <span class="token punctuation">(</span>req<span class="token punctuation">,</span> res<span class="token punctuation">,</span> next<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">{</span> User<span class="token punctuation">.</span><span class="token function">findById</span><span class="token punctuation">(</span>req<span class="token punctuation">.</span>userId<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">exec</span><span class="token punctuation">(</span><span class="token punctuation">(</span>err<span class="token punctuation">,</span> user<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span> res<span class="token punctuation">.</span><span class="token function">status</span><span class="token punctuation">(</span><span class="token number">500</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token punctuation">{</span> message<span class="token punctuation">:</span> err <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> Role<span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span> <span class="token punctuation">{</span> _id<span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token variable">$in</span><span class="token punctuation">:</span> user<span class="token punctuation">.</span>roles <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">(</span>err<span class="token punctuation">,</span> roles<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span> res<span class="token punctuation">.</span><span class="token function">status</span><span class="token punctuation">(</span><span class="token number">500</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token punctuation">{</span> message<span class="token punctuation">:</span> err <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">for</span> <span class="token punctuation">(</span>let i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> roles<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>roles<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>name <span class="token operator">===</span> <span class="token double-quoted-string string">"admin"</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">next</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</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">status</span><span class="token punctuation">(</span><span class="token number">403</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token punctuation">{</span> message<span class="token punctuation">:</span> <span class="token double-quoted-string string">"Require Admin Role!"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</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 punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> isModerator <span class="token operator">=</span> <span class="token punctuation">(</span>req<span class="token punctuation">,</span> res<span class="token punctuation">,</span> next<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">{</span> User<span class="token punctuation">.</span><span class="token function">findById</span><span class="token punctuation">(</span>req<span class="token punctuation">.</span>userId<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">exec</span><span class="token punctuation">(</span><span class="token punctuation">(</span>err<span class="token punctuation">,</span> user<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span> res<span class="token punctuation">.</span><span class="token function">status</span><span class="token punctuation">(</span><span class="token number">500</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token punctuation">{</span> message<span class="token punctuation">:</span> err <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> Role<span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span> <span class="token punctuation">{</span> _id<span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token variable">$in</span><span class="token punctuation">:</span> user<span class="token punctuation">.</span>roles <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">(</span>err<span class="token punctuation">,</span> roles<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span> res<span class="token punctuation">.</span><span class="token function">status</span><span class="token punctuation">(</span><span class="token number">500</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token punctuation">{</span> message<span class="token punctuation">:</span> err <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">for</span> <span class="token punctuation">(</span>let i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> roles<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>roles<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>name <span class="token operator">===</span> <span class="token double-quoted-string string">"moderator"</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">next</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</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">status</span><span class="token punctuation">(</span><span class="token number">403</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token punctuation">{</span> message<span class="token punctuation">:</span> <span class="token double-quoted-string string">"Require Moderator Role!"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</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 punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">const</span> authJwt <span class="token operator">=</span> <span class="token punctuation">{</span> verifyToken<span class="token punctuation">,</span> isAdmin<span class="token punctuation">,</span> isModerator <span class="token punctuation">}</span><span class="token punctuation">;</span> module<span class="token punctuation">.</span>exports <span class="token operator">=</span> authJwt<span class="token punctuation">;</span> |
Cuối cùng là tạo tệp index.js trong thư mục middlewares để export chúng:
1 2 3 4 5 6 7 | <span class="token keyword">const</span> authJwt <span class="token operator">=</span> <span class="token keyword">require</span><span class="token punctuation">(</span><span class="token double-quoted-string string">"./authJwt"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> verifySignUp <span class="token operator">=</span> <span class="token keyword">require</span><span class="token punctuation">(</span><span class="token double-quoted-string string">"./verifySignUp"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token punctuation">{</span> authJwt<span class="token punctuation">,</span> verifySignUp <span class="token punctuation">}</span><span class="token punctuation">;</span> |
XV. Tạo Controllers
Chúng ta sẽ lần lượt tạo controller cho 2 phần: Authentication và Authorization.
Controller cho Authentication
Với phần này, chúng ta có 2 công việc chính cho tính năng authentication:
- Đăng ký: tạo người dùng mới và lưu trong cơ sở dữ liệu (với role mặc định là User nếu không chỉ định trước lúc đăng ký).
- Đăng nhập: quá trình đăng nhập gồm 4 bước:
- Tìm username trong cơ sở dữ liệu,
- Nếu username tồn tại, so sánh password với password trong CSDL sử dụng. Nếu password khớp, tạo token bằng jsonwebtoken rồi trả về client với thông tin User kèm access-Token
Nguyên lý chỉ có như vậy, giờ là mã nguồn:
controllers/auth.controller.js
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 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | <span class="token keyword">const</span> config <span class="token operator">=</span> <span class="token keyword">require</span><span class="token punctuation">(</span><span class="token double-quoted-string string">"../config/auth.config"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> db <span class="token operator">=</span> <span class="token keyword">require</span><span class="token punctuation">(</span><span class="token double-quoted-string string">"../models"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> User <span class="token operator">=</span> db<span class="token punctuation">.</span>user<span class="token punctuation">;</span> <span class="token keyword">const</span> Role <span class="token operator">=</span> db<span class="token punctuation">.</span>role<span class="token punctuation">;</span> <span class="token keyword">var</span> jwt <span class="token operator">=</span> <span class="token keyword">require</span><span class="token punctuation">(</span><span class="token double-quoted-string string">"jsonwebtoken"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">var</span> bcrypt <span class="token operator">=</span> <span class="token keyword">require</span><span class="token punctuation">(</span><span class="token double-quoted-string string">"bcryptjs"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> exports<span class="token punctuation">.</span>signup <span class="token operator">=</span> <span class="token punctuation">(</span>req<span class="token punctuation">,</span> res<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> user <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">User</span><span class="token punctuation">(</span><span class="token punctuation">{</span> username<span class="token punctuation">:</span> req<span class="token punctuation">.</span>body<span class="token punctuation">.</span>username<span class="token punctuation">,</span> email<span class="token punctuation">:</span> req<span class="token punctuation">.</span>body<span class="token punctuation">.</span>email<span class="token punctuation">,</span> password<span class="token punctuation">:</span> bcrypt<span class="token punctuation">.</span><span class="token function">hashSync</span><span class="token punctuation">(</span>req<span class="token punctuation">.</span>body<span class="token punctuation">.</span>password<span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> user<span class="token punctuation">.</span><span class="token function">save</span><span class="token punctuation">(</span><span class="token punctuation">(</span>err<span class="token punctuation">,</span> user<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span> res<span class="token punctuation">.</span><span class="token function">status</span><span class="token punctuation">(</span><span class="token number">500</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token punctuation">{</span> message<span class="token punctuation">:</span> err <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>req<span class="token punctuation">.</span>body<span class="token punctuation">.</span>roles<span class="token punctuation">)</span> <span class="token punctuation">{</span> Role<span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span> <span class="token punctuation">{</span> name<span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token variable">$in</span><span class="token punctuation">:</span> req<span class="token punctuation">.</span>body<span class="token punctuation">.</span>roles <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">(</span>err<span class="token punctuation">,</span> roles<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span> res<span class="token punctuation">.</span><span class="token function">status</span><span class="token punctuation">(</span><span class="token number">500</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token punctuation">{</span> message<span class="token punctuation">:</span> err <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> user<span class="token punctuation">.</span>roles <span class="token operator">=</span> roles<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>role <span class="token operator">=</span><span class="token operator">></span> role<span class="token punctuation">.</span>_id<span class="token punctuation">)</span><span class="token punctuation">;</span> user<span class="token punctuation">.</span><span class="token function">save</span><span class="token punctuation">(</span>err <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span> res<span class="token punctuation">.</span><span class="token function">status</span><span class="token punctuation">(</span><span class="token number">500</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token punctuation">{</span> message<span class="token punctuation">:</span> err <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</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 punctuation">{</span> message<span class="token punctuation">:</span> <span class="token double-quoted-string string">"User was registered successfully!"</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 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">else</span> <span class="token punctuation">{</span> Role<span class="token punctuation">.</span><span class="token function">findOne</span><span class="token punctuation">(</span><span class="token punctuation">{</span> name<span class="token punctuation">:</span> <span class="token double-quoted-string string">"user"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">(</span>err<span class="token punctuation">,</span> role<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span> res<span class="token punctuation">.</span><span class="token function">status</span><span class="token punctuation">(</span><span class="token number">500</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token punctuation">{</span> message<span class="token punctuation">:</span> err <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> user<span class="token punctuation">.</span>roles <span class="token operator">=</span> <span class="token punctuation">[</span>role<span class="token punctuation">.</span>_id<span class="token punctuation">]</span><span class="token punctuation">;</span> user<span class="token punctuation">.</span><span class="token function">save</span><span class="token punctuation">(</span>err <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span> res<span class="token punctuation">.</span><span class="token function">status</span><span class="token punctuation">(</span><span class="token number">500</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token punctuation">{</span> message<span class="token punctuation">:</span> err <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</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 punctuation">{</span> message<span class="token punctuation">:</span> <span class="token double-quoted-string string">"User was registered successfully!"</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 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><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> exports<span class="token punctuation">.</span>signin <span class="token operator">=</span> <span class="token punctuation">(</span>req<span class="token punctuation">,</span> res<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">{</span> User<span class="token punctuation">.</span><span class="token function">findOne</span><span class="token punctuation">(</span><span class="token punctuation">{</span> username<span class="token punctuation">:</span> req<span class="token punctuation">.</span>body<span class="token punctuation">.</span>username <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">populate</span><span class="token punctuation">(</span><span class="token double-quoted-string string">"roles"</span><span class="token punctuation">,</span> <span class="token double-quoted-string string">"-__v"</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">exec</span><span class="token punctuation">(</span><span class="token punctuation">(</span>err<span class="token punctuation">,</span> user<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span> res<span class="token punctuation">.</span><span class="token function">status</span><span class="token punctuation">(</span><span class="token number">500</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token punctuation">{</span> message<span class="token punctuation">:</span> err <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</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">status</span><span class="token punctuation">(</span><span class="token number">404</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token punctuation">{</span> message<span class="token punctuation">:</span> <span class="token double-quoted-string string">"User Not found."</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">var</span> passwordIsValid <span class="token operator">=</span> bcrypt<span class="token punctuation">.</span><span class="token function">compareSync</span><span class="token punctuation">(</span> req<span class="token punctuation">.</span>body<span class="token punctuation">.</span>password<span class="token punctuation">,</span> user<span class="token punctuation">.</span>password <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>passwordIsValid<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">status</span><span class="token punctuation">(</span><span class="token number">401</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token punctuation">{</span> accessToken<span class="token punctuation">:</span> <span class="token constant">null</span><span class="token punctuation">,</span> message<span class="token punctuation">:</span> <span class="token double-quoted-string string">"Invalid Password!"</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">var</span> token <span class="token operator">=</span> jwt<span class="token punctuation">.</span><span class="token function">sign</span><span class="token punctuation">(</span><span class="token punctuation">{</span> id<span class="token punctuation">:</span> user<span class="token punctuation">.</span>id <span class="token punctuation">}</span><span class="token punctuation">,</span> config<span class="token punctuation">.</span>secret<span class="token punctuation">,</span> <span class="token punctuation">{</span> expiresIn<span class="token punctuation">:</span> <span class="token number">86400</span> <span class="token comment">// 24 hours</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">var</span> authorities <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">for</span> <span class="token punctuation">(</span>let i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> user<span class="token punctuation">.</span>roles<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> authorities<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token double-quoted-string string">"ROLE_"</span> <span class="token operator">+</span> user<span class="token punctuation">.</span>roles<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>name<span class="token punctuation">.</span><span class="token function">toUpperCase</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> res<span class="token punctuation">.</span><span class="token function">status</span><span class="token punctuation">(</span><span class="token number">200</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token punctuation">{</span> id<span class="token punctuation">:</span> user<span class="token punctuation">.</span>_id<span class="token punctuation">,</span> username<span class="token punctuation">:</span> user<span class="token punctuation">.</span>username<span class="token punctuation">,</span> email<span class="token punctuation">:</span> user<span class="token punctuation">.</span>email<span class="token punctuation">,</span> roles<span class="token punctuation">:</span> authorities<span class="token punctuation">,</span> accessToken<span class="token punctuation">:</span> token <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> <span class="token punctuation">}</span><span class="token punctuation">;</span> |
Controller cho Authorization
Chúng ta có 4 APIs chính cho việc phân quyền:
- /api/test/all
- /api/test/user
- /api/test/mod
- /api/test/admin
controllers/user.controller.js
1 2 3 4 5 6 7 8 9 10 11 12 13 | exports<span class="token punctuation">.</span>allAccess <span class="token operator">=</span> <span class="token punctuation">(</span>req<span class="token punctuation">,</span> res<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">{</span> res<span class="token punctuation">.</span><span class="token function">status</span><span class="token punctuation">(</span><span class="token number">200</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token double-quoted-string string">"Public Content."</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> exports<span class="token punctuation">.</span>userBoard <span class="token operator">=</span> <span class="token punctuation">(</span>req<span class="token punctuation">,</span> res<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">{</span> res<span class="token punctuation">.</span><span class="token function">status</span><span class="token punctuation">(</span><span class="token number">200</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token double-quoted-string string">"User Content."</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> exports<span class="token punctuation">.</span>adminBoard <span class="token operator">=</span> <span class="token punctuation">(</span>req<span class="token punctuation">,</span> res<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">{</span> res<span class="token punctuation">.</span><span class="token function">status</span><span class="token punctuation">(</span><span class="token number">200</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token double-quoted-string string">"Admin Content."</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> exports<span class="token punctuation">.</span>moderatorBoard <span class="token operator">=</span> <span class="token punctuation">(</span>req<span class="token punctuation">,</span> res<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">{</span> res<span class="token punctuation">.</span><span class="token function">status</span><span class="token punctuation">(</span><span class="token number">200</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token double-quoted-string string">"Moderator Content."</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> |
Phần tiếp theo, chúng ta sẽ kết hợp các controller này với middleware. Mọi người cảm thấy mỏi thì nghỉ ngơi, làm cốc cafe để lấy sức tiếp tục nhé.
XVI. Định nghĩa Routes
Khi một client gửi request tới web server sử dụng HTTP (GET, POST, PUT, DELETE) , chúng ta cần định nghĩa, xác định cách server tiếp nhận và phản hồi như thế nào. Đây chính là công dụng của các route.
Chúng ta chia các routes thành 2 nhóm: Authentication và Authorization
Authentication:
- POST /api/auth/signup
- POST /api/auth/signin
- routes/auth.routes.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | <span class="token keyword">const</span> <span class="token punctuation">{</span> verifySignUp <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">require</span><span class="token punctuation">(</span><span class="token double-quoted-string string">"../middlewares"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> controller <span class="token operator">=</span> <span class="token keyword">require</span><span class="token punctuation">(</span><span class="token double-quoted-string string">"../controllers/auth.controller"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span>app<span class="token punctuation">)</span> <span class="token punctuation">{</span> app<span class="token punctuation">.</span><span class="token keyword">use</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span>req<span class="token punctuation">,</span> res<span class="token punctuation">,</span> next<span class="token punctuation">)</span> <span class="token punctuation">{</span> res<span class="token punctuation">.</span><span class="token function">header</span><span class="token punctuation">(</span> <span class="token double-quoted-string string">"Access-Control-Allow-Headers"</span><span class="token punctuation">,</span> <span class="token double-quoted-string string">"x-access-token, Origin, Content-Type, Accept"</span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">next</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 punctuation">;</span> app<span class="token punctuation">.</span><span class="token function">post</span><span class="token punctuation">(</span> <span class="token double-quoted-string string">"/api/auth/signup"</span><span class="token punctuation">,</span> <span class="token punctuation">[</span> verifySignUp<span class="token punctuation">.</span>checkDuplicateUsernameOrEmail<span class="token punctuation">,</span> verifySignUp<span class="token punctuation">.</span>checkRolesExisted <span class="token punctuation">]</span><span class="token punctuation">,</span> controller<span class="token punctuation">.</span>signup <span class="token punctuation">)</span><span class="token punctuation">;</span> app<span class="token punctuation">.</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token double-quoted-string string">"/api/auth/signin"</span><span class="token punctuation">,</span> controller<span class="token punctuation">.</span>signin<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> |
Đừng quên thêm các routes vào trong tệp server.js
1 2 3 4 5 6 7 | <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span> <span class="token comment">// routes</span> <span class="token keyword">require</span><span class="token punctuation">(</span><span class="token single-quoted-string string">'./app/routes/auth.routes'</span><span class="token punctuation">)</span><span class="token punctuation">(</span>app<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">require</span><span class="token punctuation">(</span><span class="token single-quoted-string string">'./app/routes/user.routes'</span><span class="token punctuation">)</span><span class="token punctuation">(</span>app<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// set port, listen for requests</span> <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span> |
Như vậy là chúng ta đã hoàn thành dự án Node.js với Authentication rồi đấy. Bạn có thể tải toàn bộ mã nguồn trong bài viết tại đây:
Phần tiếp theo, chúng ta sẽ tiến hành chạy và test thử chương trình nhé.
XVII. Run & Test chương trình
Để chạy chương trình, bạn chỉ cần gõ lệnh: npm start
Sau khi chương trình chạy, chúng sẽ tự động tạo và thêm 3 roles cần thiết vào DB. Sử dụng Robo3T để xem dữ liệu trong MongoDB.
Có nhiều ứng dụng để test REST API, mình hay dùng Postman. Chúng ta test thử vớt API đăng ký mới: POST /api/auth/signup. Các API khác, các bạn tự thử nhé.
XVIII. Thay lời kết
Bài viết đến đây là kết thúc, chúng ta đã khám phá và thực hiện xây dựng ứng dụng Node.js để Authentication và Authorization sử dụng JWT (JSONWebToken).
Mình hi vọng bài viết này sẽ có ích cho bạn. Nếu có thắc mắc hãy để lại bình luận bên dưới nhé.
? Nguồn tham khảo: