Bootstrap

JWT鉴权实战

目录


目标

  1. 熟悉JWT鉴权流程,能通过代码实现项目上的鉴权(这里以登录作为案例讲解,拦截器实现略。)。

JWT简介

JWT即Json Web Token的缩写,在Web应用中,将数据以Json格式进行传输,通过加密、签名等算法保证数据传输的安全性。


JWT的优点

  1. 共享会话:前端保存token,避免了为分布式系统做会话共享的操作;
  2. 跨语言:Json格式的通用性决定了这一特性;
  3. 减少数据访问:用户信息保存在token中,避免多次去数据库查询用户信息。

JWT的数据结构

  1. 头部(Base64编码):使用了哪一种签名算法和令牌。
  2. 有效载荷(Base64编码):可自定义内容,一般存放用户的非敏感(如:姓名、角色等)信息,而敏感信息(如:密码、手机号等)是不推荐存放的。
  3. 验证签名:包含:头部(Base64编码)、有效载荷(Base64编码)、密钥,然后使用我们指定的签名算法加密。

JWT登录鉴权流程


代码

<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>3.10.3</version>
</dependency>
package com.ctx.jwt.auth;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.AlgorithmMismatchException;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class JWTUtils {
    //注意:密钥一定要复杂且保密。
    private static final String SIGN = "123456";

    public static void main(String[] args) {
        //生成token
        String jwt = JWTUtils.getJWT();
        System.out.println(jwt);
        //验证token
        Map<String, Object> map = JWTUtils.checkToken(jwt);
        System.out.println(map);
        //获取token信息
        Map<String, Object> tokenInfo = tokenInfo(jwt);
        System.out.println(tokenInfo);
    }

    //生成JWT(实际项目中放在登录成功后执行,并将其返回给前端。)
    public static String getJWT() {
        Map<String, String> map = new HashMap<>();
        map.put("loginName", "huangshang");
        map.put("studentName", "黄裳");
        //过期时间(我这里设置2秒后过期。方便调试看结果。)
        Calendar c = Calendar.getInstance();
        c.add(Calendar.SECOND, 2);

        //创建一个JWT
        JWTCreator.Builder builder = JWT.create();
        //有效载荷部分(我这里自定义有效载荷的内容(非敏感信息)是:登录名、学生姓名。)
        for (Object key : map.keySet()) {
            builder.withClaim((String) key, map.get(key));
        }

        //token过期时间(也可以不设置过期时间,这里根据登录业务明显需要。)
        builder.withExpiresAt(c.getTime());
        //算法签名部分(自定义算法和密钥,注意:密钥一定要复杂且保密。)
        String token = builder.sign(Algorithm.HMAC256(SIGN));
        return token;
    }

    //验证token
    public static Map<String, Object> checkToken(String token) {
        Map<String, Object> map = new HashMap<>();
        map.put("result", true);
        //创建验证对象
        JWTVerifier v = JWT.require(Algorithm.HMAC256(SIGN)).build();
        try {
            DecodedJWT decodedJWT = v.verify(token);
        } catch (TokenExpiredException e) {
            map.put("msg", "token过期");
            map.put("result", false);
        } catch (SignatureVerificationException e) {
            map.put("msg", "无效签名");
            map.put("result", false);
        } catch (AlgorithmMismatchException e) {
            map.put("msg", "算法不一致");
            map.put("result", false);
        } catch (Exception e) {
            map.put("msg", "无效的token");
            map.put("result", false);
        }
        return map;
    }


    //获取token信息
    public static Map<String, Object> tokenInfo(String token) {
        Map<String, Object> map = new HashMap<>();
        map.put("result", true);
        //创建验证对象
        JWTVerifier v = JWT.require(Algorithm.HMAC256(SIGN)).build();
        try {
            DecodedJWT decodedJWT = v.verify(token);
            String loginName = decodedJWT.getClaim("loginName").asString();
            String studentName = decodedJWT.getClaim("studentName").asString();
            String date = stampToDate(decodedJWT.getExpiresAt());
            map.put("loginName", loginName);
            map.put("studentName", studentName);
            map.put("date", date);
        } catch (TokenExpiredException e) {
            map.put("msg", "token过期");
            map.put("result", false);
        } catch (SignatureVerificationException e) {
            map.put("msg", "无效签名");
            map.put("result", false);
        } catch (AlgorithmMismatchException e) {
            map.put("msg", "算法不一致");
            map.put("result", false);
        } catch (Exception e) {
            map.put("msg", "无效的token");
            map.put("result", false);
        }

        return map;
    }


    public static String stampToDate(Date date) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateString = simpleDateFormat.format(date);
        return dateString;
    }
}

官网解析Token

点击进入JWT官网

;