目录

一、什么是JWT:

二、Jwt的使用:

第一步:引入依赖:

第二步:配置拦截器:JwtInterceptor.java:

其中异常文件ServiceException配置如下:

全局异常文件GlobalException.java文件配置如下:

其中所需的Result配置如下:

第三步:配置拦截设置文件:InterceptorConfig.java:

第四步:配置Token工具类文件:TokenUtils.java:

request.js的axios封装文件为:

文件布局大致如下:


一、什么是JWT:

        JWT是token的一种实现方式,全称是:JSON Wwb Token。简单来讲,Jwt是一种字符串,可以根据用户信息进行相关的编码操作生成带有用户信息的JWT token,我们可以根据这个来判断其信息是否正确或者是否被篡改。

二、Jwt的使用:

首先是后端:

第一步:引入依赖:

		<dependency>
			<groupId>com.auth0</groupId>
			<artifactId>java-jwt</artifactId>
			<version>4.3.0</version>
		</dependency>

第二步:配置拦截器:JwtInterceptor.java:

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.example.cqcrhouduan.Utils.TokenUtils;
import com.example.cqcrhouduan.exception.ServiceException;
import com.example.cqcrhouduan.mapper.UserMapper;
import io.micrometer.common.util.StringUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

@Component
@Slf4j
public class JwtInterceptor implements HandlerInterceptor {

    @Autowired
    private UserMapper userMapper;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        if(request.getMethod().equals("OPTIONS"))
        {
            return true;
        }
        String token = request.getHeader("token");
        if (StringUtils.isEmpty(token)) {
            token = request.getParameter("token");
        }
        token = token;
        // 执行认证
        if (StringUtils.isEmpty(token)) {
            throw new ServiceException(401, "无token,请重新登录");
        }
        // 获取 token 中的adminId
        String userId;
        User user;
        try {
            userId = JWT.decode(token).getAudience().get(0);  //解码
        // 根据token中的userid查询数据库
            user = userMapper.getById(Integer.parseInt(userId));
            user = user;
        } catch (Exception e) {
            String errMsg = "token验证失败,请重新登录";
            log.error(errMsg + ", token=" + token, e);
            throw new ServiceException(401, errMsg);
        }
        if (user == null) {
            throw new ServiceException(401, "用户不存在,请重新登录");
        }

        try {
            // 用户密码加签验证 token
            JWTVerifier jwtVerifier =             
            JWT.require(Algorithm.HMAC256(user.getPassword())).build();
            jwtVerifier.verify(token); // 验证token
        } catch (JWTVerificationException e) {
            throw new ServiceException(401, "token验证失败,请重新登录");
        }
        return true;
    }
}
其中异常文件ServiceException配置如下:
import com.example.cqcrhouduan.pojo.Result;
import lombok.Data;

@Data
public class ServiceException extends RuntimeException {
    private int code;
    public ServiceException(String msg){
        super(msg);
        this.code = 500;
    }

    public ServiceException(int code, String msg){
        super(msg);
        this.code = code;
    }
}
全局异常文件GlobalException.java文件配置如下:
import com.example.cqcrhouduan.pojo.Result;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;


//自定义异常
@ControllerAdvice
public class GlobalException {

    @ExceptionHandler(ServiceException.class)
    @ResponseBody
    public Result serviceException(ServiceException e){
        return Result.error(e.getCode(),e.getMessage());
    }
}
其中所需的Result配置如下:
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result {
    private Integer code;
    private String msg;
    private Object data;

    public static Result success(Object data){
        return new Result(200,"success",data);
    }

    public static Result success(){
        return new Result(200,"success",null);
    }

    public static Result error(String msg){
        return new Result(500,msg,null);
    }

    public static Result error(Integer Code ,String msg){
        return new Result(Code,msg,null);
    }

}

第三步:配置拦截设置文件:InterceptorConfig.java:

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.WebMvcConfigurationSupport;

@Configuration
public class InterceptorConfig extends WebMvcConfigurationSupport {
    // 加自定义拦截器JwtInterceptor,设置拦截规则
    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(jwtInterceptor())
                .addPathPatterns("/**")
                .excludePathPatterns("/login","/register");
        super.addInterceptors(registry);
    }

    @Bean
    public JwtInterceptor jwtInterceptor(){
        return new JwtInterceptor();
    }
}

第四步:配置Token工具类文件:TokenUtils.java:

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.example.cqcrhouduan.mapper.UserMapper;
import com.example.cqcrhouduan.pojo.User;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;


@Component
@Slf4j
public class TokenUtils {

    private static UserMapper staticAdminService;

    @Resource
    private UserMapper adminService;

    @PostConstruct
    public void setUserService() {
        staticAdminService = adminService;
    }

    /**
     * 生成token
     *
     * @return
     */
    public static String genToken(int adminId, String sign) {
        return JWT.create().withAudience(Integer.toString(adminId)) // 将 user id 保存到 token 里面,作为载荷
                .withExpiresAt(DateUtil.offsetHours(new Date(), 2)) // 2小时后token过期
                .sign(Algorithm.HMAC256(sign)); // 以 password 作为 token 的密钥
    }

    /**
     * 获取当前登录的用户信息
     *
     * @return user对象
     *  /admin?token=xxxx
     */
    public static User getCurrentAdmin() {
        String token = null;
        try {
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            token = request.getHeader("token");
            if (StringUtils.isNotBlank(token)) {
                token = request.getParameter("token");
            }
            if (StringUtils.isBlank(token)) {
                log.error("获取当前登录的token失败, token: {}", token);
                return null;
            }
            String userId = JWT.decode(token).getAudience().get(0);
            return staticAdminService.getById(Integer.valueOf(userId));
        } catch (Exception e) {
            log.error("获取当前登录的管理员信息失败, token={}", token,  e);
            return null;
        }
    }
}

然后是前端axios配置:

request.js的axios封装文件为:

import axios from "axios";
import router from "../modules/router.js";

const request = axios.create({
    baseURL:'http://localhost:8080/',  //自己的请求地址
    timeout:30000,
})


// Add a request interceptor
request.interceptors.request.use((config) => {
    config.headers['Content-Type'] = 'application/json;charset=utf-8';
    let user = JSON.parse(localStorage.getItem("userToken") || '{}')
    // console.log(user.token)  //查看token
    config.headers['token'] = user.token
    // config.headers.Authorization = localStorage.getItem("userToken")
    console.log("ok")
    // Do something before request is sent
    return config;
}, error => {
    console.log('request error' + error)
    // Do something with request error
    return Promise.reject(error);
});

// Add a response interceptor
request.interceptors.response.use(response => {
    let res = response.data;
    if (typeof res === 'string'){
        res = res ? JSON.parse(res) : res
    }
    // if(res.code === 401){ //自动跳转
    //     router.push('/')
    // }
    // Any status code that lie within the range of 2xx cause this function to trigger
    // Do something with response data
    return res;
}, function (error) {
    // Any status codes that falls outside the range of 2xx cause this function to trigger
    // Do something with response error
    console.log('response error' + error)
    return Promise.reject(error);
});

export default request

文件布局大致如下:

后端Jwt实现Token编码、解码以及axios的request请求头的Token传输方式-LMLPHP

03-24 07:38