jwttoken+threadlocal保存单个线程共享变量的两种方法(存储用户信息)

文章目录

    • jwt
    • 方法一------threadlocal存取用户数据
    • 方法二------通过header获取token,解析封装成一个信息对象

jwt

原理是通过登录接口获取jwt颁发的token,颁发时候可以将想传递的用户信息加密融入token里

    public static String getJsonWebToken(UserPO userPO) {
        String token = Jwts.builder().setSubject(SUBJECT)
                //加入账户信息
                .claim("account", userPO.getAccount())
                .claim("name", userPO.getUserName())
                .claim("userId", userPO.getUserId())
                //发出时间
                .setIssuedAt(new Date())
                //过期时间
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRE))
                //加密方式,秘钥
                .signWith(SignatureAlgorithm.HS256, SECRET).compact();

        token = TOKEN_PREFIX + token;
        return token;

解密token

    /**
     * 校验token方法
     *
     * @param token 令牌
     * @return
     */
    public static Claims checkJWT(String token) {
        try {
            //解密token,把前缀替换为空
            final Claims claims = Jwts.parser().setSigningKey(SECRET).parseClaimsJws(token.replace(TOKEN_PREFIX, "")).getBody();
            return claims;
        } catch (Exception e) {
            return null;
        }
    }

方法一------threadlocal存取用户数据

用户登录的时候,会在拦截器里进行权限的校验
如果token解析成功,就会将数据写入线程缓存

 Claims claims = JWTUtils.checkJWT(accesToken);
            if (claims == null) {
                //或者给前端发送json消息
                sendJsonMessage(response, ResponseVO.buildError("登录过期"));
                return false;
            }
            String account = (String) claims.get("account");
            //调用工具类 写入线程缓存
            ThreadLocalUtils.set("account", account);
            //刷新token过期时间
            redisUtil.expire("token:" + accesToken, 30 * 60);

然后需要用到的时候就用工具类取出来:

package com.music.netsadcloudmusic.utils;

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

/**
 * 线程缓存工具类
 *
 * @author Boss
 */
public class ThreadLocalUtils {
    private static ThreadLocal<Map<String, Object>> cache = new ThreadLocal<Map<String, Object>>();

    /**
     * 向ThreadLocal缓存值
     *
     * @param key   要缓存的KEY
     * @param value 要缓存的VALUE
     */
    public static void set(String key, Object value) {
        if (!isCaheIsNull()) {
            cache.get().put(key, value);
        } else {
            Map<String, Object> vmap = new HashMap<>();
            vmap.put(key, value);
            cache.set(vmap);
        }
    }

    /**
     * 从ThreadLocal里获取缓存的值
     *
     * @param key 要获取的数据的KEY
     * @return 要获取的值
     */
    public static Object getCache(String key) {
        Map<String, Object> map = cache.get();
        if (isCaheIsNull()) {
            return null;
        }
        if (map.containsKey(key)) {
            return map.get(key);
        } else {
            return null;
        }
    }

    /**
     * 根据KEY移除缓存里的数据
     *
     * @param key
     */
    public static void removeByKey(String key) {
        if (isCaheIsNull()) {
            return;
        } else {
            cache.get().remove(key);
        }
    }

    /**
     * 移除当前线程缓存
     * 用于释放当前线程threadlocal资源
     */
    public static void remove() {
        cache.remove();
    }

    private static boolean isCaheIsNull() {
        return cache.get() == null;
    }
}

重点:一定要记住在afterCompletion里要ThreadLocalUtils.remove();否则ThreadLocal可能引起的内存泄露
threadlocal里面使用了一个存在弱引用的map,当释放掉threadlocal的强引用以后,map里面的value却没有被回收.而这块value永远不会被访问到了. 所以存在着内存泄露. 最好的做法是将调用threadlocal的remove方法.

方法二------通过header获取token,解析封装成一个信息对象

这种方法的好处就是随用随取,减少性能的消耗
pojo:

/**
 * @author: Boss
 * Date: 2020/12/28
 * Time: 16:44
 * Description:
 */
@ApiModel("用户信息DTO")
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class UserInformationDTO {
    private String name;
    private String account;
    private Integer userId;
}

工具类:

/**
 * @author: Boss
 * Date: 2020/12/28
 * Time: 16:57
 * Description: 从请求头的token里解析出线程用户是谁
 */
public class GetUserInformationUtils {
    public static UserInformationDTO getUserBasic(){
        // 获取相关对象
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
        String accesToken =  request.getHeader("token");
        Claims claims = JWTUtils.checkJWT(accesToken);
        if (claims == null) {
            //或者给前端发送json消息
            throw new MyException(ErrorCode.ERROR);
        }
        String account = (String) claims.get("account");
        String name = (String) claims.get("name");
        Integer userId = (Integer) claims.get("userId");

        UserInformationDTO userINformationDTO = UserInformationDTO.builder()
                .userId(userId).account(account).name(name).build();
        return userINformationDTO;
    }
}

用法:

UserInformationDTO userBasic = GetUserInformationUtils.getUserBasic();
        String account = userBasic.getAccount();

你可能感兴趣的:(springboot项目学习)