Spring boot+VUE实现token验证

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

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

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

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

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

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

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

一、添加依赖

 <!--添加jwt 依赖-->
 <!-- maven -->
<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>3.19.1</version>
</dependency>


<!-- gradle -->
implementation group: 'com.auth0', name: 'java-jwt', version: '3.19.1'

二、添加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.lin.springMVC.domain.User;

import java.util.Date;

public class TokenUtil {
    private static final long EXPIRE_TIME= 10*60*60*1000;
    private static final String TOKEN_SECRET="test";  //密钥盐
    /**
     * 签名生成
     * @param user
     * @return
     */
    public static String sign(User user){
        String token = null;
        try {
            Date expiresAt = new Date(System.currentTimeMillis() + EXPIRE_TIME);
            token = JWT.create()
                    .withIssuer("auth0")
                    .withClaim("userAccount", user.getUserAccount())
                    .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.out.println("认证通过:");
            System.out.println("userAccount: " + jwt.getClaim("userAccount").asString());
            System.out.println("过期时间:      " + jwt.getExpiresAt());
            return true;
        } catch (Exception e){
            return false;
        }
    }
}

三、创建拦截器

import com.alibaba.fastjson.JSONObject;
import com.haiyang.utils.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添加在请求头中
        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;
    }
}

四、配置跨域

import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import com.alibaba.fastjson.support.spring.FastJsonJsonView;
import com.haiyang.Interceptor.TokenInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
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 com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
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("*")
                // 是否允许携带cookie参数
                .allowCredentials(true)
                // 设置允许的方法
                .allowedMethods("*")
                // 跨域允许时间
                .maxAge(3600);
    }


    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("/admin/register");  //登录
        excludePath.add("/admin/login");     //注册
        excludePath.add("/img/**");  //静态资源
        excludePath.add("/song/**");  //静态资源

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

}

五、登录接口

@ResponseBody
    @GetMapping("/login")
    public Object login(User user){
        User u = userService.userLogin(user);
        JSONObject jsonObject = new JSONObject();
        if (u != null){
            String token = TokenUtil.sign(u);
            jsonObject.put("token",token);
            jsonObject.put("user",u);
	        jsonObject.put("msg","登录成功");
            jsonObject.put("code",200);
        }else{
        	jsonObject.put("msg","账号或密码错误");
			jsonObject.put("code",500);
		}
        return jsonObject;
    }

六、前端配置

(1)main.js配置

1.添加路由前置守卫beforeEach拦截请求:

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

    //请求拦截器 在请求头中加token
    axios.interceptors.request.use(
        config => {
            if(localStorage.getItem('token')){
                config.headers.token = localStorage.getItem('token');
            }
            return config;
        },
        error => {
            return Promise.reject(error);
        }
    )
    

(2)配置Vuex

const store = new Vuex.Store({
    state: {
        user: localStorage.getItem('user') ? localStorage.getItem('user') : null,
        //若localSorage存在token,将值赋给Vuex.state.token
        token: localStorage.getItem('token') ? localStorage.getItem('token') : null,
    },
    mutations: {
        setUser(state, user) {
            state.user = user
            localStorage.setItem('user', JSON.stringify(user))
        },
        setToken(state, token) {
            localStorage.setItem('token', token)
            state.token = token
        },
        logout(state) {
            localStorage.removeItem('token')
            state.token = null
            localStorage.removeItem('user')
            state.user = null
        }
    }
})

(3)登录方法

login(){
   var vm = this
   vm.axios.get('http://localhost:8080/login',{
     params:{
       username:this.username,
       password:this.password
     }
   }).then(function (response) {
     if(response.data.code == 200){
       console.log(response.data.msg)
       //将token和user保存到localStorage中
       vm.$store.commit('setToken',response.data.token)
       vm.$store.commit('setUser',response.data.user)
       //跳转到登录成功后的页面
       vm.$router.push({path:'/index'})
	 else{
       alert(response.data.msg)
     }
   }).catch(function (e) {
     console.log(e)
   })
 }
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