第一次写博客有点紧张,还有点小激动,话不多说直接切入正题

什么是JWT(JSON WEB TOKENS)?

JWT是一种用于双方之间传递安全信息的简洁的、URL安全的表述性声明规范。JWT作为一个开放的标准(RFC 7519),定义了一种简洁的,自包含的方法用于通信双方之间以Json对象的形式安全的传递信息。因为数字签名的存在,这些信息是可信的,JWT可以使用HMAC算法或者是RSA的公私秘钥对进行签名。简洁(Compact): 可以通过URL,POST参数或者在HTTP header发送,因为数据量小,传输速度也很快 自包含(Self-contained):负载中包含了所有用户所需要的信息,避免了多次查询数据库

简单介绍JWT之后,这篇文章不详细讲解JWT,如果想详细了解JWT请关注后续博客

好了,JWT理解为传递安全信息的一种声明规范就可以了,我会从登陆生成token到认证详细进行说明,欢迎大家指明不足,也可以一起讨论----本次案例是微服务的登陆权限校验

首先微服务的知识我不在这里普及,先贴代码

 
/**
 * 创建jwt
 * @param id
 * @param subject
 * @param ttlMillis 过期的时间长度
 * @return jwt
 */
public static String createJWT(String id,String subject,long ttlMillis){

    //指定签名时候使用的签名算法,也就是header那部分,jjwt已经将这部分内容封装好了
    SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS512;
    //生成JWT的时间
    long nowMillis = System.currentTimeMillis();
    Date now = new Date(nowMillis);
    //创建payload的私有声明(根据特定的业务需要添加,如果要拿这个做验证,一般是需要和jwt的接收方提前沟通好验证方式的)
    Map<String,Object> clamis = new HashMap<String,Object>();
    clamis.put("uid","123456");
    clamis.put("user_name","admin");
    clamis.put("nickName","DASDA121");
    //生成签名的时候使用的密钥secret,这个方法在本地封装一般可以从本地配置文件中读取,切记这个秘钥不能外露哦。
    // 它就是你服务端的私钥,在任何场景都不应该流露出去。一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了。
    String key = generalKey();
    //下面就是为payload添加各种标准申明和私有声明了
    JwtBuilder builder = Jwts.builder()
                        .setClaims(clamis)//如果有私有声明,一定要先设置这个自己创建的私有声明这个是给builder的claim赋值,
                                          // 一旦写在标准的声明赋值之后,就是覆盖了那些标准的声明的

                        .setId(id)        //设置jti(JWT ID):是JWT的唯一标识,根据业务需要,这个可以设置为一个不重复的值,
                                          // 主要用来作为一次性token,从而回避重放攻击。
                        .setIssuedAt(now) //iat: jwt的签发时间
                        .setSubject(subject) //sub(Subject):代表这个JWT的主体,即它的所有人,这个是一个json格式的字符串
                                             // ,可以存放什么userid,roldid之类的,作为什么用户的唯一标志。
                        .signWith(signatureAlgorithm,key);//设置签名使用的签名算法和签名使用的秘钥

    if (ttlMillis >= 0) {
        long expMillis = nowMillis + ttlMillis;
        Date exp = new Date(expMillis);
        builder.setExpiration(exp);     //设置过期时间
    }
    return builder.compact();

}

以上是创建token 基于JWT声明规范(注释很多我就不再赘述),其中generalKey()方法没有贴出来,是生成签名的密钥,
可以自己定义运用一些加密算法生成字符串,不过认证的时候还要用到该密钥,所以前后要保持一致。
    

    然后什么时候认证?肯定是每次访问我们接口的时候,请求每次放入头部,

    因为本次案例是微服务,认证这块肯定放在网关(zuul)统一处理,详细代码如下:

 
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
log.info("send {} request to{}", request.getMethod(), request.getRequestURL().toString());
String access_Token =request.getHeader("access_token");
if(access_Token == null || access_Token.equals("")){
    log.warn("accessToken is empty");
    ctx.setSendZuulResponse(false);
    ctx.setResponseStatusCode(405);
    try {
        ctx.getResponse().getWriter().write("accessToken is empty");
    } catch (Exception e) {
}
    return ResultVOUtil.error(405,"accessToken is empty");
}else{
    Claims claims = null;
    try {
    //解密JWT
        claims = JwtUtil.parseJWT(access_Token);
    } catch (Exception e) {
        log.warn("accessToken is ERRO");
        ctx.setSendZuulResponse(false);
        ctx.setResponseStatusCode(405);
        try {
            ctx.getResponse().getWriter().write("accessToken is ERRO");
        } catch (IOException e1) {
            e1.printStackTrace();
        }
        return ResultVOUtil.error(405,"accessToken is ERRO");
    }
    log.warn("accessToken is ok");
    return true;


以上是认证过程,解密token如下:
 
/**
 * 解密jwt
 * @param jwt
 * @return
 * @throws Exception
 */
public static Claims parseJWT(String jwt) throws Exception{
    String key = generalKey();  //签名秘钥,和生成的签名的秘钥一模一样
    Claims claims = Jwts.parser()  //得到DefaultJwtParser
            .setSigningKey(key)         //设置签名的秘钥
            .parseClaimsJws(jwt).getBody();//设置需要解析的jwt
    return claims;
}


以上代码可以使用,如有疑问的话请加本人微信:a1498470355 欢迎一起讨论,

下一篇我会讲解微服务SpringCloud+Eureka




Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