【9/10】前端认证整合:Vue.js 中处理 JWT,实现登录页面和受保护路由

标签:前端认证、JWT、Vue.js、登录页面、受保护路由、Axios、入门教程、项目实践

前言

欢迎来到"前后端与数据库交互详解"系列的第9篇文章!在前八篇文章中,我们从Vue.js前端基础,到Express后端API、MongoDB整合,再到JWT认证,构建了一个带安全登录的后端。现在,后端已保护,但前端还需处理:如何登录、存储JWT并安全调用API?

本篇文章的焦点是 前端认证整合,特别是用Vue.js处理JWT,实现登录页面和受保护路由。我们将解释前端认证流程、JWT存储,并在结尾扩展第七/八篇的项目:添加Vue登录组件、路由守卫,只有认证用户才能访问用户管理系统(CRUD界面)。这将形成一个完整的full-stack认证应用。未来,我们将引入状态管理。

前提:您已安装Vue CLI和Axios(从前文)。我们用Vue Router(第二篇)实现路由保护,localStorage存储JWT(简单入门;生产用更安全方式)。后端基于第八篇运行。

一、前端认证是什么?

前端认证是处理用户身份验证的客户端逻辑:发送登录请求、存储令牌,并在后续API调用中附加令牌。如果令牌无效,重定向到登录页。

  • 为什么前端认证?

    • 用户体验:无缝登录/注销,保护私有页面。
    • 与后端协作:前端发送JWT,后端验证(第八篇)。
    • JWT 在前端:存储在localStorage或cookie,Axios自动附加到header。
    • 对比其他:Session需服务器状态;JWT无状态,适合SPA(如Vue)。
    • 安全考虑:避免XSS,设置HttpOnly cookie(高级);我们用localStorage入门。
    • 在Vue中的作用:用组件处理表单,路由守卫检查认证。
  • 核心概念

    • 登录流程:POST /api/login,存储res.data.token。
    • 拦截器:Axios.interceptors.request添加Authorization: Bearer 。
    • 路由保护:Vue Router的beforeEach检查localStorage。
    • 注销:清除存储,重定向。
    • 错误处理:捕获401(未授权),跳转登录。

在我们的系列中,这是认证的最后一环:前后端完整闭环。

二、前端认证的基本使用

  1. 登录组件:表单v-model绑定,Axios.post发送。
  2. JWT存储:localStorage.setItem('token', token)。
  3. 请求拦截:Axios配置自动加header。
  4. 路由守卫:router.beforeEach((to, from, next) => { if (to.meta.requiresAuth && !token) next('/login'); })。

示例:登录后 localStorage.setItem('token', res.data.token); this.$router.push('/dashboard');

接下来,通过项目实践这些。

三、实现完整项目:带前端认证的用户管理系统

项目目标:扩展第七篇的Vue前端和第八篇的Express后端,添加登录页面、JWT处理和路由保护。只有登录用户才能访问CRUD界面(用户列表/添加/编辑/删除)。这是一个独立的完整full-stack应用,可以运行前后端,测试认证流。

步骤 1: 前端准备(扩展Vue项目)

基于第七篇的Vue项目(user-manager-vue),安装Vue Router(如果未):vue add router。更新依赖:确保Axios安装。

步骤 2: 配置Axios拦截器和路由

src/main.js中添加:

javascript 复制代码
import Vue from 'vue';
import App from './App.vue';
import router from './router';
import axios from 'axios';

// Axios 全局配置
axios.defaults.baseURL = 'http://localhost:3000/api'; // 后端API基础URL

// 请求拦截器:添加JWT
axios.interceptors.request.use(config => {
  const token = localStorage.getItem('token');
  if (token) {
    config.headers.Authorization = `Bearer ${token}`;
  }
  return config;
}, error => Promise.reject(error));

// 响应拦截器:处理401
axios.interceptors.response.use(response => response, error => {
  if (error.response.status === 401) {
    localStorage.removeItem('token');
    router.push('/login');
  }
  return Promise.reject(error);
});

Vue.config.productionTip = false;

new Vue({
  router,
  render: h => h(App)
}).$mount('#app');

src/router/index.js中配置路由和守卫:

