Đăng nhập

📘 BÀI 22: GIAO DIỆN TÀI KHOẢN + ĐỔI MẬT KHẨU (Vue + NodeJS)

Giao diện Quản lý Tài khoản + Thay đổi Mật khẩu, bạn sẽ học cách tạo một trang người dùng thực tế – nơi họ có thể:

  • Xem thông tin tài khoản
  • Đổi mật khẩu
  • Đăng xuất an toàn

Mục tiêu:

  • Tạo trang “Tài khoản cá nhân”
  • Giao diện đổi mật khẩu
  • API xử lý đổi mật khẩu bảo mật
  • Tự động đăng xuất sau khi đổi mật khẩu

Phần 1: Cập nhật Backend – API đổi mật khẩu

index.js – thêm route POST /auth/change-password

app.post('/auth/change-password', authMiddleware, async (req, res) => {
  const { currentPassword, newPassword } = req.body
  const user = await User.findById(req.userId)
  const match = await user.comparePassword(currentPassword)
  if (!match) return res.status(400).json({ error: 'Mật khẩu hiện tại không đúng' })

  user.password = newPassword
  await user.save()
  res.json({ message: 'Mật khẩu đã được đổi. Vui lòng đăng nhập lại.' })
})

Phần 2: Tạo giao diện tài khoản trong Vue

src/views/AccountView.vue

<template>
  <div class="account">
    <h2>Tài khoản của bạn</h2>
    <p>Username: <strong>{{ username }}</strong></p>

    <form @submit.prevent="changePassword">
      <h3>Đổi mật khẩu</h3>
      <input v-model="currentPassword" type="password" placeholder="Mật khẩu hiện tại" required />
      <input v-model="newPassword" type="password" placeholder="Mật khẩu mới" required />
      <button type="submit">Đổi mật khẩu</button>
    </form>

    <p v-if="message" :class="{ success: success, error: !success }">{{ message }}</p>
    <button @click="logout">Đăng xuất</button>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { useAuthStore } from '@/store/authStore'
import { useTodoStore } from '@/store/todoStore'
import { useRouter } from 'vue-router'

const auth = useAuthStore()
const todos = useTodoStore()
const router = useRouter()

const username = ref('') // chưa có backend trả username → hardcode hoặc thêm API riêng
const currentPassword = ref('')
const newPassword = ref('')
const message = ref('')
const success = ref(false)

async function changePassword() {
  const res = await fetch('http://localhost:5000/auth/change-password', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      Authorization: 'Bearer ' + auth.token
    },
    body: JSON.stringify({
      currentPassword: currentPassword.value,
      newPassword: newPassword.value
    })
  })
  const data = await res.json()
  message.value = data.message || data.error
  success.value = res.ok

  if (res.ok) {
    auth.logout()
    todos.todos = []
    router.push('/login')
  }
}

function logout() {
  auth.logout()
  todos.todos = []
  router.push('/login')
}
</script>

<style scoped>
.account {
  max-width: 400px;
  margin: 0 auto;
}
input {
  display: block;
  margin: 8px 0;
  padding: 8px;
  width: 100%;
}
button {
  padding: 8px 16px;
  margin-top: 10px;
}
.success {
  color: green;
}
.error {
  color: red;
}
</style>

Ghi chú bảo mật:

  • Sau khi đổi mật khẩu → buộc người dùng đăng xuất (invalidate JWT hiện tại)
  • Trong hệ thống lớn: bạn nên dùng token version / token blacklist
Thành phầnMục tiêu
API /change-passwordĐổi mật khẩu có xác thực
Giao diện VueHiển thị thông tin, nhập mật khẩu mới
Token logicĐăng xuất sau khi đổi mật khẩu thành công
State quản lý bằng PiniaDễ bảo trì, chia sẻ trạng thái toàn app
  1. Thêm API GET /auth/me để lấy username, email,…
  2. Cho phép người dùng cập nhật thông tin hồ sơ (tên, avatar, bio,…)
  3. Hiển thị ngày tạo tài khoản (user.createdAt)

Thảo luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *

Đăng ký nhận tin mới

Nhận bài học, tài nguyên và cơ hội việc làm qua email hàng tuần.

Chúng tôi cam kết không spam. Bạn có thể hủy bất cứ lúc nào.