Spring boot+VUE实现token验证的示例代码

 更新时间:2024年10月27日 15:39:03   作者:初夏0811  
本文详细介绍了使用Vue和SpringBoot实现token认证的方法,包括前后端交互流程、后端依赖导入、token工具类、拦截器、跨域处理、前端路由守卫、请求拦截器等内容,具有一定的参考价值,感兴趣的可以了解一下

一、 步骤

Vue+Spring Boot实现token认证主要可分为六步:

1.前端登录,post用户名和密码到后端。

2.后端验证用户名和密码,若通过,生成一个token返回给前端。

3.前端拿到token用vuex和localStorage管理,登录成功进入首页。

4.之后前端每一次权限操作如跳转路由,都需要判断是否存在token,若不存在,跳转至登录页。

5.前端之后的每一个对后端的请求都要在请求头上带上token,后端查看请求头是否有token,拿到token检查是否过期,返回对应状态给前端。(通常失败返回401)

6.若token已过期,清除token信息,跳转至登录页。

二、后端

1.导依赖

<!--        jwt.token要用到的-->
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.4.0</version>
        </dependency>

2.添加token工具类

.withClaim(“Username”, staff.getUsername())
我这个项目没有用户密码,所以我这里只用一个Username,如果有密码的话可以加多一行,比如说:

.withClaim(“Password”, staff.getPassword())

package com.xfish.employeeManagement.token;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.xfish.employeeManagement.pojo.staff;

import java.util.Date;


public class TokenUtil {
    private static final long EXPIRE_TIME= 10*60*60*1000;   //十小时
    private static final String TOKEN_SECRET="123456";  //密钥盐
    /**
     * 签名生成
     * @param staff
     * @return
     */
    public static String sign(staff staff){
        String token = null;
        try {
            Date expiresAt = new Date(System.currentTimeMillis() + EXPIRE_TIME);
            token = JWT.create()
                    .withIssuer("auth0")
                    .withClaim("Username", staff.getUsername())
//                    .withAudience(staff.getUsername())
                    .withExpiresAt(expiresAt)
                    // 使用了HMAC256加密算法。
                    .sign(Algorithm.HMAC256(TOKEN_SECRET));
        } catch (Exception e){
            e.printStackTrace();
        }
        return token;
    }
    /**
     * 签名验证
     * @param token
     * @return
     */
    public static boolean verify(String token){
        try {
            JWTVerifier verifier = JWT.require(Algorithm.HMAC256(TOKEN_SECRET)).withIssuer("auth0").build();
            DecodedJWT jwt = verifier.verify(token);
            System.err.println("认证通过:");
            System.err.println("Username: " + jwt.getClaim("Username").asString());
            System.err.println("过期时间:      " + jwt.getExpiresAt());
            return true;
        } catch (Exception e){
            return false;
        }
    }
}

3.添加拦截器

这个拦截器主要的功能就是,把一些没有token的请求拦截下来并返回错误信息,有token就可以直接通过

package com.xfish.employeeManagement.Interceptor;
import com.alibaba.fastjson.JSONObject;
import com.xfish.employeeManagement.token.TokenUtil;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


@Component
public class TokenInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,Object handler)throws Exception{
        if(request.getMethod().equals("OPTIONS")){
            response.setStatus(HttpServletResponse.SC_OK);
            return true;
        }
        response.setCharacterEncoding("utf-8");
        String token = request.getHeader("token"); //前端vue将token添加在请求头中
//        System.err.println(request.getHeader());
        if(token != null){
            boolean result = TokenUtil.verify(token);
            if(result){
                System.out.println("通过拦截器");
                return true;
            }
        }
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        try{
            JSONObject json = new JSONObject();
            json.put("msg","token verify fail");
            json.put("code","50000");
            response.getWriter().append(json.toJSONString());
            System.out.println("认证失败,未通过拦截器");

        }catch (Exception e){
            e.printStackTrace();
            response.sendError(500);
            return false;
        }
        return false;
    }
}

4.配置跨域,并处理请求

注意:这边拦截的是后端的接口,不是前端的,

