springboot项目+redis验证token

pom文件中导入对应jar包

<!--jwt生成token验证token-->
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>4.4.0</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--pageHelper坐标-->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.4.7</version>
        </dependency>
       
        <!--redis坐标-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

 

  jwt工具类  生成token并验证token有效性

package com.itheima.bigevent.utills;

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;
import java.util.Map;

/**
 * @author*/
public class JwtUtil {
    private static final String KEY="itheima";

    /**
     *接收业务数据生成token
     * @param claims
     * @return
     */
    public static String genToken(Map<String,Object> claims){
        //生成jwt
        String token = JWT.create()
                //添加载荷
                .withClaim("claims",claims)
                //过期时间
                .withExpiresAt(new Date(System.currentTimeMillis()+1000*60*60*12))
                //指定算法配置秘钥
                .sign(Algorithm.HMAC256(KEY));
        System.out.println("token===:"+token);
        return token;
    }

    /**
     * 接收token验证token并返回数据
     * @param token
     * @return
     */
    public static Map<String,Object> parseToken(String token){
        JWTVerifier verifier = JWT.require(Algorithm.HMAC256(KEY)).build();
        //验证token,生成一个解析后的jwt对象
        DecodedJWT decodedJWT = verifier.verify(token);
        Map<String, Object> claims = decodedJWT.getClaim("claims").asMap();
        return claims;
    }
}

 

  

ThreadLocalUtil工具类 把解析的用户信息放入ThreadLocal中
package com.itheima.bigevent.utills;

/**
 * @author*/
public class ThreadLocalUtil {
    /**
     * 提供threadLocal对象
     */

    private static final ThreadLocal THREAD_LOCAL = new ThreadLocal<>();

    /**
     * 根据key获取值
     * @return
     * @param <T>
     */
    public static <T> T get(){
        return (T) THREAD_LOCAL.get();
    }

    /**
     * 存储键值对
     * @param value
     */
    public static void set(Object value){
        THREAD_LOCAL.set(value);
    }

    /**
     * 清除threadLocal防止内存泄漏
     */
    public static void remove(){
        THREAD_LOCAL.remove();
    }







}

 

  //自定义拦截器验证token

package com.itheima.bigevent.interceptors;

import com.itheima.bigevent.utills.JwtUtil;
import com.itheima.bigevent.utills.ThreadLocalUtil;
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.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import java.util.Map;

/**
 * @author*/
@Component
public class LoginInterceptor implements HandlerInterceptor {
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        String url = request.getRequestURI();
        System.out.println("请求路径url==="+url);
        //令牌验证
        String token = request.getHeader("Authorization");
        try{
            //解析token
            Map<String,Object> map = JwtUtil.parseToken(token);
            Integer userId = (Integer) map.get("id");
            System.out.println("解析token-map=="+map);
            //从redis中获取相同的token
            String key = "accessToken:token:"+userId;
            String redisToken = redisTemplate.opsForValue().get(key);
            if(null == redisToken){
                throw new RuntimeException("token失效");
            }
            //把业务数据存放到ThreadLocal中
            ThreadLocalUtil.set(map);
            //放行
            return Boolean.TRUE;
        }catch (Exception e){
            e.printStackTrace();
            response.setStatus(401);
            //不放行
            return Boolean.FALSE;
        }
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        //清空treadLocal中数据
        ThreadLocalUtil.remove();
    }
}
WebConfig配置文件,把自定义拦截器添加到配置中
package com.itheima.bigevent.config;

import com.itheima.bigevent.interceptors.LoginInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @author*/
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Autowired
    private LoginInterceptor loginInterceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //登陆接口和注册接口不拦截
        registry.addInterceptor(loginInterceptor)
                // 只拦截/api开头的路径
                .addPathPatterns("/api/**")
                //放行路径
                .excludePathPatterns("/api/user/login","/user/register","/api/article/getAll");
    }
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                //允许哪些域访问
                .allowedOriginPatterns("*")
                //方法
                .allowedMethods("GET", "POST", "PUT", "DELETE","HEAD", "OPTIONS")
                .allowedHeaders("*")
                //3600秒之内浏览器不必再次询问
                .maxAge(3600)
                //允许携带cok
                .allowCredentials(true);

    }

}

