【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篇。关注我,跟着学完整系列!)

相关推荐
RFCEO7 分钟前
前端编程 课程十三、:CSS核心基础1:CSS选择器
前端·css·css基础选择器详细教程·css类选择器使用方法·css类选择器命名规范·css后代选择器·精准选中嵌套元素
烬头882131 分钟前
React Native鸿蒙跨平台采用了函数式组件的形式,通过 props 接收分类数据,使用 TouchableOpacity实现了点击交互效果
javascript·react native·react.js·ecmascript·交互·harmonyos
Amumu1213831 分钟前
Vuex介绍
前端·javascript·vue.js
We་ct32 分钟前
LeetCode 54. 螺旋矩阵:两种解法吃透顺时针遍历逻辑
前端·算法·leetcode·矩阵·typescript
2601_9498095944 分钟前
flutter_for_openharmony家庭相册app实战+相册详情实现
javascript·flutter·ajax
qq_177767371 小时前
React Native鸿蒙跨平台通过Animated.Value.interpolate实现滚动距离到动画属性的映射
javascript·react native·react.js·harmonyos
2601_949833391 小时前
flutter_for_openharmony口腔护理app实战+饮食记录实现
android·javascript·flutter
2601_949480061 小时前
【无标题】
开发语言·前端·javascript
css趣多多1 小时前
Vue过滤器
前端·javascript·vue.js
理人综艺好会2 小时前
Web学习之用户认证
前端·学习