什么是JWT ? JWT简易快速入门

  • JWT介绍

  • JWT作用

    • 授权
    • 信息交换
  • 为何选择JWT ?

    • 基于传统的Session验证
    • 基于JWT验证
  • JWT结构

  • JWT+Spring Boot的使用

 

JWT介绍

以下是官网对于JWT的介绍

什么是JWT ? JWT简易快速入门_第1张图片

大概意思就是,Json Web Token(JWT)是一个开放标准,其定义了一个简洁且自包含的方式,以JSON对象的形式在各方之间安全的传递信息。传递的信息能被验证和信任,因为他是数字签名的。简单点说,即是通过JSON形式作为web应用中的令牌,用于在各方之间安全的将信息作为JSON对象进行传输。在数据传输过程中还可以完成数据加密,签名等相关处理。

 

JWT作用

授权

JWT使用最常见的方案。当用户登录后,后续该用户的每个请求将包括JWT,从而允许用户访问该令牌允许的路由,服务和资源。例:单点登录时当前广泛使用jwt的一项功能,因为其开销小而且可以在不同的域中使用。

信息交换

JWT是在各方面之间安全传输信息的好方法。因为可以对JWT进行签名(例如 : 使用公钥/私钥对),所以您可以确保发件人是真实的发件人。此外,由于签名是使用标头和有效负载计算的,因此还可以验证内容是否遭到篡改。

 

为何选择JWT ? 

要解决这个问题,首先要了解在传统Web开发中是如何使用Session来识别不同用户的。

基于传统的Session认证

-- 认证方式

http协议本身是一种无状态协议,这就意味着如果我们向我们的应用提供了用户名和密码来进行用户认证,那么下一次请求时,用户还要再一次进行用户认证才行,因为根据http协议,我们并不能知道是哪个用户发出的请求,为了让应用能识别出是哪个应用发起的请求,我们只能在服务器存储一份用户登录信息(session),并在相应时传递给浏览器(session id),在浏览器端保存(session id)到cookie中,以便下次请求时发送给我们应用(即下次请求从cookie中携带session id访问应用),这样应用就能识别请求来自哪个用户了。

 

-- 认证流程

什么是JWT ? JWT简易快速入门_第2张图片

首先,客户端会请求服务器,服务器校验成功后会将用户相关信息信息存储在服务端Session中,然后返回session id给客户端,存储在浏览器中的cookie,当该认证过的用户再次访问该服务器时就会携带cookie,服务端根据cookie中携带的session id查找与之匹配的session进行校验,从而完成认证。

 

-- 存在问题

1.每个用户经过应用认证之后,应用都需要在服务端做一次记录,以方便用户下次请求的鉴别。通常而言,session都是保存在内存中的,而随着认证用户的增多,服务端的开销会明显增大。

2.用户认证之后,服务端做认证记录,如果认证的记录被保存在内存中,那就意味着用户下次请求还必须请求在这台服务器上,这样才能拿到授权的资源。这种方式在分布式应用中会相应的限制负载均衡器的能力,也意味着限制了应用的扩展能力。

3. 因为是基于cookie来进行用户识别的,假设cookie被截获,用户就会很容易遭受跨站请求伪造攻击。

4. 在前后端分离系统中缺点更大:前后端分离在应用解耦后增加了部署的复杂性。通常用户一次请求就要转发多次。如果用session,每次携带session id到服务器,服务器还要查询用户信息。同时,如果用户很多,这些信息存储在服务器内存中会给服务器增加负担;以及CSRF(跨站伪造请求攻击)问题,session是基于cookie进行用户识别的,cookie若被截获,用户很容易遭受CSRF攻击。同时,session id是一个特征值,表达的信息不够丰富,不容易扩展,且若应用为多节点部署,那么还需要实现session共享机制,不方便集群应用。

 

基于JWT的认证

-- 认证流程

什么是JWT ? JWT简易快速入门_第3张图片

1. 前端通过web表单将自己的用户名和密码发送到后端的接口。这一过程一般是一个HTTP POST请求。建议的方式是通过SSL加密的传输(https协议),从而避免敏感信息嗅探。

2. 后端核对用户名和密码成功后,将用户的id等其他信息作为JWT Payload(负载),将其与头部分别进行Base64编码拼接后签名,形成一个JWT(Token)。形成的JWT形同一个xxxx.yyyy.zzzz的字符串。

3. 后端将JWT字符串作为登录成功的返回结果返回给前端。前端可以将返回的结果保存在localStorage或sessionStorage中,退出登录时前端删除保存的JWT即可。

4. 后端检查是否存在,以及验证JWT的有效性。例:检查签名是否正确、检查Token是否过期、检查Token接收方是否为自己(可选)。

5. 验证通过后后端使用JWT中包含的用户信息进行其他逻辑操作,返回相应结果。

 

