springboot+vue结合redis实现登录拦截

springboot+vue结合redis实现登录拦截

1.后端代码

1.1pom.xml依赖

redis依赖

		
			org.springframework.boot
			spring-boot-starter-data-redis
		

mysql依赖

		
			mysql
			mysql-connector-java
			8.0.33
		

jwt依赖

		
			com.auth0
			java-jwt
			3.8.3
		

完整pom.xml依赖



	4.0.0
	
		org.springframework.boot
		spring-boot-starter-parent
		2.7.15
		 
	
	com.example
	vuesb
	0.0.1-SNAPSHOT
	vuesb
	vuesb
	
		1.8
	
	
		
			org.springframework.boot
			spring-boot-starter-web
		
		
			com.auth0
			java-jwt
			3.8.3
		

		
			mysql
			mysql-connector-java
			8.0.33
		
		
			org.springframework.boot
			spring-boot-starter-data-redis
		
	

	
		
			
				org.springframework.boot
				spring-boot-maven-plugin
			
		
	


1.2后端jwt拦截器

1.2.1 Interceptor拦截器配置(入口拦截)

因为我前端的url为本机8080端口,所以在allowedOrigins这里我把允许的跨域请求设置为了我的前端端口,这里也可以写为

registry.addMapping("/**")
                .allowedOrigins("*")
                .allowCredentials(true)
                .allowedMethods("GET", "POST", "DELETE", "PUT", "PATCH", "OPTIONS", "HEAD")
                .maxAge(3600 * 24);
package com.example.vuesb.jwt;

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;

public class InterceptorConfig implements WebMvcConfigurer {
    TokenInterceptor tokenInterceptor;
    public InterceptorConfig(TokenInterceptor tokenInterceptor){//构造函数
            this.tokenInterceptor=tokenInterceptor;
        }
        @Override
        public void addInterceptors(InterceptorRegistry registry){//配置拦截器
            ArrayListexcludePath=new ArrayList<>();
            excludePath.add("/login");//登录
            excludePath.add("/logout");//登出
            excludePath.add("/register");//注册
            registry.addInterceptor(tokenInterceptor)//注册拦截器
                    .addPathPatterns("/**")//拦截所有请求
                    .excludePathPatterns(excludePath);//添加拦截白名单
            WebMvcConfigurer.super.addInterceptors(registry);//调用父接口
    }
    @Override
    public void addCorsMappings(CorsRegistry registry){
        registry.addMapping("/**")
                .allowCredentials(true)//允许携带cookie
                .allowedMethods("GET", "POST", "DELETE", "PUT", "PATCH", "OPTIONS", "HEAD")//允许访问的方法
                .allowedOrigins("http://localhost:8080")//允许的跨域访问地址
                .maxAge(3600*24);//options缓存时间
    }
}

1.2.2 JWTUtil

这里的verify方法没什么用,是我在用redis之前写的,可以不加

package com.example.vuesb.jwt;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;

import java.util.Date;


public class JWTUtil {
    private static final long EXPIRE_TIME = 60 * 60 * 1000;
    private static final String tokenPassword = "uziCjb";

    public static String sign(String username) {//用用户名作为被加密的对象
        String token;
        Date expireTime = new Date(System.currentTimeMillis() + EXPIRE_TIME);//过期时间
        token = JWT.create()//生成jwt令牌,加密过程
                .withIssuer("llh")
                .withClaim("username", username)
                .withExpiresAt(expireTime)
                .sign(Algorithm.HMAC256(tokenPassword));
        return token;//返回加密后的token
    }
    public static boolean verify(String token){
        JWTVerifier jwtVerifier=JWT.require(Algorithm.HMAC256(tokenPassword)).withIssuer("llh").build();//构建一个jwt解码器
        DecodedJWT jwtToken=jwtVerifier.verify(token);//解码
        if(token.isEmpty()){//若token为空则返回false拦截
            return false;
        }
        else {
            System.out.println("认证通过:");
            System.out.println("issuer: " + jwtToken.getIssuer());
            System.out.println("username: " + jwtToken.getClaim("username").asString());
            System.out.println("过期时间:      " + jwtToken.getExpiresAt());
            return true;
        }
    }
}

