通过jwt令牌使用threadlocal传递用户信息

threadlocal定义--定义什么的看看就行了==================

        ThreadLocal 是 Java 中的一个类,它提供了线程局部变量。为每个线程分配独立的变量副本来工作。每个线程在访问 ThreadLocal 变量时,都会获取该线程特有的值,而不会影响或被其他线程的值影响。

        就是说threadlocal就像线程的口袋,每个线程都有口袋,可以往里面放东西,也可以取东西,你的口袋是你的,我的口袋是我的,我的口袋跟你没关系,你的口袋跟我也没关系。

应用场景:========================================

在单体架构项目中,有许多情况都需要用到--当前用户身份信息,比如说删除某个数据我要判断当前登录用户是否有权限删除,比如说购物环境中不可能为每个用户都创建一个购物车表,所有的用户共用一个购物车表,用户查询购物车时就要根据当前用户信息查询出该用户的购物车数据,总不能把表中所有的购物车商品都查出来把。

想要获取当前登录用户信息,肯定要在登录时做些手脚,将用户信息保存下来。保存在令牌中,然后每次请求都可以携带到后端,后端再去存储,这样在不同的线程中都能获取到当前用户信息了。

实现=============================================

我们先看一下jwt令牌的工作流程:

用户首先进行登录==》

        请求到后端controller==》

                (用户名密码正确)生成令牌返回给前端==》

                        前端保存令牌并在以后每次请求中携带令牌

用户发起其他请求(请求头中携带了令牌)==》

        后端拦截器拦截用户请求==》

                验证请求中令牌是否合法==》

                        合法放行,不合法拒绝访问
                    
原文链接:https://blog.csdn.net/weixin_75001968/article/details/138923794

================================================

在生成令牌时将用户信息保存在其中:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
 
import java.util.HashMap;
import java.util.Map;
 
@RestController
public class AuthController {
 
    @Autowired
    private AuthenticationManager authenticationManager;
 
    @Autowired
    private JwtUtil jwtUtil;
    
    @Autowired
    private UserMapper userMapper;
 
    @PostMapping("/login")
    public Map<String, String> login(@RequestBody AuthRequest authRequest) {
        try {
            //验证用户名密码是否正确--查询数据库
             User user = userMapper.select(authRequest);
            
            //密码正确才解析令牌,否则直接返回
           if(user == null) throw new Exception("用户名或者密码不正确!");

            //生成令牌-userId作为数据载荷部分
            //如果username唯一,将username作为数据载荷部分也是一样
            String token = jwtUtil.generateToken(authRequest.getUserId());

            //将生成的令牌返回给前端
            Map<String, String> response = new HashMap<>();
            response.put("token", token);
            return response;
        } catch (AuthenticationException e) {
            throw new RuntimeException("Invalid login credentials");
        }
    }
}
 
class AuthRequest {
    private String username;
    private String password;
 
    // getters and setters
}

解析令牌时将用户信息(userId)存入threadlocal

1.创建threadlocal类:

public class UserContext {
    private static final ThreadLocal<String> currentUser = new ThreadLocal<>();

    public static void setCurrentUser(Long userId) {
        currentUser.set(userId);
    }

    public static Long getCurrentUser() {
        return currentUser.get();
    }

    public static void clear() {
        currentUser.remove();
    }
}

2.修改jwt工具类

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.SignatureException;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.MalformedJwtException;

import java.util.Date;

public class JwtUtil {
    private static final String SECRET_KEY = "yourSecretKey"; // 替换为你的密钥

    public static String generateToken(String username) {
        return Jwts.builder()
                .setSubject(username)
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + 86400000)) // 1 天有效期
                .signWith(SignatureAlgorithm.HS256, SECRET_KEY)
                .compact();
    }

    public static boolean validateToken(String token) {
        try {
            Jwts.parser()
                .setSigningKey(SECRET_KEY)
                .parseClaimsJws(token);
            return true;
        } catch (SignatureException | ExpiredJwtException | MalformedJwtException e) {
            return false;
        }
    }

    public static Claims getClaims(String token) {
        return Jwts.parser()
                .setSigningKey(SECRET_KEY)
                .parseClaimsJws(token)
                .getBody();
    }
}

3.修改jwt拦截器

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import io.jsonwebtoken.Claims;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
public class JwtInterceptor implements HandlerInterceptor {

    @Autowired
    private JwtUtil jwtUtil;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 获取到请求头中的令牌
        String authorizationHeader = request.getHeader("Authorization");

        // 校验令牌是否合法
        if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
            String token = authorizationHeader.substring(7);
            if (jwtUtil.validateToken(token)) {

                // 解析用户信息并存入 ThreadLocal
                Claims claims = jwtUtil.getClaims(token);
                Long userId= claims.getSubject();

                //将用户id存入threadlocal
                UserContext.setCurrentUser(userId);

                return true;
            }
        }
        // 返回不合法信息
        response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Invalid or missing Authorization header");
        return false;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 清理 ThreadLocal,防止内存泄漏
        UserContext.clear();
    }
}

4.使用

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

@RestController
@RequestMapping("/api")
public class ApiController {

    @GetMapping("/userinfo")
    public Map<String, String> getUserInfo() {

        //从threadlocal中获取用户信息--userId
        String username = UserContext.getCurrentUser();

        Map<String, String> response = new HashMap<>();
        response.put("username", username);
        return response;
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值