首页 > 其他分享 >简易Token认证系统实现指南(Spring Boot - Vue)

简易Token认证系统实现指南(Spring Boot - Vue)

时间:2024-07-12 20:31:12浏览次数:14  
标签:account Vue Spring refs Token router import password

在现代Web应用中,用户认证是一个不可或缺的部分。除了传统的会话/cookie认证方式,Token认证提供了一种无状态、可扩展的认证机制。在本文中,我将向您展示如何在一个Spring Boot应用中实现一个简易的Token认证系统 

什么是Token认证?

Token认证是一种安全机制,通常使用JSON Web Tokens (JWT) 来实现。服务器对用户凭证进行验证后,生成一个包含用户信息和有效期限的Token,随后客户端需要在每个请求中携带这个Token以验证用户身份。

为什么选择Token认证?
  • 无状态:服务器不需要存储会话信息,易于扩展。
  • 跨域:Token可以轻松地在不同域名的服务间传递。
  • 安全性:JWTs可以被签名和验证,确保数据未被篡改。
实现步骤
  1. 添加依赖:在Spring Boot项目的pom.xml中添加Spring Security和JWT的依赖项。

  2. 配置Spring Security:创建一个配置类来配置Spring Security,禁用CSRF保护,并设置无状态会话。

  3. 创建Token工具类:编写一个工具类来生成和解析JWT。

  4. 实现登录逻辑:创建一个登录控制器,接收用户名和密码,验证后返回Token。

  5. 手动验证Token:在需要保护的API中手动验证Token。

示例代码

以下是一些关键代码片段,展示了如何实现上述步骤。

后端
1. 添加依赖
<!-- pom.xml -->
<dependencies>
    <!-- Spring Boot Starter Security -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <!-- JWT -->
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt</artifactId>
        <version>0.9.1</version> <!-- 请检查最新版本 -->
    </dependency>
    <dependency>
        <groupId>javax.xml.bind</groupId>
        <artifactId>jaxb-api</artifactId>
        <version>2.3.1</version>
    </dependency>
</dependencies>
2. Token工具类
package com.example.javaee.config;

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

import java.util.Date;

public class JwtUtil {
    private static final String SECRET_KEY = "your_secret_key";

    public static String generateToken(String username) {
        return Jwts.builder()
                .setSubject(username)
                .setIssuedAt(new Date(System.currentTimeMillis()))
                .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10))                 
                 // 10 hours
                .signWith(SignatureAlgorithm.HS256, SECRET_KEY)
                .compact();
    }

}
3. 实现登录逻辑
import com.example.javaee.entity.User;
import com.example.javaee.entity.Response;
import com.example.javaee.mapper.UserMapper;

// 其他导入...

public class UserService {
    private UserMapper userMapper; // 假设已注入UserMapper

    public Response login(String account, String password) {
        User existingUser = userMapper.findByUsername(account);
        if (existingUser != null && existingUser.checkPassword(password)) {
            String token = JwtUtil.generateToken(account); // 生成Token
            String permission = existingUser.getPermission();
            return new Response("登录成功", token, permission);
        }
        return new Response("登录失败", null, null);
    }
}
前端
1.router/index.js
import Vue from 'vue';
import Router from 'vue-router';
import Home from '../components/Home.vue';
import Login from '../components/Login.vue';
// 导入其他页面组件,例如 activitypost、superadmin 等

Vue.use(Router);

// 定义路由配置
const routes = [
  {
    path: '/',
    redirect: '/home',
  },
  {
    path: '/home',
    name: 'Home',
    component: Home,
    meta: { requiresAuth: false },
  },
  {
    path: '/login',
    name: 'Login',
    component: Login,
    meta: { requiresAuth: false },
  },
  // 示例一个受保护的路由
  {
    path: '/activitypost',
    name: 'activitypost',
    component: () => import('../components/activitypost.vue'),
    meta: { requiresAuth: true },
  },
  // ...其他受保护的路由配置
];

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


router.beforeEach((to, from, next) => {
  const hasToken = localStorage.getItem(TOKEN_KEY);
  if (to.matched.some(record => record.meta.requiresAuth)) {
    if (hasToken) {
      next(); // 有Token,允许进入受保护的路由
    } else {
      next({ path: '/login', query: { redirect: to.fullPath } }); // 无Token,重定向到登录页,并附带redirect查询参数
    }
  } else {
    next(); // 公共路由,直接放行
  }
});