1.2.3TokenInterceptor(token拦截器)

注册服务那里一定要写!!!

package com.example.vuesb.jwt;

import com.example.vuesb.redis.RedisUtil;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


public class TokenInterceptor implements HandlerInterceptor {
    @Resource
    RedisUtil redisUtil;//注册服务

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        String token = request.getHeader("token");
        try {
            if (request.getMethod().equals("OPTIONS")) {//检查是否为跨域请求
                if (token != null) {
                    if (redisUtil.getTokens(token) != null) {
                        response.setStatus(200);//设置状态码为正常
                        return true;
                    } else {
                        response.setStatus(401);//设置状态码为未通过登录验证
                        return false;
                    }
                } else {
                    response.setStatus(401);//设置状态码为未通过登录验证
                    return false;

                }
            }
        } catch (Exception e) {
            response.setStatus(500);
            throw new RuntimeException();
        }
        response.setCharacterEncoding("utf-8");
        try {
            if (token != null) {
                if (redisUtil.getTokens(token) != null) {
                    response.setStatus(200);//设置状态码为正常,即通过登录验证
                    System.out.println("通过拦截器");
                    return true;
                } else {
                    response.setStatus(401);
                    return false;
                }
            } else {
                response.setStatus(401);
                return false;
            }
        } catch (Exception exception) {
            response.setStatus(500);//发生了不可预测的错误
            throw new RuntimeException();
        }


    }
}

1.3redis配置

RedisUtil

package com.example.vuesb.redis;


import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;


@Service
public class RedisUtil {
    @Resource
    private RedisTemplate stringRedisTemplate;//这是一个使用redis的API,可以直接用StringRedisTemplate
    
    public void addTokens(String username, String token) {//存入token
        if (username != null && token != null) {
            System.out.println("参数不为空");
            System.out.println(username);
            System.out.println(token);
            ValueOperations valueOperations = stringRedisTemplate.opsForValue();
            valueOperations.set(username, token, 60, TimeUnit.MINUTES);//设置token过期时间为一小时

        } else {
            System.out.println("参数为空");
        }
    }

    public String getTokens(String username) {//获取token
        return stringRedisTemplate.opsForValue().get(username);
    }

    public void delTokens(String username) {//删除token
        stringRedisTemplate.delete(username);
    }

}

1.4登录接口

数据库这里我是用的原生jdbc

package com.example.vuesb;

import JDBC.VueLogin;
import com.example.vuesb.jwt.JWTUtil;
import com.example.vuesb.redis.RedisUtil;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.sql.ResultSet;
import java.sql.SQLException;

@CrossOrigin
@RestController
public class demo {
    @Resource
    RedisUtil redisUtil;
    @RequestMapping("/login")
    public String loginCheck(@RequestParam("username") String username, @RequestParam("password") String password) throws SQLException {
        String returnStr="No";
        ResultSet resultSet;
        resultSet=new VueLogin().seekAccount(username);
        String sqlPass = null;
        if(resultSet.next()){
            sqlPass=resultSet.getString(1);
            if (sqlPass.equals(password)){
                String token = new JWTUtil().sign(username);

                redisUtil.addTokens(username,token);
                returnStr=token;
            }
        }

        return returnStr;
    }
    @RequestMapping("/register")
    public String register(@RequestParam("username") String username,@RequestParam("password") String password){
        String returnStr="123";
        ResultSet resultSet=new VueLogin().seekAccount(username);
        try {
            if (!resultSet.next()){
                new VueLogin().addRegister(username, password);
                returnStr="OK";
            }
            else {
                returnStr="No";
            }
        } catch (SQLException e) {
            System.out.println("注册失败");
            throw new RuntimeException(e);
        }
        return  returnStr;
    }
}

1.5mysql

