JWT

JWT

前言:

jwt作为分布式的考点往往在面试中被聊到:

  • 什么是jwt?
  • jwt有什么优点呢?
  • 都在哪些场景使用过?

这连环三问你能接得住吗?

本文从以上几个面试高频问题入手,带领大家认识和了解jwt。

jwt

什么是jwt?

JSON Web Token (JWT)是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的。

简单点说就是基于json,用于签名和认证的token(令牌)。

结构

JWT通常由三部分组成: 头信息(header), 载体(payload)和签名(signature)。它们之间用圆点(.)连接,构成jwt。

例如:

xxxxx.yyyyy.zzzzz
头信息(header)

头信息描述了JWT使用的签名算法

header = '{"alg":"HS256","typ":"JWT"}'
  • token(令牌)的类型是jwt
  • HS256 表示使用了 HMAC-SHA256 来生成签名
  • 算法可以用其他的,如rsa等

通过base64对json进行编码 获得jwt的第一部分header

载体(payload)
payload = '{"username":"w_rcss","iat":1422779638}'//iat表示令牌生成的时间

通过base64对json进行编码 获得jwt的第二部分payload

签名(signature)

签名需要通过私有的key计算而成

/**
*
* 私有key
*/
key = 'secretkey'  

/**
*
* 未签名token
*/
unsignedToken = encodeBase64(header) + '.' + encodeBase64(payload)  //base64编码过的header和payload


/**
*
* 签名(signature)
*/
signature = HMAC-SHA256(key, unsignedToken) 

此时就获取到了signature,base64编码后再拼接(使用"."分隔)起来就是JWT了:

token = encodeBase64(header) + '.' + encodeBase64(payload) + '.' + encodeBase64(signature) 

# token看起来像这样: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJsb2dnZWRJbkFzIjoiYWRtaW4iLCJpYXQiOjE0MjI3Nzk2Mzh9.gzSraSYS8EXBxLN_oWnFSRgCzcmJmMjLiuyu5CSpyHI 

签名是用于验证消息在传递过程中是否被篡改,对于使用私钥签名的token,还可以验证JWT的发送方是否真实。

聊到这里,相必大家已经对jwt的结构有了清晰的认识,但是要注意,
payload和header用base64进行编码,而不是加密,所以不要在JWT的payload或header中放置敏感信息(如果一定要放,请加密)。

优点

说了这么多,JWT到底有哪些优点呢?

  • 相比于session,因为无需保存在服务器,所以不占用服务器内存
  • 无状态、可扩展性强:Session无法跨域,比如有3台机器(A、B、C)组成服务器集群,若session存在机器A上,session只能保存在其中一台服务器,此时你便不能访问机器B、C,因为B、C上没有存放该Session。jwt能够验证用户请求合法性,对服务器的影响几乎没有,更有利于服务器扩展
  • jwt支持了跨域访问

使用场景

虽然相比session有诸多优点,但是并不适合用jwt来代替session。接下来我们看看jwt适用场景有哪些。

JWT适合一次性操作的认证:
服务B你好, 服务A告诉我,我可以操作<JWT内容>, 这是我的凭证(即JWT)
  1. 服务A负责认证用户身份,并颁布一个很短过期时间的JWT给浏览器
  2. 浏览器在向服务B的请求中带上该JWT
  3. 服务B通过验证该JWT来判断用户是否有权执行该操作。这样,服务B就成为一个安全的无状态的服务了。
授权:

这是最常见的使用场景,解决单点登录问题。因为JWT使用起来轻便,开销小,服务端不用记录用户状态信息(无状态),所以使用比较广泛;

信息交换:

JWT是在各个服务之间安全传输信息的好方法。

  • 使用公钥/私钥对儿 - 可以确定请求方是合法的。
  • 使用标头和有效负载计算签名,还可以验证内容是否未被篡改。

代码示例

那如何代码实现jwt呢?

  1. 编写JWT(Java Web Token)操作类
public class JavaWebToken {
    private static Logger log = LoggerFactory.getLogger(JavaWebToken.class);

    //该方法使用HS256算法和Secret:bankgl生成signKey
    private static Key getKeyInstance() {
        //将用ApiKey签署我们的JavaWebToken
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary("bankgl");
        Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
        return signingKey;
    }

    //使用HS256签名算法和生成的signingKey最终的Token,claims是有效载体
    public static String createJavaWebToken(Map<String, Object> claims) {
        return Jwts.builder().setClaims(claims).signWith(SignatureAlgorithm.HS256, getKeyInstance()).compact();
    }

    //解析Token,同时也能验证Token,当验证失败返回null
    public static Map<String, Object> parserJavaWebToken(String jwt) {
        try {
            Map<String, Object> jwtClaims =
                    Jwts.parser().setSigningKey(getKeyInstance()).parseClaimsJws(jwt).getBody();
            return jwtClaims;
        } catch (Exception e) {
            log.error("jwt验证失败");
            return null;
        }
    }
}
  1. 编写登录Conreoller,在服务器端给客户返回token
public LoginStatusMessage checkUserAndPassword(
        @RequestParam(value = "username", required = true) String username,
        @RequestParam(value = "password", required = true) String password,User user,HttpServletRequest request)throws Exception{
        User u=new User();

        //登录成功
        if((u=userService.checkUsernameAndPassword(user))!=null){
            Map<String, Object> m=new HashMap<String, Object>();
            m.put("userid",user.getUserid());

            String token=JavaWebToken.createJavaWebToken(m);
            System.out.println(token);

            LoginStatusMessage lsm=new LoginStatusMessage();
            lsm.setUser(u);
            lsm.setToken(token);

            return lsm;
        };

        // 登录失败,返回Null
        return null;

        }
}
  1. 在拦截器中验证token
String token = request.getParameter("token");
if(JavaWebToken.parserJavaWebToken(token) != null){
    //表示token合法
     return true;
}else{
    //token不合法或者过期
     return false;JWT
}

总结

JWT相比Session减轻了服务器的内存压力,在分布式上可扩展性也更强,通过签名保证了传输数据的有效性和合法性,有诸多优点但是更适用于一次性的认证,并不能完全替代Session。具体的使用还需要根据具体的生产环境来具体分析。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值