我们知道 jwt(JSON Web Token)是基于RFC 7519标准的方法,并不是某公司的开源项目,所以jwt在java端有很多的实现库,主流的有jjwt、java-jwt、JOSE4j等,其实基础功能都差不多。本文提供的是基于 java-jwt 的工具类。

1. 依赖

  1. <!-- jwt -->
  2. <dependency>
  3. <groupId>com.auth0</groupId>
  4. <artifactId>java-jwt</artifactId>
  5. <version>3.10.3</version>
  6. </dependency>

2. JwtUtils

public class JwtUtils {

    //通过有效时间
    private static int days = 7;

    //密钥(需要后端严密保存)
    private static String SecretKey = "852@$%#123!";

    /**
     *  生成token header.payload.sing
     */
    public static String getToken(Map<String,String> map){
        Calendar instance = Calendar.getInstance();
        instance.add(Calendar.DATE,days);
        //创建jwt builder
        JWTCreator.Builder builder = JWT.create();
        //payload
        map.forEach((k,v)->{
           builder.withClaim(k,v);
        });
        //生成token,头部默认jwt和Base64编码
        String token = builder.withExpiresAt(instance.getTime())   //设置过期时间
                .sign(Algorithm.HMAC256(SecretKey));        //加密算法和密钥
        return token;
    }

    /**
     * 验证 token 合法性
     */
    public static DecodedJWT verify(String token){
        return JWT.require(Algorithm.HMAC256(SecretKey)).build().verify(token);
    }

}

3. 使用生成

//仅为示例,可以以此扩展
@PostMaping("/login")
public String login(String username, String pwd){
    //普通用户类
    User user = new User(username,pwd);
    userService.save(user); //mybatis plus
    Map<String,String> map = new HashMap<>();
    //请勿放用户的敏感信息,例如密码等
    map.put("userId",user.getId());
    map.put("username",user.getName());
    String token = JwtUtils.getToken(map);
    return token; //前端可以存入localStorage或是缓存中
}

4. 后端校验与获取

//一般在过滤器/拦截器中对请求拦截,从请求头中拿到该token。
try{
    DecodedJWT jwt = JwtUtils.verify(token);
    int userId = jwt.getClaim("userId").asInt();
    Stirng username = jwt.getClaim("username").asString();
    //自己的业务处理
    //......
} catch (Exception e){
    //自己的业务处理,或者直接抛出自定义异常
    //.....
}
//如果token有任何问题,无论是过期、无效、非法等,该方法都会抛出相应的异常
//但是前端无需知道是哪种,因为结果都是让用户重新登录,所以不用过细的捕获
//直接返回统一的 请重新登录 即可。
   工具类设计的相对简单,因为每个人向 **payload **种放置的信息不同,所以本方法就直接把验证后的对象直接返回了,大家还可以自己向工具类中根据业务需求自己补充方法