javascript 复制代码
import Vue from 'vue';
import VueRouter from 'vue-router';
import Login from '../components/Login.vue'; // 新组件
import UserManager from '../components/UserManager.vue'; // 从第七篇

Vue.use(VueRouter);

const routes = [
  { path: '/', redirect: '/login' },
  { path: '/login', name: 'Login', component: Login },
  { path: '/users', name: 'Users', component: UserManager, meta: { requiresAuth: true } }
];

const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes
});

// 路由守卫
router.beforeEach((to, from, next) => {
  const token = localStorage.getItem('token');
  if (to.meta.requiresAuth && !token) {
    next('/login');
  } else {
    next();
  }
});

export default router;

步骤 3: 创建登录组件

新建src/components/Login.vue

vue 复制代码
<template>
  <div>
    <h1>登录</h1>
    <form @submit.prevent="login">
      <input v-model="username" placeholder="Username" required />
      <input v-model="password" type="password" placeholder="Password" required />
      <button type="submit">登录</button>
    </form>
    <p v-if="error">{{ error }}</p>
  </div>
</template>

<script>
import axios from 'axios';

export default {
  data() {
    return {
      username: '',
      password: '',
      error: ''
    };
  },
  methods: {
    async login() {
      try {
        const res = await axios.post('/login', { username: this.username, password: this.password });
        localStorage.setItem('token', res.data.token);
        this.$router.push('/users');
      } catch (err) {
        this.error = '登录失败:' + (err.response?.data?.error || '未知错误');
      }
    }
  }
};
</script>
  • 解释:POST到/api/login,存储token,重定向到/users(CRUD页面)。

更新第七篇的UserManager.vue:无需大改,但确保API调用用Axios(拦截器会自动加token)。

App.vue中用<router-view />渲染路由。

步骤 4: 运行和测试

  • 后端:运行第八篇的node server.js(localhost:3000)。
  • 前端:npm run serve(localhost:8080)。
  • 测试:访问/,重定向到/login;输入第八篇注册的凭证(e.g., username: "test", password: "123456"),登录后跳转到/users,CRUD操作成功(token附加);注销(可选添加按钮:localStorage.removeItem('token'); this.$router.push('/login'););无token访问/users,重定向登录。
  • 这是一个完整的带认证full-stack应用!前后端协作,实现安全CRUD。

步骤 5: 扩展(可选)

  • 注册页面:类似登录,POST /api/register。
  • 自动续期:检查token过期,刷新。
  • UI库:用Element UI美化表单。

四、常见问题与调试

  • 401错误?检查token存储、拦截器;后端密钥匹配。
  • 路由不跳转?验证守卫逻辑,console.log(token)。
  • CORS?后端已启用(第八篇),但检查header。
  • 安全?localStorage易XSS;生产用cookie或Vuex+secure storage。

总结

通过本篇,您学会了前端认证整合,用Vue.js处理JWT,实现登录和路由保护。带认证的用户管理系统证明了完整认证流,形成独立的full-stack项目。

下一篇文章:状态管理基础:Vuex 在 Vue.js 中的应用,实现全局用户状态。我们将用Vuex管理认证状态,提升应用可扩展性。如果有疑问,欢迎评论!

(系列导航:这是第9/20篇。关注我,跟着学完整系列!)

相关推荐
donecoding6 分钟前
前端AI开发:为什么选择SSE,它与分块传输编码有何不同?axios能处理SSE吗?
前端·人工智能
安_11 分钟前
<style scoped>跟<style>有什么区别
前端·vue
姝然_952712 分钟前
Claude Code 命令完整文档
前端
wjcroom12 分钟前
web版进销存的设计到实现一
前端
无知的前端15 分钟前
Flutter常见问题以及解决方案
前端·flutter·dart
BD_Marathon27 分钟前
Vue3_Vite构建工程化前端项目
前端
武清伯MVP28 分钟前
CSS Grid布局全解析:从基础到实战的二维布局方案
前端·css·grid
xfq34 分钟前
typescript泛型枚举以及NaN传染处理
前端·typescript
ErMao34 分钟前
开始搭建第一个React项目吧~
前端·react.js
郑州光合科技余经理34 分钟前
实战:攻克海外版同城生活服务平台开发五大挑战
java·开发语言·javascript·数据库·git·php·生活