JWT的简单介绍

大家好,我是IT修真院深圳分院第11期学员,一枚正直善良的JAVA程序员。

今天给大家分享一下,修真院官网JAVA任务5中需要使用的JWT


1.背景介绍

        HTTP 是一种没有状态的协议,一旦数据交换完毕,客户端与服务器端的连接就会关闭,再次交换数据需要建立新的连接。也就导致服务器无法分辨是谁浏览了网页。为了维持用户在网站的状态,比如登陆、购物车等,出现了先后出现了四种技术。为了保证数据安全可靠地在用户与服务端之间传输,实现服务端的认证就显得极为必要。

        常见的服务端认证方法有基于 Cookie-Session的认证;以及 Token (令牌)认证,如 JWT。前者客户端在每次请求时都需要带上 cookie ,取出相应字段并与服务器端的进行对比,以实现身份的认证。而后者仅仅需要在 HTTP 的头部或者使用Cookie附上 token,由服务器 check signature 即可实现,无须担心 cookie 存在的 CORS 问题。


2.知识剖析

什么是JWT

JWT 是一套开放的标准(RFC 7519),它定义了一套简洁的(compact)、自包含的(self-contained)方案,来让我们安全地在客户端和服务器之间传输 JSON 格式的信息。

Token身份验证基本流程

1). 客户端使用自己的账号密码发送 post 请求登录

2). 由于这是首次接触,服务器会校验账号与密码是否合法

3). 如果一致,则根据密钥生成一个 JWT 并返回

4). 客户端收到这个 token 并保存在本地

5). 客户端需要访问一个受保护的资源时,只要附加上JWT发送到服务器

6). 服务器就会检查这个 token 是否有效,并做出响应

JWT的组成

JWT 标准的 Token 有三个部分:header、payload、signature。

JWT = Base64(Header) + "." + Base64(Payload) + "." + $Signature

$Signature:HS256(Base64(Header) + "." + Base64(Payload), secretKey)

Payload 部分(载荷)

1、 sub: 该JWT所面向的用户;

2、 iss: 该JWT的签发者;

3、 iat(issued at): 在什么时候签发的token;

4、 exp(expires): token什么时候过期;

5、 nbf(not before):token在此时间之前不能被接收处理

6、 jti:JWT ID为web token提供唯一标识。

Signature 部分(签名)

1、 用 Base64 编码的 header.payload

2、 HS256加密算法加密(将密钥存储在服务端)


3.编码实战

1.搜索找到jar包和工具类;

2.分析工具类:

//生成JWT
//公有 静态 返回值:String sign:签名 (形参:1:泛型,2:long)
public static <T> String sign(T object, long maxAge) {
    try {
        //设置密钥
        final JWTSigner signer = new JWTSigner(SECRET);
        //Map集合(字符串:形参1:泛型)
        final Map<String, Object> claims = new HashMap<String, Object>();
        //JSON和对象的转换类
        ObjectMapper mapper = new ObjectMapper();
        //将参数1:泛型,转换为字符串JSON形式
        String jsonString = mapper.writeValueAsString(object);
        //Map集合添加元素:荷载,参数1的泛型
        claims.put(PAYLOAD, jsonString);
        //Map集合添加元素:有效时间,当前时间戳+形参2:有效时间
        claims.put(EXP, System.currentTimeMillis() + maxAge);
        //返回加密后的密钥
        return signer.sign(claims);
    } catch(Exception e) {
        return null;
    }
}
//解析JWT,验证JWT,验证成功获得荷载
//公有 静态 解密钥 参数(参数1:字符串jwt,参数2:泛型类)
public static<T> T unsign(String jwt, Class<T> classT) {
    //常量:设置密钥
    final JWTVerifier verifier = new JWTVerifier(SECRET);
    final JWTSigner signer = new JWTSigner(SECRET);
    try {
        //常量:Map<字符串:Object> 参数1.解密
        final Map<String,Object> claims= verifier.verify(jwt);
        //如果Map集合中有"EXP"和"PAYLOAD"的键值对
        if (claims.containsKey(EXP) && claims.containsKey(PAYLOAD)) {
            //获得当时的时间戳+有效时间
            long exp = (Long)claims.get(EXP);
            //获得当前时间戳
            long currentTimeMillis = System.currentTimeMillis();
            //判断是否有效
            if (exp > currentTimeMillis) {
                //有效的话,获得荷载中的内容
                String json = (String)claims.get(PAYLOAD);
                if(signer.sign(claims).equals(jwt)){
                    //对象与JSON转换类
                    ObjectMapper objectMapper = new ObjectMapper();
                    //将荷载中的JSON数据转为形参2:泛型
                    return objectMapper.readValue(json, classT);
                }
            }
        }
        return null;
    } catch (Exception e) {
        return null;
    }
}

编写测试代码:

public static void main(String[] args) {
    Student student=new Student();
    student.setName("希尔瓦娜斯");
    student.setId(1);
    student.setOid(0);

    //将学员对象作为荷载,有效时间30分钟
    String jwt=JWT.sign(student,1000L*60*30);
    //输出jwt
    System.out.println("JWT: "+jwt);

    //解析jwt获得荷载中的对象
    Student s=JWT.unsign(jwt,Student.class);
    //输出对象
    System.out.println("荷载: "+s);
}

运行:


4.常见问题

1、 用户匹配

服务端在生成token时,加入少量的用户信息,比如用户的id。服务端接收到token之后,可以解析出这些数据,从而将token和用户关联了起来。

2、 防伪造

建议放入token的数据是不敏感的数据,这样只要服务端使用私钥对数据生成签名,然后和数据拼接起来,作为token的一部分即可

基于加密的算法,对数据进行加密,把加密的结果作为token

3、 防冒充

1) 加干扰码

服务端在生成token时,使用了客户端的UA作为干扰码对数据加密,客户端进行请求时,会同时传入token、UA,服务端使用UA对token解密,从而验证用户的身份。

2) 有效期

给token加上有效期,即使被冒充也只是在一定的时间段内有效。每次服务端接收到请求,解析token之后,判断是否已过期,如果过期就拒绝服务。


5.参考文献

百度

CSDN


6.拓展思考

JWT应用场景

一次性验证

比如用户注册后需要发一封邮件让其激活账户,通常邮件中需要有一个链接,这个链接需要具备以下的特性:能够标识用户,该链接具有时效性(通常只允许几小时之内激活),不能被篡改以激活其他可能的账户…这种场景就和 jwt 的特性非常贴近,jwt 的 payload 中固定的参数:iss 签发者和 exp 过期时间正是为其做准备的。

restful api 的无状态认证

使用 jwt 来做 restful api 的身份认证也是值得推崇的一种使用方案。客户端和服务端共享 secret;过期时间由服务端校验,客户端定时刷新;签名信息不可被修改…spring security oauth jwt 提供了一套完整的 jwt 认证体系,以笔者的经验来看:使用 oauth2 或 jwt 来做 restful api 的认证都没有大问题,oauth2 功能更多,支持的场景更丰富,后者实现简单。


7.更多讨论


8.感谢观看

鸣谢,感谢观看

猜你喜欢

转载自blog.csdn.net/qq_41829464/article/details/81020864
今日推荐