JWT快速使用以及结合ThreadLocal获取token信息

目录

 1.JWT使用

2.ThredLocal使用


 1.JWT使用

首先需要明确 JWT 就是 JSON WEB TOKEN它只是通用的一种token令牌校验规则,它规定了token的生成解析策略,方便大家使用。接下来就是JWT执行流程,如下:

JWT由 JWT头有效载荷签名三个 组成:JWT头部分是一个描述JWT元数据的JSON对象;有效载荷一般是JWT的主体内容部分用于存储用户信息;签名对上面两部分数据签名,通过指定的算法生成哈希,以确保数据不会被篡改。

了解了JWT的基本使用后,接下来就是带领大家快速入门了。

第一步: 首先是引入相关依赖,以及一些准备

        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>

jwt令牌配置类(需自行引入lombok):

@Component
@ConfigurationProperties(prefix = "sky.jwt")  //配置前缀注入,在yml文件中进行属性配置
@Data
public class JwtProperties {

    /**
     * 管理端员工生成jwt令牌相关配置
     */
    private String adminSecretKey;
    private long adminTtl;
    private String adminTokenName;

    /**
     * 用户端微信用户生成jwt令牌相关配置
     */
    private String userSecretKey;
    private long userTtl;
    private String userTokenName;

}

yml如下:

第二步:   编写JWT工具类(仅对JWT方法的进一步封装)

public class JwtUtil {
    /**
     * 生成jwt
     * 使用Hs256算法, 私匙使用固定秘钥
     *
     * @param secretKey jwt秘钥
     * @param ttlMillis jwt过期时间(毫秒)
     * @param claims    设置的信息
     * @return
     */
    public static String createJWT(String secretKey, long ttlMillis, Map<String, Object> claims) {
        // 指定签名的时候使用的签名算法,也就是header那部分
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;

        // 生成JWT的时间
        long expMillis = System.currentTimeMillis() + ttlMillis;
        Date exp = new Date(expMillis);

        // 设置jwt的body
        JwtBuilder builder = Jwts.builder()
                // 如果有私有声明,一定要先设置这个自己创建的私有的声明,这个是给builder的claim赋值,一旦写在标准的声明赋值之后,就是覆盖了那些标准的声明的
                .setClaims(claims)
                // 设置签名使用的签名算法和签名使用的秘钥
                .signWith(signatureAlgorithm, secretKey.getBytes(StandardCharsets.UTF_8))
                // 设置过期时间
                .setExpiration(exp);

        return builder.compact();
    }

    /**
     * Token解密
     *
     * @param secretKey jwt秘钥 此秘钥一定要保留好在服务端, 不能暴露出去, 否则sign就可以被伪造, 如果对接多个客户端建议改造成多个
     * @param token     加密后的token
     * @return
     */
    public static Claims parseJWT(String secretKey, String token) {
        // 得到DefaultJwtParser
        Claims claims = Jwts.parser()
                // 设置签名的秘钥
                .setSigningKey(secretKey.getBytes(StandardCharsets.UTF_8))
                // 设置需要解析的jwt
                .parseClaimsJws(token).getBody();
        return claims;
    }

}

第三步:   编写JWT拦截器

/**
 * jwt令牌校验的拦截器
 */
@Component
@Slf4j
public class JwtTokenAdminInterceptor implements HandlerInterceptor {

    @Autowired
    private JwtProperties jwtProperties;

    /**
     * 校验jwt
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //判断当前拦截到的是Controller的方法还是其他资源,instanceof同 ==
        if (!(handler instanceof HandlerMethod)) {
            //当前拦截到的不是动态方法,直接放行
            return true;
        }

        //1、从请求头中获取令牌
        String token = request.getHeader(jwtProperties.getAdminTokenName());

        //2、校验令牌
        try {
            log.info("jwt校验:{}", token);
            Claims claims = JwtUtil.parseJWT(jwtProperties.getAdminSecretKey(), token);
            //JwtClaimsConstant.EMP_ID就是存放的id属性名,这里用了静态参数类进行统一管理
            Long empId = Long.valueOf(claims.get(JwtClaimsConstant.EMP_ID).toString()); 
            log.info("当前id:", empId);
            //3、通过,放行
            return true;
        } catch (Exception ex) {
            //4、不通过,响应401状态码
            response.setStatus(401);
            return false;
        }
    }
}

编写参数统一管理类,如下:

//参数统一管理类
public class JwtClaimsConstant {

    public static final String EMP_ID = "empId";
    public static final String USER_ID = "userId";
    public static final String PHONE = "phone";
    public static final String USERNAME = "username";
    public static final String NAME = "name";

}

第四步:   编写mvc配置类注册JWT拦截器(上面只是写出了拦截器,这里才是对其的使用)

/**
 * 配置类,注册web层相关组件
 */
@Configuration
@Slf4j
public class WebMvcConfiguration extends WebMvcConfigurationSupport {

    @Autowired
    private JwtTokenAdminInterceptor jwtTokenAdminInterceptor;

    /**
     * 注册自定义拦截器
     *
     * @param registry
     */
    protected void addInterceptors(InterceptorRegistry registry) {
        log.info("开始注册自定义拦截器...");
        registry.addInterceptor(jwtTokenAdminInterceptor)
                .addPathPatterns("/admin/**")           //拦截的请求路径
                .excludePathPatterns("/admin/employee/login");  //放过的请求路径
    }
}

第五步:   对JWT的使用

只需在登录成功时,利用JWT工具类创建jwt令牌并返回给前端即可,如下:

后续请求中,前端会携带JWT令牌,通过JWT令牌可以解析出当前登录id。

2.ThredLocal使用

那解析出登录id后,如何传递给Service的save方法呢?

而接下来就需要使用到ThredLocal了,下面是对ThredLocal的简单介绍:

 下面是使用:

第一步:  封装(可省略)

public class BaseContext {

    public static ThreadLocal<Long> threadLocal = new ThreadLocal<>();

    public static void setCurrentId(Long id) {
        threadLocal.set(id);
    }

    public static Long getCurrentId() {
        return threadLocal.get();
    }

    public static void removeCurrentId() {
        threadLocal.remove();
    }

}

第二步:  使用

1、在前面JWT的拦截器使用中,当JWT校验通过时可在最后加入BaseContext.setCurrentId(empId);如下:

 2、然后在需要的地方调用BaseContext.getCurrentId();即可

以上就是对JWT和ThreadLocal的基本使用。

猜你喜欢

转载自blog.csdn.net/weixin_58403235/article/details/132840876
今日推荐