在中’ /** ‘无论是restful的,还是后面有一大长串地址都可以识别到

excludePath.add(“/toLogin/**”);

package com.xfish.employeeManagement.config;
import com.xfish.employeeManagement.Interceptor.TokenInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ConcurrentTaskExecutor;
import org.springframework.web.servlet.config.annotation.AsyncSupportConfigurer;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    /**
     * 开启跨域
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        // 设置允许跨域的路由
        registry.addMapping("/**")
                // 设置允许跨域请求的域名
                .allowedOriginPatterns("*")
//                 设置允许的方法
                .allowedMethods("GET","HEAD","POST","PUT","DELETE","OPTIONS")
                // 是否允许携带cookie参数
                .allowCredentials(true)
                // 设置允许的方法
                .allowedMethods("*")
                // 跨域允许时间
                .maxAge(4600);
    }


    private TokenInterceptor tokenInterceptor;
    //构造方法
    public WebMvcConfig(TokenInterceptor tokenInterceptor){
        this.tokenInterceptor = tokenInterceptor;
    }

    @Override
    public void configureAsyncSupport(AsyncSupportConfigurer configurer){
        configurer.setTaskExecutor(new ConcurrentTaskExecutor(Executors.newFixedThreadPool(3)));
        configurer.setDefaultTimeout(30000);
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        List<String> excludePath = new ArrayList<>();
        //排除拦截,除了注册登录(此时还没token),其他都拦截
//        excludePath.add("");  //登录
        excludePath.add("/toLogin/**");  //登录
//        excludePath.add("/admin/login");     //注册
//        excludePath.add("/**");
        excludePath.add("/img/**");  //静态资源
        excludePath.add("/song/**");  //静态资源

        registry.addInterceptor(tokenInterceptor)
                .addPathPatterns("/**")
                .excludePathPatterns(excludePath);
        WebMvcConfigurer.super.addInterceptors(registry);
    }

}

5.登录接口

@GetMapping("/toLogin/{username}")
    public Object toLogin(@PathVariable("username") String username){
        staff staff = staffService.queryStaffDataByName(username);
        JSONObject jsonObject = new JSONObject();
        if(staff!=null){
            String token = TokenUtil.sign(staff);
            jsonObject.put("token",token);
            jsonObject.put("staff",staff);
            jsonObject.put("msg","登录成功");
            jsonObject.put("code",200);
        }else {
            jsonObject.put("msg","账号或密码错误");
            jsonObject.put("code",500);
        }
        return jsonObject;
    }

三、前端

1.main.js配置

添加路由前置守卫beforeEach拦截请求,2.在axios中添加请求拦截器:

//路由全局前置守卫
router.beforeEach((to,from,next) => {
  // if(to.path === '/register' || to.path === '/login' || to.path === '/'){ //若是进入登录与注册页面 ==> pass
    if(to.path === '/register' || to.path === '' || to.path === '/'){
    next()
  }else{ 
    let userToken = localStorage.getItem('token');
    // console.log("Token为:"+userToken); 
    if(userToken == null || userToken == ''){
      alert("无权限,请先登录!");
      return next('/');
    }else{
      next();
    }
  }
}),


//请求拦截器 在请求头中加token
axios.interceptors.request.use(
    config => { // 将获取到的token设置给header中的token
        if(localStorage.getItem('token')){
            config.headers.token = localStorage.getItem('token');
        }
        return config;
    },
    error => {
        return Promise.reject(error);
    }
)

2.配置Vuex

在配置前记得一定要下载Vuex的依赖

cnpm install vuex --save

vuex的使用方式(可以不看)

store/index.js

import Vue from 'vue'
import Vuex from 'vuex'
 
 Vue.use(Vuex)
 
export default new Vuex.Store({
  state: {
      user: localStorage.getItem('staff') ? localStorage.getItem('staff') : null,
      //若localSorage存在token,将值赋给Vuex.state.token
      token: localStorage.getItem('token') ? localStorage.getItem('token') : null
  },
  mutations: {
      setUsername(state, staff) {
          state.staff = staff
          // JSON.stringify(ary)
          //将staff存成JSON格式
          localStorage.setItem('staff', JSON.stringify(staff))
          
      },
      setToken(state, token) {
          localStorage.setItem('token', token)
          state.token = token
      },
       //我页面中写了退出登录的按钮所以补了一个logout用来清空localStorage中的数据
      logout(state) {
          localStorage.removeItem('token')
          state.token = null
          localStorage.removeItem('staff')
          state.setUsername = null
           //我写的RSA加密需向后端获取公钥,为了方便我在拿到公钥后直接存入localStorage中,所以在这里也要清空
          localStorage.removeItem('publickey')
          state.publickey=null
          
      }
  }
})

3.登录方法

记得一定要导包

import store from ‘…/store/index.js’

import store from '../store/index.js'
    export default {
       data() {
         return {
           ruleForm: {     pass: '',    username: ''},
           staff:null,
        }
    },
       methods: {
}
submitForm() {
            var vm=this;
            vm.axios.get('http://localhost:8090/toLogin/'+this.ruleForm.username+''
            ).then(function (response) {
                console.log(response.data.staff)
                if(response.data.code == 200){//将token和user保存到localStorage中
                       store.commit('setToken',response.data.token)
                       store.commit('setUsername',response.data.staff)
                       //跳转到登录成功后的页面
                       console.log("========"+response.data.msg)
                       vm.$router.push('/index')
                       //获取本地存储中的staff
                       vm.staff=JSON.parse(localStorage.getItem('staff'))
                       console.log(vm.staff);
                       }
                       else{
                         alert(response.data.msg)
                            }    
            }).catch(function (e) {
                console.log(e)
                })
         }

4.退出登录

退出登录方法,记得一定要导包

import store from ‘…/store/index.js’

 loginOut(){
          store.commit('logout')  
      }

Spring boot+VUE为什么不用session,
因为session是存在与服务器的,跨域session是会变的。

到此这篇关于Spring boot+VUE实现token验证的示例代码的文章就介绍到这了,更多相关Spring boot VUE token验证内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 基于Feign使用okhttp的填坑之旅

    基于Feign使用okhttp的填坑之旅

    这篇文章主要介绍了基于Feign使用okhttp的填坑之旅,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-02-02
  • CompletableFuture创建及功能使用全面详解

    CompletableFuture创建及功能使用全面详解

    这篇文章主要为大家介绍了CompletableFuture创建及功能使用全面详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-07-07
  • Java timezone设置和mybatis连接数据库时区设置方式

    Java timezone设置和mybatis连接数据库时区设置方式

    这篇文章主要介绍了Java timezone设置和mybatis连接数据库时区设置方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-09-09
  • SpringBoot redis分布式缓存实现过程解析

    SpringBoot redis分布式缓存实现过程解析

    这篇文章主要介绍了SpringBoot redis分布式缓存实现过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-10-10
  • Java 通过手写分布式雪花SnowFlake生成ID方法详解

    Java 通过手写分布式雪花SnowFlake生成ID方法详解

    SnowFlake是twitter公司内部分布式项目采用的ID生成算法,开源后广受国内大厂的好评。由这种算法生成的ID,我们就叫做SnowFlakeID,下面我们来详细看看
    2022-04-04
  • Java多线程ForkJoinPool实例详解

    Java多线程ForkJoinPool实例详解

    这篇文章主要介绍了Java多线程ForkJoinPool实例详解,涉及forkjoin框架的相关内容,需要的朋友可以参考下。
    2017-09-09
  • 带你轻松了解Modbus协议

    带你轻松了解Modbus协议

    这篇文章主要给大家介绍了关于Modbus协议的相关资料,此协议定义了一个控制器能认识使用的消息结构,而不管它们是经过何种网络进行通信的,需要的朋友可以参考下
    2021-11-11
  • java 线程公平锁与非公平锁详解及实例代码

    java 线程公平锁与非公平锁详解及实例代码

    这篇文章主要介绍了java 线程公平锁与非公平锁详解及实例代码的相关资料,需要的朋友可以参考下
    2017-02-02
  • 使用gRPC微服务的内部通信优化

    使用gRPC微服务的内部通信优化

    这篇文章主要为大家介绍了微服务优化之使用gRPC做微服务的内部通信,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步
    2022-03-03
  • Java实现FTP文件的上传和下载功能的实例代码

    Java实现FTP文件的上传和下载功能的实例代码

    FTP 是File Transfer Protocol(文件传输协议)的英文简称,而中文简称为“文传协议”。接下来通过本文给大家实例讲解Java实现FTP文件的上传和下载功能,需要的的朋友一起看看吧
    2016-11-11

最新评论