export default router;
2.Login.vue
<template>
  <div id="login">

    <div class="me-login-box me-login-box-radius">
      <h1>登录界面</h1>

      <el-form ref="userForm" :model="userForm" :rules="rules">
        <el-form-item prop="account">
          <div class="my-form1">
            <img src="../assets/img/user.png" id="user-img">
            <input class="my-input" placeholder="用户名" v-model="userForm.account" ref="account" />
          </div>
        </el-form-item>

        <el-form-item prop="password">
          <div class="my-form1">
            <img src="../assets/img/lock.png" id="password-img">
            <input class="my-input" placeholder="密码" type="password" v-model="userForm.password" ref="password"
              @keyup="onHCapitalize($event)" />
            <img src="../assets/img/eyesclosed.png" id="eyes-img" ref="eyes" @click="show()">
          </div>
        </el-form-item>

        <el-form-item size="small" class="me-login-button">
          <el-button type="primary" @click.native.prevent="login('userForm')">登录</el-button>
        </el-form-item>
      </el-form>
    </div>
  </div>
</template>

<script>
import { login } from '../api/api'
import { TOKEN_KEY } from '../router/index'
export default {
  name: 'Login',
  data() {
    return {
      userForm: {
        account: '',
        password: ''
      },
      rules: {
        account: [
          { required: true, message: '用户名不能为空' }
        ],
        password: [
          { required: true, message: '密码不能为空' },
          { min: 6, message: 'password must be at least 6 characters' }
        ]
      },
      flag: 'false',
      bigChar: 'false'
    }
  },

  methods: {
    login(formName) {
      let that = this;
      this.$refs[formName].validate((valid) => {
        if (valid) {
          if (this.userForm.account.trim() !== "" && this.userForm.password.trim() !== "") {
            let params = new URLSearchParams();
            params.append('account', this.userForm.account);
            params.append('password', this.userForm.password);

            login(params)
              .then(function (response) {
                if (response.data.message === '登录成功') {
                  const token = response.data.token;
                  // 存储 Token 到 localStorage
                  localStorage.setItem('authToken', token);
                  // 根据返回的权限进行路由跳转
                  switch (response.data.permission) {
                    case '超级管理员':
                      that.$router.push({ name: 'superadmin' });
                      break;
                    case '普通管理员':
                      that.$router.push({ name: 'admin' });
                      break;
                    case '注册用户':
                      that.$router.push({ name: 'user' });
                      break;
                    default:
                      console.error('未知权限');
                  }
                } else if (responseData.message === '登录失败') {
                  console.error('登录失败,用户名不存在或者密码错误');
                }
              })
              .catch(function (error) {
                console.error(error);
              });
          } else {
            // 验证账号密码是否为空,并设置输入框边框颜色
            if (this.userForm.account.trim() === "") {
              this.$refs.account.style.borderColor = "red";
            } else {
              this.$refs.account.style.borderColor = "#797979";
            }

            if (this.userForm.password.trim() === "") {
              this.$refs.password.style.borderColor = "red";
            } else {
              this.$refs.password.style.borderColor = "#797979";
            }
            return false;
          }
        }
      });
    },
    show() {
      if (this.flag) {
        this.$refs.eyes.src = "../../static/img/eyes.png";
        this.$refs.password.setAttribute("type", "text");
      } else {
        this.$refs.eyes.src = "../../static/img/eyesclosed.png";
        this.$refs.password.setAttribute("type", "password");
      }
      this.flag = !this.flag;
    },
  }
}
</script>

<style>
/* 您的样式 */
</style>
测试和调试

在实现Token认证后,进行充分的测试是非常重要的。确保在各种情况下Token都能正确生成、验证和失效。

1.当登录成功后,查看控制台是否成功打印Token,并进行路由跳转。

2.删除Token,看看是否还能直接访问页面,如果不能,则说明已经成功。删除Token的方法如图:F12打开控制台后进行如下操作

结论

Token认证是一种强大且灵活的用户认证方式。通过本指南,本人进行了Token最简易最初步的实现,后续继续提高!

