springBoot集成jwt实现用户登录验证,请求接口验证

1 篇文章 0 订阅
1 篇文章 0 订阅
该博客详细介绍了如何在springBoot项目中集成jwt进行用户登录验证。首先,在pom.xml引入jwt依赖,然后配置InterceptorConfig类并创建JwtInterceptor。接着,利用TokenUtils工具类生成和验证token。前端在登录后存储token,并在后续请求中携带token,通过自定义注释和请求拦截器进行验证。
摘要由CSDN通过智能技术生成

springBoot + jwt

1.springboot项目中在pom.xml引入以下jwt依赖

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

2.配置类InterceptorConfig 类继承 WebMvcConfigurationSupport

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;

//1、继承WebMvcConfigurationSupport
@Configuration//表示这是一个配置类
public class InterceptorConfig extends WebMvcConfigurationSupport {

    //2、addInterceptors方法是继承WebMvcConfigurationSupport需要重写一个拦截器的规则jwtInterceptor()他通过@Bean的方法将对象注入到spring容器里面
    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(jwtInterceptor())// 配置jwt的拦截器规则
                .addPathPatterns("/**")          //addPathPatterns("/**")/**表示拦截所有的请求路径
                .excludePathPatterns("/erpUserInfo/login");  //应该拦截除了登录,注册请求以外的所有路径
        super.addInterceptors(registry);
    }

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

3.创建JwtInterceptor 继承 HandlerInterceptor

前端存登录生成的token,访问接口时获取前端请求头携带的token,若token匹配则验证通过,否则抛出异常

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 jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.servlet.HandlerInterceptor;

public class JwtInterceptor implements HandlerInterceptor {

    @Resource
    private ErpUserInfoMapper userMapper;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws ServiceException {
        //1、首先用request拿到header(请求头)里的token参数
        String token = request.getHeader("Authorization");
        //2、拿到token参数以后进行校验,看他有没有.getparameter获取到的是url参数比如:xxx?token=...  可以用1和2两种方式接受参数一个是头一个是url参数,两个里面有一个获取到了token参数就认为他是有这个参数的
        if (StrUtil.isBlank(token)) {
            token = request.getParameter("token");
        }
        // 如果不是映射到方法直接通过 配合自定义注解使用
        //if (handler instanceof HandlerMethod) {
        //AuthAccess annotation = ((HandlerMethod) handler).getMethodAnnotation(AuthAccess.class);
        //if (annotation != null) {
        //return true;
        //}
        //}
        //3、如果请求头和参数里面都没有则抛出异常返回信息“请登录” 执行认证
        if (StrUtil.isBlank(token)) {
            throw new ServiceException("401", "请登录");
        }
        //4、如果有token的话   token里面存储的是字符串所以定义的时候是string getAudience()可以存储信息 获取 token 中的 userid  JWT.decode(token)解码解码完成之后拿到getAudience()里面的第一个数据get(0)
        String userId;
        try {
            userId = JWT.decode(token).getAudience().get(0);
        } catch (JWTDecodeException j) {
            throw new ServiceException("401", "请登录");
        }
        //5、 根据token中的userid查询数据库进行信息校验Integer.valueOf(userId)把字符串转化为数字然后查询数据库
        ErpUserInfo erpUserInfo = userMapper.selectById(Integer.valueOf(userId));
        if (erpUserInfo == null) {
            throw new ServiceException("401", "请登录");
        }
        //6、 用户密码加签验证:通过user拿到密码 jwtVerifier是一个验证器,通过用户密码加密之后生成的一个验证器 通过验证器的verify方法继续验证token,如果验证通过return true,如果验证失败则跑一个异常
        JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(erpUserInfo.getPassword())).build();
        try {
            jwtVerifier.verify(token); // 验证token
        } catch (JWTVerificationException e) {
            throw new ServiceException("401", "请登录");
        }
        String res = stringRedisTemplate.opsForValue().get(token);
        if (res == null){
            throw new ServiceException("401", "请登录");
        }
        return true;
    }
}

4.创建TokenUtils工具类 生成token与获取token对应的用户

package com.lx.erp.utils;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.util.Date;

@Component
public class TokenUtils {

    //1、定义一个静态mapper的原因,因为下面有static方法,在static方法里面像使用mapper那么mapper必须是static修饰的(静态的方法只能访问静态的变量)
    private static ErpUserInfoMapper staticUserMapper;

    @Resource
    ErpUserInfoMapper userMapper;

    @PostConstruct
    public void setUserService() {
        staticUserMapper = userMapper;
    }

    /**
     * 2、生成token
     *
     * @return
     */
    public static String genToken(String userId, String sign) {
        return JWT.create().withAudience(userId) // 将 user id 保存到 token 里面,作为载荷
                .withExpiresAt(DateUtil.offsetHour(new Date(), 2)) // 2小时后token过期  withExpiresAt设置过期时间。offsetHour(new Date(), 2)表示当前日期new Date()往后偏移两个小时,他返回的是一个时间
                .sign(Algorithm.HMAC256(sign)); // 以 password 作为 token 的密钥.sign(Algorithm.HMAC256(sign))进行加密  sign是传过来的参数,传什么参数生成什么类型的验证器
    }

    /**
     * 3、获取当前登录的用户信息
     *只要当前请求有token我就可以通过token去拿到当前请求的用户的所有的信息(是从数据库里面查出来的 )
     * @return user对象
     */
    public static ErpUserInfo getCurrentUser() {
        try {
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            String token = request.getHeader("Authorization");
            if (StrUtil.isNotBlank(token)) {
                String userId = JWT.decode(token).getAudience().get(0);
                return staticUserMapper.selectById(Integer.valueOf(userId));
            }
        } catch (Exception e) {
            return null;
        }
        return null;
    }
}

5.token的使用

String token = TokenUtils.genToken(erpUserInfo1.getId().toString(),erpUserInfo1.getPassword());

6.自定义注释

import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AuthAccess {
}

7.前端登录接口存储token

login(this.formInline).then((res) => {
        console.log(res)
        if (res.status === 200) {
          window.localStorage.setItem('token', res.data, '7d')
        } 
      })

8.前端请求拦截器

//请求拦截器 
instance.interceptors.request.use((config) => {
    showLoading()
    // 每次发送请求之前判断是否存在token,如果存在,则统一在http请求的header都加上token,不用每次请求都手动添加了
    const token = window.localStorage.getItem('token');
    if (token) {  // 每次发送请求之前判断是否存在token,如果存在,则统一在http请求的header都加上token,不用每次请求都手动添加了
        config.headers.Authorization = token;
    } else {
        router.push("/");
        if (config.url !== '/api/erpUserInfo/login') {
            alert("登录已过期,请重新登录")
        }

    }
    //若请求方式为post,则将data参数转为JSON字符串  
    if (config.method === 'POST') {
        config.data = JSON.stringify(config.data);
    }
    return config;
}, (error) =>
    // 对请求错误做些什么
    Promise.reject(error));
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

传奇丶少年

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

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

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

打赏作者

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

抵扣说明:

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

余额充值