学习springboot+vue笔记十二--springboot集成jwt以及常见的坑

项目架构参见之前的笔记。

集成JWT

1、增加jwt依赖

<!--        JWT依赖-->
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.10.3</version>
        </dependency>

2、新建生成token的类和方法及可能遇见的坑

编写jwt的生成token类,

package com.zhuoaninfo.vueDemo.common;
import cn.hutool.core.date.DateUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import java.util.Date;
public class TokenUtil {
    public static String genToken(String uid,String pwd){
       return JWT.create().withAudience(uid)
                .withExpiresAt(DateUtil.offsetHour(new Date(),2)) //2小时候过期
                .sign(Algorithm.HMAC256(pwd));
    }
}

上面的代码容易出现的坑,JWT可能会导错,hutool依赖中也有一个JWT的类,如果这里的JWT导错包,则.withAudience就会报错。

3、把TOKEN应用于登录方法

给userdto增加token属性

package com.zhuoaninfo.vueDemo.dto;
import cn.hutool.core.annotation.Alias;
import lombok.Data;
@Data
public class UserDto {
    @Alias("用户名")
    String username;
    @Alias("密码")
    String password;
    private String awata;
    private String token;
}

给userSerice中的login方法增加token

package com.zhuoaninfo.vueDemo.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.log.Log;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zhuoaninfo.vueDemo.common.Contants;
import com.zhuoaninfo.vueDemo.common.TokenUtil;
import com.zhuoaninfo.vueDemo.common.exception.ServiceException;
import com.zhuoaninfo.vueDemo.dto.UserDto;
import com.zhuoaninfo.vueDemo.entity.User;
import com.zhuoaninfo.vueDemo.mapper.UserMapper;
import com.zhuoaninfo.vueDemo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService{
    private static final Log LOG = Log.get();
    public UserDto login(UserDto userDto){
        QueryWrapper<User> query = new QueryWrapper<>();
        query.eq("name", userDto.getUsername());
        query.eq("password", userDto.getPassword());
        User one;
        try{
             one=getOne(query);
        }catch (Exception e){
        LOG.error("");
        throw new ServiceException(Contants.Code_500,"系统错误");
        }
        if(one!=null){
            BeanUtil.copyProperties(one, userDto,true);
            String s = TokenUtil.genToken(one.getId().toString(), one.getPassword());
            userDto.setToken(s);
            return userDto;
        }else{
            throw new ServiceException(Contants.Code_400,"用户名或密码错误");
        }
    }
    @Override
    public User register(UserDto vo) {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("name",vo.getUsername());
        wrapper.eq("password",vo.getPassword());
        User one = getOne(wrapper);
        if(one == null){
           one= new User();
           BeanUtil.copyProperties(vo,one,true);
           save(one);
        }else {
            throw new ServiceException(Contants.Code_401,"用户已存在");
        }
        return one;
    }
}

现在登录返回的数据里面已经有了token属性和值。

4、新建增加拦截器

新建JwtInterceptor类,该类可以自定义名称。代码如下:

package com.zhuoaninfo.vueDemo.common.interceptor;

import cn.hutool.core.util.StrUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.zhuoaninfo.vueDemo.common.Contants;
import com.zhuoaninfo.vueDemo.common.exception.ServiceException;
import com.zhuoaninfo.vueDemo.entity.User;
import com.zhuoaninfo.vueDemo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class JwtInterceptor implements HandlerInterceptor {
    @Resource
   private UserService userService;
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String token = request.getHeader("token");
        //如果不是方法类,则可以放行
        if(!(handler instanceof HandlerMethod)){
            return true;
        }
        //验证token是否为空
        if(StrUtil.isBlank(token)){
            throw new ServiceException(Contants.Code_401,"无TOKEN");
        }
        String uid;
        try{
             //获取token中的用户信息
            uid= JWT.decode(token).getAudience().get(0);
        }catch (JWTDecodeException e){
            throw new ServiceException(Contants.Code_401,"token用户信息验证失败");
        }
        User user=userService.getById(Integer.parseInt(uid));
        if(null==user){
            throw new ServiceException(Contants.Code_401,"用户不存在,请重新登录");
        }
        JWTVerifier jwtVerifier=JWT.require(Algorithm.HMAC256(user.getPassword())).build();
        try{
            jwtVerifier.verify(token);
        }catch(JWTVerificationException e){
            throw new RuntimeException("token加密信息验证失败");
        }
        return true;
    }
}

这里的 JWT.require(Algorithm.HMAC256(user.getPassword())).build()中HMAC256和对应生产类中的加密必须一致,否则会报错,无法进行token验证。导入的包比较多,今天导入的还比较顺利,没有错,如果代码有错的话,请先检查导入的包。

5、注册拦截器到项目中

新建InterceptorConfig类,名称可以自定义

package com.zhuoaninfo.vueDemo.config;

import com.zhuoaninfo.vueDemo.common.interceptor.JwtInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(jwtInterceptor())
                .addPathPatterns("/**")  //拦截所有请求
                .excludePathPatterns("/**/login","/**/register"); //放行路径
    }
    @Bean
    public JwtInterceptor jwtInterceptor(){
        return new JwtInterceptor();
    }
}

这里容易出现的坑是,@Configuration和 @Bean注释有时候会漏掉,项目编译不报错,但使用中userService会出现null,没有实现自定加载的问题,无法完成用户查询,导致无法进行数据查询。
后端的文件架构为:
在这里插入图片描述

6、前端增加配置token

前端的request.js把config代码处增加token,代码如下:

import axios from "axios"; 
const request=axios.create({
    // baseURL:'/api',
    baseURL:'http://localhost:8181',
    timeout:5000
})
// request拦截器
// 可以自请求发送前对请求做一些处理
// 比如同意加token,对请求参数统一加密
request.interceptors.request.use(config=>{
    config.headers['Content-Type']='application/json;charset=utf-8';
   let user=localStorage.getItem("user")?JSON.parse(localStorage.getItem("user")):{}
   if(user){
    config.headers['token']=user.token;
   }
    return config
},error=>{
    return Promise.reject(error)
}
);
request.interceptors.response.use(
    response=>{
        let res=response.data;
        if(response.config.responseType=='blob'){
            return res
        }
        if(typeof res ==='string'){
            res=res?JSON.parse(res):res
        }
        return res;
    },error=>{
        console.log(error);
        return Promise.reject(error);
    }
)
export default request

前后端集成jwt完成。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cngm110

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值