对应用户controller提供用户注册登陆方法

package com.itheima.bigevent.controller;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.itheima.bigevent.pojo.Result;
import com.itheima.bigevent.pojo.User;
import com.itheima.bigevent.pojo.UserReq;
import com.itheima.bigevent.service.UserService;
import com.itheima.bigevent.utills.JwtUtil;
import com.itheima.bigevent.utills.ThreadLocalUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.DigestUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author 
 *
 */
@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService userService;
    @Autowired
    private StringRedisTemplate redisTemplate;

    @PostMapping("/register")
    public Result register(String username,String password){
        System.out.println("注册开始>>>>>>>>>>>>>");
        if(StrUtil.isEmpty(username)){
            return Result.error("用户名不能为空");
        }
        if(StrUtil.isEmpty(password)){
            return Result.error("密码不能为空");
        }
        //查询用户
        User user = userService.findByUserName(username);
        System.out.println("user===:"+user);
        if(null == user){
            //注册
            userService.register(username,password);
            return Result.success();
        }else {
            //占用
            return Result.error("用户名被占用");
        }
    }
    @PostMapping("/login")
    public Result<String> login(String username,String password){
        if(StrUtil.isEmpty(username)){
            return Result.error("用户名不能为空");
        }
        if(StrUtil.isEmpty(password)){
            return Result.error("密码不能为空");
        }
        //查询用户
        User user = userService.findByUserName(username);
        if(ObjectUtil.isEmpty(user)){
            return Result.error("用户不存在");
        }
        if(!DigestUtils.md5DigestAsHex(password.getBytes()).equals(user.getPassword())){
            return Result.error("密码错误!");
        }
        //生成token
        Map<String,Object> claims = new HashMap<>();
        claims.put("id",user.getId());
        claims.put("username",user.getUsername());
        claims.put("nickname",user.getNickname());
        String token = JwtUtil.genToken(claims);
        //把token存储到redis中
        String key = "accessToken:token:"+user.getId();
        redisTemplate.opsForValue().set(key,token,30, TimeUnit.MINUTES);
        return Result.successDate(token);
    }

    /**
     * 获取用户信息
     * @return
     */
    @GetMapping("/getUserInfo")
    public Result<User> getUserInfo(@RequestHeader("Authorization") String token){
       /* Map<String,Object> map = JwtUtil.parseToken(token);
        System.out.println("获取用户信息map=="+map);
        String username = map.get("username").toString();*/
        Map<String,Object> map = ThreadLocalUtil.get();
        System.out.println("map==="+map);
        String username = map.get("username").toString();
        User user = userService.findByUserName(username);
        return Result.successDate(user);
    }
    @PostMapping("/update")
    public Result<Boolean> update(@Validated @RequestBody User user){
        userService.update(user);
        return Result.successDate(Boolean.TRUE);
    }

    /**
     * 更新用户头像
     * @param user
     * @return
     */
    @PostMapping("updateUserPic")
    private Result<Boolean>updateUserPic(@RequestBody User user){
        userService.updateUserPic(user);
        return Result.successDate(Boolean.TRUE);
    }

    /**
     * 更新用户密码
     * @param user
     * @return
     */
    @PostMapping("updatePassword")
    private Result<Boolean>updatePassword(@RequestBody UserReq user){
        userService.updatePassword(user);
        Map<String,Object> map =ThreadLocalUtil.get();
        Integer userId = (Integer) map.get("id");
        //删除token
        String key = "accessToken:token:"+userId;
        redisTemplate.delete(key);
        return Result.successDate(Boolean.TRUE);
    }


}

yaml配置文件

#
server:
  port: 8080
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/mybatis
    username:自己数据库用户名
    password: 自己数据库密码
  # redis配置
  data:
    redis:
      host: localhost
      port: 6379
      database: 0


mybatis:
  configuration:
    #开启驼峰命名和下划线命名字段的自动转换
    map-underscore-to-camel-case: true
  mapper-locations: classpath*:mapper/**/*.xml

 

posted @ 2025-08-21 23:26  红尘沙漏  阅读(11)  评论(0)    收藏  举报