JWT,拦截器

JWT

在这里插入图片描述注意第二部分不要有密码等敏感信息
相关代码,眼熟就行

在这里插入图片描述
在这里插入图片描述生成JWT令牌后,怎么使用呢?笨方法就是给每个需要认证的方法加上验证。现在流行的方法是建立拦截器,分为两个部分:
一:写拦截器-建立防止拦截器的包-创建拦截器类-写拦截器:

package com.example.interceptors;

import com.example.pojo.Result;
import com.example.utils.JwtUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import java.util.Map;

@Component //把当前拦截对象注入到ioc容器里
public class LoginInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //令牌验证
        String token = request.getHeader("Authorization");

        try {
            Map<String, Object> map = JwtUtil.parseToken(token);
            //放行
            return true;
        } catch (Exception e) {
            //设置响应状态码 HttpServletResponse response
            response.setStatus(401);
            //不放行
            return false;
        }

    }
}

二、注册拦截器:创建config包,在里面创建相应类-注册拦截器:

package com.example.config;

import com.example.interceptors.LoginInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
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 WebConfig implements WebMvcConfigurer {
    @Autowired
    private LoginInterceptor loginInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //登录和注册接口不拦截
        registry.addInterceptor(loginInterceptor).excludePathPatterns("/user/login","/user/register");
    }
}



怎么用token里的信息?以查询用户信息为例:

    @GetMapping("/userInfo")
    public Result<User> userInfo(@RequestHeader(name = "Authorization") String token) {
        Map <String,Object> map = JwtUtil.parseToken(token);//解析token
        //注意这里返回的是Map,能够直接把 JSON 格式的数据映射到 Java 的数据结构中,
        //返回 Map 后,可以灵活地获取各种声明信息。例如:Date issuedAt = (Date) map.get("iat");// 获取签发时间
        String username = (String) map.get("username");
        User user = userService.findByUserName(username);
        return Result.success(user);
    }

注意,我们已经写好了拦截器,但是上面的代码又自己解析了token,其实是多余的,那么怎么复用呢?
答案是:THreadLocal
在这里插入图片描述在这里插入图片描述
注:线程执行顺序随机的

如何使用?
首先添加工具类:

package com.example.utils;
import java.util.HashMap;
import java.util.Map;

/**
 * ThreadLocal 工具类
 */
@SuppressWarnings("all")
public class ThreadLocalUtil {
    //提供ThreadLocal对象,
    private static final ThreadLocal THREAD_LOCAL = new ThreadLocal();

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

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


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

然后在拦截器中创立ThreadLocal对象

@Component //把当前拦截对象注入到ioc容器里
public class LoginInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //令牌验证
        String token = request.getHeader("Authorization");

        try {
            Map<String, Object> map = JwtUtil.parseToken(token);
            //把业务数据放入TheadLocal中
            ThreadLocalUtil.set(map);
            //放行
            return true;
        } catch (Exception e) {
            //设置响应状态码 HttpServletResponse response
            response.setStatus(401);
            //不放行
            return false;
        }

    }
}

然后Controller的方法就可以简化了:

    @GetMapping("/userInfo")
    public Result<User> userInfo(/*@RequestHeader(name = "Authorization") String token*/) {
//        Map <String,Object> map = JwtUtil.parseToken(token);//解析token
        Map<String,Object> map =ThreadLocalUtil.get();
        String username = (String) map.get("username");
        User user = userService.findByUserName(username);
        return Result.success(user);
    }

}

为防止内存泄漏,还应该在拦截器中加入afterCompletion方法,拦截器完整代码为:

package com.example.interceptors;

import com.example.pojo.Result;
import com.example.utils.JwtUtil;
import com.example.utils.ThreadLocalUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import java.util.Map;

@Component //把当前拦截对象注入到ioc容器里
public class LoginInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //令牌验证
        String token = request.getHeader("Authorization");

        try {
            Map<String, Object> map = JwtUtil.parseToken(token);
            //把业务数据放入TheadLocal中
            ThreadLocalUtil.set(map);
            //放行
            return true;
        } catch (Exception e) {
            //设置响应状态码 HttpServletResponse response
            response.setStatus(401);
            //不放行
            return false;
        }

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        //清空ThreadLocal中的数据,防止内存泄漏
        ThreadLocalUtil.remove();
    }
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值