-- 优势

1.简洁(compact):可以通过url,post参数或在HTTP header发送,因为数据量小,传输速度也很快。

2.自包含(Self-contained):负载中包含了许多用户所需要的信息,避免了多次查询数据库。

3.Token是以JSON加密的形式保存在客户端的,所以JWT是跨语言的,原则上任何web形式都支持。

4.不需要在服务端保存会话信息,特别适用于分布式微服务。

 

JWT结构

--令牌组成

标头Header:包含了令牌的类型以及其所使用的签名算法(例如HMAC SHA256或RSA),标头由着两部分组成,使用Base64编码组成JWT结构的第一部分。

什么是JWT ? JWT简易快速入门_第4张图片

 

有效载荷payload:包含声明。声明,即是有关实体(通常指用户)和其他数据的声明,同样使用Base64编码组成JWT的第二部分。

什么是JWT ? JWT简易快速入门_第5张图片

 

签名signature:前面两部分都是使用Base64进行编码,即前端可以解码从而获得编码后的信息,signature需要使用编码后的header和payload以及我们提供的一个秘钥,然后使用header中指定的算法进行签名,签名的作用是保证JWT没有被篡改过,这也是签名的目的,实际上签名是对header和payload进行签名,防止其中内容被篡改。假设有人对header或payload的内容编码后进行修改,再进行编码,最终加上之前的的其他部分组成新的JWT,发送到服务端,则服务端会判断出header和payload形成的签名和JWT携带过来的签名是否一致,在不知道服务器加密时使用的秘钥的话,得出来的签名也是不一样的。

例:HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload) , secret)

 

附图:JWT格式

什么是JWT ? JWT简易快速入门_第6张图片

 

--关于信息安全问题

Base64严格来说不是加密,是可以被解码,是可逆的,故在使用JWT传输数据的时候尽量不要存储敏感信息。

 

JWT+Spring Boot的使用

使用IDEA创建一个Spring Boot项目,略。

引入所需要的jar包


        
            com.auth0
            java-jwt
            3.10.3
        

写一个生成token的测试方法,我们在payload中存储了username,userId以及department的信息。

//自己指定的秘钥
    private static final String SIGNATURE = "AlexZheng1997%^&*JGSJjsvjdjhkagjd";

    //生成token
    @Test
    void contextLoads() {
        //获取一个Calendar类实例
        Calendar instance = Calendar.getInstance();
        //设置时间单位和时间
        instance.add(Calendar.SECOND,500);
        //创建一个JWT Builder
        String token = JWT.create()
//                .withHeader() //一般header默认就好
                .withClaim("username","张三") //payload
                .withClaim("userId",0001)
                .withClaim("department","001")
                .withExpiresAt(instance.getTime())  //指定令牌过期时间
                .sign(Algorithm.HMAC256(SIGNATURE)); //使用指定秘钥和算法进行签名

        System.out.println(token); //此token返回给客户端
    }

运行代码后控制台出现token

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJkZXBhcnRtZW50IjoiMDAxIiwiZXhwIjoxNjAwNTA1NjgxLCJ1c2VySWQiOjEsInVzZXJuYW1lIjoi5byg5LiJIn0.pH9rgnj04jEBRBlxMHH3gzL6t4CPpnWMYoLlOz9ODy8

上面就是生成的token(JWT),有效期为指定的500秒。接下来我们写一个方法来模拟后端接受并验证token是否正确。

   //验证token
    //客户端发送请求到达服务端
    @Test
    public void test(){
        //创建JWTVerifier对象指定加密的算法和秘钥
        JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(SIGNATURE)).build();
        //创建DecodeJWT获取JWTVerifier验证token后的结果,若验证失败则会报错
        DecodedJWT verify = jwtVerifier.verify("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9." +
                "eyJkZXBhcnRtZW50IjoiMDAxIiwiZXhwIjoxNjAwNTA1NjgxLCJ1c2VySWQiOjEsInVzZXJuYW1lIjoi5byg5LiJIn0." +
                "pH9rgnj04jEBRBlxMHH3gzL6t4CPpnWMYoLlOz9ODy8");
        //前面存储的信息
        System.out.println(verify.getClaim("username").asString());
        System.out.println(verify.getClaim("userId").asInt());
        System.out.println(verify.getClaim("department").asString());
        System.out.println("过期时间:"+verify.getExpiresAt());
//        //other way
//        System.out.println(verify.getClaims().get("username").asString());
//        System.out.println(verify.getClaims().get("userId").asInt());
//        System.out.println(verify.getClaims().get("department").asString());
    }

验证成功。

什么是JWT ? JWT简易快速入门_第7张图片

如有什么地方写错了,恳请各位大佬帮忙指正。

 

 

你可能感兴趣的:(JWT,数据安全)