1. Trước hết
Bài viết này mô tả cách triển khai chức năng đặt lại mật khẩu an toàn trong ứng dụng Node.js Express của bạn. Đặt lại mật khẩu là một tính năng quan trọng để đảm bảo tính bảo mật và trải nghiệm người dùng tốt. Để thực hiện điều này, chúng tôi sẽ hướng dẫn bạn qua quy trình, từng bước, từ thiết lập môi trường đến gửi email đặt lại đến cuối cùng là cập nhật mật khẩu người dùng của bạn.
2. Cài đặt dự án
2.1 Khởi tạo dự án
Đầu tiên, tạo một thư mục mới cho dự án của bạn và điều hướng đến nó trên dòng lệnh. Tiếp theo, khởi tạo dự án với tệp pack.json bằng cách chạy lệnh bên dưới.
1 2 | <span class="token function">npm</span> init -y |
2.2 Cài đặt phụ thuộc
Sau đó chạy lệnh sau để cài đặt các phụ thuộc cần thiết cho dự án này.
1 2 | <span class="token function">npm</span> <span class="token function">install</span> express mongoose bcryptjs jsonwebtoken nodemailer dotenv |
Những phụ thuộc này bao gồm:
- express: khung Express cốt lõi
- mongoose: Thư viện mô hình hóa đối tượng MongoDB cho Node.js
- bcryptjs: một thư viện để băm và so sánh mật khẩu
- jsonwebtoken: Một thư viện để tạo và xác thực JSON Web Tokens
- gật đầu: mô-đun để gửi email
- dotenv: module đọc biến môi trường từ file .env
3. Cài đặt môi trường
3.1 Tạo tệp .env
Tạo tệp .env trong thư mục gốc của dự án để lưu trữ dữ liệu nhạy cảm và cài đặt dành riêng cho môi trường. Thêm các dòng sau vào tệp.
1 2 3 4 5 6 | MONGODB_URI=mongodb://localhost:27017/password-reset EMAIL_SERVICE=あなたのメールサービス EMAIL_USER=あなたのメールアドレス EMAIL_PASS=あなたのメールパスワード JWT_SECRET=あなたのJWT秘密鍵 |
Đảm bảo thay thế trình giữ chỗ bằng các giá trị phù hợp với dịch vụ email và thông tin đăng nhập tài khoản của bạn.
3.2 Tải biến môi trường
Trong tệp ứng dụng chính của bạn (ví dụ: app.js), hãy nhập mô-đun dotenv và đặt nó để tải các biến môi trường từ tệp .env của bạn.
1 2 | <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">'dotenv'</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">config</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
4. Cấu hình cơ sở dữ liệu
4.1 Kết nối với MongoDB
Sử dụng Mongoose để thiết lập kết nối tới cơ sở dữ liệu MongoDB của bạn. Cập nhật tệp app.js của bạn bằng mã bên dưới.
1 2 3 4 5 6 7 8 9 10 11 12 13 | <span class="token keyword">const</span> express <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">'express'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> mongoose <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">'mongoose'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> app <span class="token operator">=</span> <span class="token function">express</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> app <span class="token punctuation">.</span> <span class="token function">use</span> <span class="token punctuation">(</span> express <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> mongoose <span class="token punctuation">.</span> <span class="token function">connect</span> <span class="token punctuation">(</span> process <span class="token punctuation">.</span> env <span class="token punctuation">.</span> <span class="token constant">MONGODB_URI</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> useNewUrlParser <span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">,</span> useUnifiedTopology <span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">then</span> <span class="token punctuation">(</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> console <span class="token punctuation">.</span> <span class="token function">log</span> <span class="token punctuation">(</span> <span class="token string">'Connected to MongoDB'</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">catch</span> <span class="token punctuation">(</span> <span class="token punctuation">(</span> <span class="token parameter">err</span> <span class="token punctuation">)</span> <span class="token operator">=></span> console <span class="token punctuation">.</span> <span class="token function">error</span> <span class="token punctuation">(</span> <span class="token string">'Failed to connect to MongoDB:'</span> <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">const</span> <span class="token constant">PORT</span> <span class="token operator">=</span> process <span class="token punctuation">.</span> env <span class="token punctuation">.</span> <span class="token constant">PORT</span> <span class="token operator">||</span> <span class="token number">3000</span> <span class="token punctuation">;</span> app <span class="token punctuation">.</span> <span class="token function">listen</span> <span class="token punctuation">(</span> <span class="token constant">PORT</span> <span class="token punctuation">,</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> console <span class="token punctuation">.</span> <span class="token function">log</span> <span class="token punctuation">(</span> <span class="token template-string"><span class="token template-punctuation string">`</span> <span class="token string">Server is running on port </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span> <span class="token constant">PORT</span> <span class="token interpolation-punctuation punctuation">}</span></span> <span class="token template-punctuation string">`</span></span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
4.2 Xác định mô hình và lược đồ người dùng
Tạo một thư mục mới có tên models và tạo một tệp có tên User.js bên trong nó. Xác định lược đồ người dùng và mô hình bằng đoạn mã 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 | <span class="token keyword">const</span> mongoose <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">'mongoose'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> bcrypt <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">'bcryptjs'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> userSchema <span class="token operator">=</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> email <span class="token operator">:</span> <span class="token punctuation">{</span> type <span class="token operator">:</span> String <span class="token punctuation">,</span> required <span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">,</span> unique <span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> password <span class="token operator">:</span> <span class="token punctuation">{</span> type <span class="token operator">:</span> String <span class="token punctuation">,</span> required <span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> passwordResetToken <span class="token operator">:</span> <span class="token punctuation">{</span> type <span class="token operator">:</span> String <span class="token punctuation">}</span> <span class="token punctuation">,</span> passwordResetExpires <span class="token operator">:</span> <span class="token punctuation">{</span> type <span class="token operator">:</span> Date <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">// データベースに保存する前にパスワードをハッシュ化する</span> userSchema <span class="token punctuation">.</span> <span class="token function">pre</span> <span class="token punctuation">(</span> <span class="token string">'save'</span> <span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token punctuation">(</span> <span class="token parameter">next</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 keyword">this</span> <span class="token punctuation">.</span> <span class="token function">isModified</span> <span class="token punctuation">(</span> <span class="token string">'password'</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token keyword">return</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">const</span> salt <span class="token operator">=</span> <span class="token keyword">await</span> bcrypt <span class="token punctuation">.</span> <span class="token function">genSalt</span> <span class="token punctuation">(</span> <span class="token number">10</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> password <span class="token operator">=</span> <span class="token keyword">await</span> bcrypt <span class="token punctuation">.</span> <span class="token function">hash</span> <span class="token punctuation">(</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> password <span class="token punctuation">,</span> salt <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 comment">// ユーザーのパスワードを検証するインスタンスメソッド</span> userSchema <span class="token punctuation">.</span> methods <span class="token punctuation">.</span> <span class="token function-variable function">validatePassword</span> <span class="token operator">=</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token punctuation">(</span> <span class="token parameter">password</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">await</span> bcrypt <span class="token punctuation">.</span> <span class="token function">compare</span> <span class="token punctuation">(</span> password <span class="token punctuation">,</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> password <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> 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 string">'User'</span> <span class="token punctuation">,</span> userSchema <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> |
5. Thực hiện chức năng đặt lại mật khẩu
5.1 Cấu hình tuyến đường
Tạo một thư mục mới có tên là các tuyến đường và tạo một tệp có tên auth.js bên trong nó. Đặt các tuyến đường sau.
- /auth/forgot-password: để bắt đầu quá trình đặt lại mật khẩu
- /auth/reset-password: để xử lý việc đặt lại mật khẩu thực tế
1 2 3 4 5 6 7 8 9 | <span class="token keyword">const</span> express <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">'express'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> router <span class="token operator">=</span> express <span class="token punctuation">.</span> <span class="token function">Router</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token punctuation">{</span> forgotPassword <span class="token punctuation">,</span> resetPassword <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">'../controllers/authController'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> router <span class="token punctuation">.</span> <span class="token function">post</span> <span class="token punctuation">(</span> <span class="token string">'/forgot-password'</span> <span class="token punctuation">,</span> forgotPassword <span class="token punctuation">)</span> <span class="token punctuation">;</span> router <span class="token punctuation">.</span> <span class="token function">post</span> <span class="token punctuation">(</span> <span class="token string">'/reset-password'</span> <span class="token punctuation">,</span> resetPassword <span class="token punctuation">)</span> <span class="token punctuation">;</span> module <span class="token punctuation">.</span> exports <span class="token operator">=</span> router <span class="token punctuation">;</span> |
Sau đó nhập và sử dụng bộ định tuyến auth.js trong tệp app.js của bạn.
1 2 3 4 | <span class="token keyword">const</span> authRoutes <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">'./routes/auth'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> app <span class="token punctuation">.</span> <span class="token function">use</span> <span class="token punctuation">(</span> <span class="token string">'/auth'</span> <span class="token punctuation">,</span> authRoutes <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
5.2 Tạo bộ điều khiển xác thực
Tạo một thư mục mới có tên là bộ điều khiển và bên trong nó tạo một tệp có tên authController.js. Tệp này chứa các chức năng của bộ điều khiển để xử lý quá trình đặt lại mật khẩu.
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 | <span class="token keyword">const</span> User <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">'../models/User'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> jwt <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">'jsonwebtoken'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> bcrypt <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">'bcryptjs'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> nodemailer <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">'nodemailer'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> transporter <span class="token operator">=</span> nodemailer <span class="token punctuation">.</span> <span class="token function">createTransport</span> <span class="token punctuation">(</span> <span class="token punctuation">{</span> service <span class="token operator">:</span> process <span class="token punctuation">.</span> env <span class="token punctuation">.</span> <span class="token constant">EMAIL_SERVICE</span> <span class="token punctuation">,</span> auth <span class="token operator">:</span> <span class="token punctuation">{</span> user <span class="token operator">:</span> process <span class="token punctuation">.</span> env <span class="token punctuation">.</span> <span class="token constant">EMAIL_USER</span> <span class="token punctuation">,</span> pass <span class="token operator">:</span> process <span class="token punctuation">.</span> env <span class="token punctuation">.</span> <span class="token constant">EMAIL_PASS</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">async</span> <span class="token keyword">function</span> <span class="token function">forgotPassword</span> <span class="token punctuation">(</span> <span class="token parameter">req <span class="token punctuation">,</span> res</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// TODO: forgotPassword関数を実装する</span> <span class="token punctuation">}</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">resetPassword</span> <span class="token punctuation">(</span> <span class="token parameter">req <span class="token punctuation">,</span> res</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// TODO: resetPassword関数を実装する</span> <span class="token punctuation">}</span> module <span class="token punctuation">.</span> exports <span class="token operator">=</span> <span class="token punctuation">{</span> forgotPassword <span class="token punctuation">,</span> resetPassword <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> |
5.3 Thực hiện chức năng quên mật khẩu
Trong tệp authController.js, hãy triển khai chức năng forgetPassword để xử lý các yêu cầu đặt lại mật khẩu.
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 | <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">forgotPassword</span> <span class="token punctuation">(</span> <span class="token parameter">req <span class="token punctuation">,</span> res</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// メールでユーザーを見つける</span> <span class="token keyword">const</span> user <span class="token operator">=</span> <span class="token keyword">await</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 operator">:</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 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">json</span> <span class="token punctuation">(</span> <span class="token punctuation">{</span> error <span class="token operator">:</span> <span class="token string">'ユーザーが見つかりません'</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">// パスワードリセットトークンを生成し、有効期限を設定する</span> <span class="token keyword">const</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 operator">:</span> user <span class="token punctuation">.</span> _id <span class="token punctuation">}</span> <span class="token punctuation">,</span> process <span class="token punctuation">.</span> env <span class="token punctuation">.</span> <span class="token constant">JWT_SECRET</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> expiresIn <span class="token operator">:</span> <span class="token string">'1h'</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> user <span class="token punctuation">.</span> passwordResetToken <span class="token operator">=</span> token <span class="token punctuation">;</span> user <span class="token punctuation">.</span> passwordResetExpires <span class="token operator">=</span> Date <span class="token punctuation">.</span> <span class="token function">now</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token number">3600000</span> <span class="token punctuation">;</span> <span class="token comment">// 1時間</span> <span class="token keyword">await</span> user <span class="token punctuation">.</span> <span class="token function">save</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">// パスワードリセットメールを送信する</span> <span class="token keyword">const</span> resetUrl <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span> <span class="token string">http://</span> <span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span> req <span class="token punctuation">.</span> headers <span class="token punctuation">.</span> host <span class="token interpolation-punctuation punctuation">}</span></span> <span class="token string">/auth/reset-password?token=</span> <span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span> token <span class="token interpolation-punctuation punctuation">}</span></span> <span class="token template-punctuation string">`</span></span> <span class="token punctuation">;</span> <span class="token keyword">const</span> mailOptions <span class="token operator">=</span> <span class="token punctuation">{</span> from <span class="token operator">:</span> process <span class="token punctuation">.</span> env <span class="token punctuation">.</span> <span class="token constant">EMAIL_USER</span> <span class="token punctuation">,</span> to <span class="token operator">:</span> user <span class="token punctuation">.</span> email <span class="token punctuation">,</span> subject <span class="token operator">:</span> <span class="token string">'パスワードリセットリクエスト'</span> <span class="token punctuation">,</span> html <span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"> <p>パスワードリセットをリクエストしました。以下のリンクをクリックしてパスワードをリセットしてください。<p> <a href="</span> <span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span> resetUrl <span class="token interpolation-punctuation punctuation">}</span></span> <span class="token string">"></span> <span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span> resetUrl <span class="token interpolation-punctuation punctuation">}</span></span> <span class="token string"><a> <p>このリクエストを行っていない場合は、このメールを無視してください。<p> </span><span class="token template-punctuation string">`</span></span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> <span class="token keyword">try</span> <span class="token punctuation">{</span> <span class="token keyword">await</span> transporter <span class="token punctuation">.</span> <span class="token function">sendMail</span> <span class="token punctuation">(</span> mailOptions <span class="token punctuation">)</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 operator">:</span> <span class="token string">'パスワードリセットメールが送信されました'</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 punctuation">)</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 string">'パスワードリセットメールの送信に失敗しました:'</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">json</span> <span class="token punctuation">(</span> <span class="token punctuation">{</span> error <span class="token operator">:</span> <span class="token string">'パスワードリセットメールの送信に失敗しました'</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> |
5.4 Thực hiện chức năng resetPassword
Trong tệp authController.js
, hãy triển khai chức năng resetPassword
để xử lý các xác nhận đặt lại mật khẩu và cập nhật mật khẩu của người dùng.
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 | <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">resetPassword</span> <span class="token punctuation">(</span> <span class="token parameter">req <span class="token punctuation">,</span> res</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// パスワードリセットトークンを検証する</span> <span class="token keyword">const</span> token <span class="token operator">=</span> req <span class="token punctuation">.</span> query <span class="token punctuation">.</span> token <span class="token punctuation">;</span> <span class="token keyword">const</span> decodedToken <span class="token operator">=</span> jwt <span class="token punctuation">.</span> <span class="token function">verify</span> <span class="token punctuation">(</span> token <span class="token punctuation">,</span> process <span class="token punctuation">.</span> env <span class="token punctuation">.</span> <span class="token constant">JWT_SECRET</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">// IDとトークンでユーザーを検索し、トークンがまだ有効かどうかを確認する</span> <span class="token keyword">const</span> user <span class="token operator">=</span> <span class="token keyword">await</span> User <span class="token punctuation">.</span> <span class="token function">findOne</span> <span class="token punctuation">(</span> <span class="token punctuation">{</span> _id <span class="token operator">:</span> decodedToken <span class="token punctuation">.</span> id <span class="token punctuation">,</span> passwordResetToken <span class="token operator">:</span> token <span class="token punctuation">,</span> passwordResetExpires <span class="token operator">:</span> <span class="token punctuation">{</span> $gt <span class="token operator">:</span> Date <span class="token punctuation">.</span> <span class="token function">now</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">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">401</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">json</span> <span class="token punctuation">(</span> <span class="token punctuation">{</span> error <span class="token operator">:</span> <span class="token string">'無効または期限切れのパスワードリセットトークン'</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">// ユーザーのパスワードを更新し、リセットトークンとその有効期限を削除する</span> user <span class="token punctuation">.</span> password <span class="token operator">=</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> passwordResetToken <span class="token operator">=</span> <span class="token keyword">undefined</span> <span class="token punctuation">;</span> user <span class="token punctuation">.</span> passwordResetExpires <span class="token operator">=</span> <span class="token keyword">undefined</span> <span class="token punctuation">;</span> <span class="token keyword">await</span> user <span class="token punctuation">.</span> <span class="token function">save</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">// 確認メールを送信する</span> <span class="token keyword">const</span> mailOptions <span class="token operator">=</span> <span class="token punctuation">{</span> from <span class="token operator">:</span> process <span class="token punctuation">.</span> env <span class="token punctuation">.</span> <span class="token constant">EMAIL_USER</span> <span class="token punctuation">,</span> to <span class="token operator">:</span> user <span class="token punctuation">.</span> email <span class="token punctuation">,</span> subject <span class="token operator">:</span> <span class="token string">'パスワードリセット確認'</span> <span class="token punctuation">,</span> html <span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"> <p>パスワードが正常にリセットされました。このリクエストを行っていない場合は、すぐにお問い合わせください。</p> </span><span class="token template-punctuation string">`</span></span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> <span class="token keyword">try</span> <span class="token punctuation">{</span> <span class="token keyword">await</span> transporter <span class="token punctuation">.</span> <span class="token function">sendMail</span> <span class="token punctuation">(</span> mailOptions <span class="token punctuation">)</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 operator">:</span> <span class="token string">'パスワードリセットが成功しました'</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 punctuation">)</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 string">'パスワードリセット確認メールの送信に失敗しました:'</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">json</span> <span class="token punctuation">(</span> <span class="token punctuation">{</span> error <span class="token operator">:</span> <span class="token string">'パスワードリセット確認メールの送信に失敗しました'</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> |
6. Kiểm tra việc triển khai của bạn
Để kiểm tra chức năng đặt lại mật khẩu, hãy sử dụng một công cụ như Postman hoặc curl để gửi yêu cầu đến các điểm cuối /auth/forgot-password và /auth/reset-password. Dưới đây là các bước để gửi yêu cầu bằng Postman.
- Mở Postman và tạo một yêu cầu mới.
- Đặt loại yêu cầu thành POST và nhập http://localhost:3000/auth/forgot-password vào URL.
- Chọn tab Nội dung, chọn thô và chọn JSON.
- Nhập đối tượng JSON sau vào phần nội dung và chỉ định địa chỉ email của người dùng đã đăng ký.1234<span class="token punctuation">{</span><span class="token property">"email"</span> <span class="token operator">:</span> <span class="token string">"user@example.com"</span><span class="token punctuation">}</span>
- Nhấp vào nút
Send
để gửi yêu cầu của bạn. Một phản hồi thành công sẽ được trả lại và một email đặt lại mật khẩu sẽ được gửi đến địa chỉ email được chỉ định. - Sao chép liên kết đặt lại được cung cấp trong email và tạo một yêu cầu mới trong
Postman
. - Đặt loại yêu cầu thành POST và nhập mã thông báo http://localhost:3000/auth/reset-password?token=copied vào URL.
- Chọn lại tab
Body
, chọnraw
và chọnJSON
. - Nhập đối tượng JSON sau vào phần nội dung và chỉ định mật khẩu mới.1234<span class="token punctuation">{</span><span class="token property">"password"</span> <span class="token operator">:</span> <span class="token string">"new-password"</span><span class="token punctuation">}</span>
- Nhấp vào nút Gửi để gửi yêu cầu của bạn. Một phản hồi thành công được trả về và mật khẩu được đặt lại.
7. Tóm tắt
Trong bài viết này, chúng ta đã xem cách triển khai chức năng đặt lại mật khẩu an toàn trong ứng dụng Node.js Express. Điều này cho phép người dùng lấy lại quyền truy cập vào tài khoản của họ một cách an toàn ngay cả khi họ quên mật khẩu.
Phương pháp được triển khai lần này là một ví dụ và trong môi trường sản xuất thực tế, bạn nên thêm xử lý lỗi và xác thực. Điều quan trọng nữa là xây dựng giao diện người dùng đặt lại mật khẩu ở giao diện người dùng để mang lại trải nghiệm tốt hơn cho người dùng.
cuối cùng
Tôi luôn mắc nợ. Tôi hy vọng bạn thích bài viết này và học được một cái gì đó mới.
Hẹn gặp lại các bạn trong bài viết tiếp theo! Nếu bạn thích bài viết này, hãy nhấn “THÍCH” và đăng ký để ủng hộ tôi. Cảm ơn rất nhiều.