package JDBC;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class VueLogin {
    public void addRegister(String username ,String password){
        String sql="insert into vuelogin(username,password)values(?,?)";
        PreparedStatement preparedStatement;
        try {
            preparedStatement=Conn.getConnection().prepareStatement(sql);
            preparedStatement.setString(1,username);
            preparedStatement.setString(2,password);
            preparedStatement.executeUpdate();
            preparedStatement.close();
        } catch (SQLException e) {
            System.out.println("注册失败");
            throw new RuntimeException(e);

        }
    }
    public ResultSet seekAccount(String account){
        String sql="select password from vuelogin where username=?";
        PreparedStatement preparedStatement;
        ResultSet resultSet;
        try {

            preparedStatement= Conn.getConnection().prepareStatement(sql);
            preparedStatement.setString(1,account);
            resultSet=preparedStatement.executeQuery();

            return resultSet;
        } catch (SQLException e) {
            System.out.println("查询失败");
            throw new RuntimeException(e);
        }
    }
}

2.前端代码

2.1 main.js

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import './plugins/element.js'
import './router/permission'
import axiosInstance from './store/request.js'
import axios from 'axios'
Vue.prototype.$http = axios
Vue.config.productionTip = false
// axiosInstance.defaults.baseURL = 'http://localhost:8081'; // 后端端口为8081

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

2.2store/index.js(记得安装vuex)

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    token:localStorage.getItem('token')?localStorage.getItem('token'):''
  },
  getters: {
  },
  mutations: {
    setToken(state,token){
      state.token=token
      localStorage.setItem("token",token.token)//存储token
    },
    delToken(state){
      state.token=''
      localStorage.removeItem("token")//删除token
      
    }
  },
  actions: {
  },
  modules: {
  }
})

2.3路由配置router下index.js

import Vue from 'vue'
import VueRouter from 'vue-router'
import HomeView from '../views/HomeView.vue'
import LayoutView from "../views/LayoutView.vue"
Vue.use(VueRouter)

const routes = [
{
  path:"/",
  name:"LayoutView",
  component:LayoutView,
  children:[
    {
      path: '',
      name: 'home',
      component: HomeView,
      meta:{
        isLogin:true
      }
    },
    {
      path:"params",
      name:"paramsview",
      component:()=>import("../views/main/ParamsView.vue"),
      meta:{
        isLogin:true
      }
    },
    {
      path:"product",
      name:"ProductView",
      component:()=>import("../views/main/ProductView.vue"),
      meta:{
        isLogin:true
      }
    },
    {
      path:"ad",
      name:"ADCategoryview",
      component:()=>import("../views/main/ADCategoryView.vue"),
      meta:{
        isLogin:true
      }
    }
  ]
},
{
  path:"/login",
  name:"LoginView",
  component:()=>import("../views/LoginView.vue")
}
  
  
]

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

export default router

2.4permission路由守护

import router from "./index";
//路由守护
router.beforeEach((to,from,next)=>{
    if(to.meta.isLogin){
        if(to.path==='/login'){
            next()
        }
        else{
            const tokenStr=window.localStorage.getItem('token')
            if(!tokenStr){
                return next('/login')
            }
            else{
                next()
            }
        }
    }
    else{
        next();
    }
})

 2.5设置新的全局axios

在这里需要设置一个新的全局axios,这样可以在每一个ajax请求发出之前将token加入到请求头中

import axios from "axios";


//创建axios实例
const axiosInstance = axios.create({
    baseURL: 'http://localhost:8081', // 设置默认发送地址为后端端口
    });

//添加拦截器,在每次ajax之前都会执行这个操作
axiosInstance.interceptors.request.use(function (config){
    console.log("操作了")
    //从本地缓存获得token
    const token=window.localStorage.getItem('token')
    
    //如果存在将其加入请求头中
    if(token){
        console.log(token)
        config.headers.token = token;
    }
    return config;
},function (error){
    return Promise.reject(error);//发生错误返回一个拒绝的promise对象
})

export default axiosInstance;

2.6loginView(登录业务)

上半部分是elementUI,可以省略





3.成果展示

可以在请求头里看到加上了一个token

springboot+vue结合redis实现登录拦截_第1张图片

你可能感兴趣的:(spring,boot,vue.js)