标签:account,Vue,Spring,refs,Token,router,import,password
From: https://blog.csdn.net/m0_63254505/article/details/140337659

相关文章

  • 计算机Java项目|基于SpringBoot的学生选课系统的设计与实现
    作者主页:编程指南针作者简介:Java领域优质创作者、CSDN博客专家、CSDN内容合伙人、掘金特邀作者、阿里云博客专家、51CTO特邀作者、多年架构师设计经验、腾讯课堂常驻讲师主要内容:Java项目、Python项目、前端项目、人工智能与大数据、简历模板、学习资料、面试题库、技术互......
  • 计算机Java项目|基于SpringBoot的企业人事管理系统
    作者主页:编程指南针作者简介:Java领域优质创作者、CSDN博客专家、CSDN内容合伙人、掘金特邀作者、阿里云博客专家、51CTO特邀作者、多年架构师设计经验、腾讯课堂常驻讲师主要内容:Java项目、Python项目、前端项目、人工智能与大数据、简历模板、学习资料、面试题库、技术互......
  • 【后端 · 初学】使用IDEA新建一个Springboot项目
    1【newproject】=》【Springboot】=》配置项目的名称和存放位置,type选择【maven】。选择jdk,最好大于等于17.2选择需要的依赖,本项目使用mybatis-plus,所以不需要添加mybatis的依赖。选择完成点击create即可。3修改pom.xml,下面是一份验证过没有问题的依赖配置。由于......
  • springboot
    一,什么是springbootSpringBoot是开发者和Spring本身框架的中间层,帮助开发者统筹管理应用的配置,提供基于实际开发中常见配置的默认处理(即习惯优于配置),简化应用的开发,简化应用的运维;总的来说,其目的SpringBoot就是为了对Javaweb的开发进行“简化”和加“快”速度,简化开发过......
  • SpringBoot整合mybatis-plus
    1.什么是mybatis-plus?mybatis-plus是一个mybatis的增强工具,在mybatis的基本上只做增强不做改变,为简化开发,提高效率而生。2.特点:3.如何使用?添加mybatis-plus依赖<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-bo......
  • 适合小白学校的springboot2 vue3 图书管理系统idea开发mysql数据库
    博主介绍:专注于Java.net phpphython 小程序等诸多技术领域和毕业项目实战、企业信息化系统建设,从业十五余年开发设计教学工作☆☆☆精彩专栏推荐订阅☆☆☆☆☆不然下次找不到哟我的博客空间发布了1000+毕设题目方便大家学习使用感兴趣的可以先收藏起来,还有大家在......
  • 【计算机毕业设计】基于Springboot的智能物流管理系统【源码+lw+部署文档】
    包含论文源码的压缩包较大,请私信或者加我的绿色小软件获取免责声明:资料部分来源于合法的互联网渠道收集和整理,部分自己学习积累成果,供大家学习参考与交流。收取的费用仅用于收集和整理资料耗费时间的酬劳。本人尊重原创作者或出版方,资料版权归原作者或出版方所有,本人不对所......
  • 【Springboot】玩转复杂单元测试启动类-只测试数据访问层(JPA+Mybatis) 和服务层 以及
    上一篇文章写了一个最复杂的SpringBootTest启动类,定制化程序奇高,然而有时候仅测试JPA是不够的。启动类需求:测试SpringDataJPA测试Mybatis从容器中获得ObjectMapper测试单独的Service使用TestNG或者使用Junit阻止Dubbo、Kafka、ElasticSearch等中间件启动使用appl......
  • Springboot按天生成日志文件
    原文链接:https://blog.csdn.net/weixin_47798667/article/details/131846942 1:首先再yml文件上加上配置 logging: config:classpath:logback-spring.xml2:新建一个logback-spring.xml文件 文件内容是如下 <?xmlversion="1.0"encoding="UTF-8"?>......
  • 用Vue3和Plotly.js实现3D小提琴图的交互式可视化
    本文由ScriptEcho平台提供技术支持项目地址:传送门小提琴图:绘制性别账单分布应用场景小提琴图是一种数据可视化工具,用于比较不同组别的分布。它结合了箱线图和核密度估计,可以直观地展示数据的中心趋势、离散度和分布形状。小提琴图常用于比较不同性别、年龄组或其他类别......