继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

JWT教程:轻松入门JWT认证

紫衣仙女
关注TA
已关注
手记 386
粉丝 71
获赞 334
概述

JWT教程详细介绍了JWT(JSON Web Token)的定义、工作原理及其组成部分,包括头部、负载和签名。文章还深入讲解了JWT认证流程、生成JWT的方法以及验证JWT的有效性和签名的步骤。此外,教程提供了JWT在Web应用和移动应用中的实际应用示例,帮助读者更好地理解和使用JWT。

1. JWT简介

1.1 什么是JWT

JWT(JSON Web Token)是一种开放标准(RFC 7519),用于在网络应用之间安全地传输信息。JWT通常用于身份验证和授权,它允许客户端通过HTTP请求携带少量的数据,这些数据经过了严格的加密处理,确保了数据的安全性。

JWT由三部分组成,分别是头部(Header)、负载(Payload)和签名(Signature),这三部分通过点号(.)连接在一起。

1.2 JWT的工作原理

当用户登录时,服务器验证用户名和密码,然后生成一个JWT。这个JWT被发送回客户端,客户端将它存储起来,以便后续的请求中使用。客户端在发送请求时,通常会将JWT放在HTTP请求头中的Authorization字段里。

服务器接收到请求后,会检查请求中的JWT是否有效。有效的JWT会包含一些信息,例如用户的标识符(如ID、用户名等),这些信息可以用于授权和访问控制。

1.3 JWT的组成部分

  1. 头部(Header)

    • 包含令牌的类型(通常是JWT)和所使用的签名算法(如HMAC SHA256RSA等)。
    • 示例头部:
      {
      "alg": "HS256",
      "typ": "JWT"
      }
  2. 负载(Payload)

    • 包含声明(claims),声明是关于实体(人、服务、资源)的声明。
      • 标准声明:例如iss(发行人)、sub(主题)、aud(受众)、exp(过期时间)、nbf(生效时间)、iat(发行时间)、jti(JWT ID)等。
      • 自定义声明:开发者可以根据需要添加自定义的声明,例如用户的ID、用户名等。
    • 示例负载:
      {
      "sub": "1234567890",
      "name": "John Doe",
      "admin": true
      }
  3. 签名(Signature)
    • 通过使用Header中指定的算法,对头部和负载的Base64编码后的字符串进行加密。
    • 示例签名:
      HMACSHA256(
      base64UrlEncode(header) + "." +
      base64UrlEncode(payload),
      secret
      )
2. JWT认证流程

2.1 请求与响应流程

  1. 客户端发起登录请求

    • 客户端发送包含用户名和密码的登录请求到服务器。
    • 示例请求:

      POST /login HTTP/1.1
      Host: localhost:3000
      Content-Type: application/json
      
      {
      "username": "john",
      "password": "123456"
      }
  2. 服务器验证用户身份

    • 服务器验证用户名和密码是否正确,验证通过后,服务器生成一个JWT。
    • 示例响应:

      HTTP/1.1 200 OK
      Content-Type: application/json
      
      {
      "token": "eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJzdWIiOiAibWFuYmVyIiwgImlhdCI6IDMxNDI3OTU2MzMsICJzdHJwIjogInRlc3QifQ.ASfzr2fZi6jPQhB9X3kx2x20b730XWzY1203jKQ"
      }
  3. 客户端携带JWT发起请求

    • 客户端获取到JWT后,将JWT存储起来,并在后续的请求中将JWT放在HTTP请求头的Authorization字段中。
    • 示例请求:
      GET /user HTTP/1.1
      Host: localhost:3000
      Authorization: Bearer eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJzdWIiOiAibWFuYmVyIiwgImlhdCI6IDMxNDI3OTU2MzMsICJzdHJwIjogInRlc3QifQ.ASfzr2fZi6jPQhB9X3kx2x20b730XWzY1203jKQ
  4. 服务器验证JWT

    • 服务器收到请求后,会解析HTTP请求头中的JWT,验证签名的有效性,检查JWT是否过期,最后从JWT中提取出必要的信息用于后续的处理。
    • 示例响应:

      HTTP/1.1 200 OK
      Content-Type: application/json
      
      {
      "username": "manny",
      "isLoggedIn": true
      }

2.2 签名与验证机制

  1. 生成签名

    • 通过签名算法(如HMAC SHA256)对头部和负载进行加密。
    • 示例代码:

      import jwt
      
      # 生成JWT
      token = jwt.encode({
       'sub': '1234567890',
       'name': 'John Doe',
       'admin': True
      }, 'secret', algorithm='HS256')
      print(token)
  2. 验证签名

    • 通过相同的签名算法对JWT进行验证。
    • 示例代码:

      import jwt
      
      # 解码和验证JWT
      payload = jwt.decode(token, 'secret', algorithms=['HS256'])
      print(payload)
3. 如何生成JWT

3.1 使用Python生成JWT

  1. 安装依赖

    • 使用pip安装PyJWT库。
    • 示例代码:
      pip install PyJWT
  2. 生成JWT

    • 使用jwt.encode方法生成JWT。
    • 示例代码:

      import jwt
      
      # 生成JWT
      token = jwt.encode({
       'sub': '1234567890',
       'name': 'John Doe',
       'admin': True
      }, 'secret', algorithm='HS256')
      
      print(token)

3.2 使用Java生成JWT

  1. 安装依赖

    • pom.xml中添加jjwt依赖。
    • 示例代码:
      <dependency>
       <groupId>io.jsonwebtoken</groupId>
       <artifactId>jjwt</artifactId>
       <version>0.9.1</version>
      </dependency>
  2. 生成JWT

    • 使用JwtBuilder创建JWT。
    • 示例代码:

      import io.jsonwebtoken.Jwts;
      import io.jsonwebtoken.SignatureAlgorithm;
      
      public class JwtExample {
       public static void main(String[] args) {
           String token = Jwts.builder()
                   .setSubject("1234567890")
                   .claim("name", "John Doe")
                   .claim("admin", true)
                   .signWith(SignatureAlgorithm.HS256, "secret")
                   .compact();
      
           System.out.println(token);
       }
      }

3.3 使用JavaScript生成JWT

  1. 安装依赖

    • 使用npm安装jsonwebtoken库。
    • 示例代码:
      npm install jsonwebtoken
  2. 生成JWT

    • 使用jwt.sign方法生成JWT。
    • 示例代码:

      const jwt = require('jsonwebtoken');
      
      const token = jwt.sign({
       sub: '1234567890',
       name: 'John Doe',
       admin: true
      }, 'secret', { algorithm: 'HS256' });
      
      console.log(token);
4. 如何验证JWT

4.1 验证JWT的有效性

  1. 安装依赖

    • 使用pip安装PyJWT库。
    • 示例代码:
      pip install PyJWT
  2. 验证JWT的有效性

    • 使用jwt.decode方法验证JWT的有效性。
    • 示例代码:

      import jwt
      
      try:
       payload = jwt.decode(token, 'secret', algorithms=['HS256'])
       print(payload)
      except jwt.ExpiredSignatureError:
       print("Token has expired")
      except jwt.InvalidTokenError:
       print("Invalid token")

4.2 验证JWT的签名

  1. 安装依赖

    • 使用pip安装PyJWT库。
    • 示例代码:
      pip install PyJWT
  2. 验证JWT的签名

    • 使用jwt.decode方法验证JWT的签名。
    • 示例代码:

      import jwt
      
      try:
       payload = jwt.decode(token, 'secret', algorithms=['HS256'])
       print(payload)
      except jwt.SignatureVerificationError:
       print("Signature verification failed")
      except jwt.InvalidTokenError:
       print("Invalid token")
5. JWT的实际应用

5.1 在Web应用中的使用

  1. 用户登录

    • 用户登录时,服务器验证用户名和密码,生成JWT并返回给客户端。
    • 客户端在后续的请求中携带JWT进行认证。
    • 示例代码:

      from flask import Flask, request, jsonify
      import jwt
      
      app = Flask(__name__)
      
      @app.route('/login', methods=['POST'])
      def login():
       username = request.json.get('username')
       password = request.json.get('password')
      
       if username == 'john' and password == '123456':
           token = jwt.encode({
               'sub': 'john',
               'name': 'John Doe',
               'admin': False
           }, 'secret', algorithm='HS256')
           return jsonify({'token': token})
       return jsonify({'error': 'Invalid credentials'}), 401
      
      @app.route('/user', methods=['GET'])
      def user():
       token = request.headers.get('Authorization', '').split(' ')[1]
       try:
           payload = jwt.decode(token, 'secret', algorithms=['HS256'])
           return jsonify(payload)
       except jwt.ExpiredSignatureError:
           return jsonify({'error': 'Token has expired'}), 401
       except jwt.InvalidTokenError:
           return jsonify({'error': 'Invalid token'}), 401
  2. 获取用户信息

    • 客户端发送带有JWT的请求,服务器验证JWT并返回用户信息。
    • 示例代码:

      from flask import Flask, request, jsonify
      import jwt
      
      app = Flask(__name__)
      
      @app.route('/login', methods=['POST'])
      def login():
       username = request.json.get('username')
       password = request.json.get('password')
      
       if username == 'john' and password == '123456':
           token = jwt.encode({
               'sub': 'john',
               'name': 'John Doe',
               'admin': False
           }, 'secret', algorithm='HS256')
           return jsonify({'token': token})
       return jsonify({'error': 'Invalid credentials'}), 401
      
      @app.route('/user', methods=['GET'])
      def user():
       token = request.headers.get('Authorization', '').split(' ')[1]
       try:
           payload = jwt.decode(token, 'secret', algorithms=['HS256'])
           return jsonify(payload)
       except jwt.ExpiredSignatureError:
           return jsonify({'error': 'Token has expired'}), 401
       except jwt.InvalidTokenError:
           return jsonify({'error': 'Invalid token'}), 401

5.2 在移动应用中的使用

  1. 用户登录

    • 用户登录时,服务器验证用户名和密码,生成JWT并返回给客户端。
    • 客户端在后续的请求中携带JWT进行认证。
    • 示例代码:

      import io.jsonwebtoken.Jwts;
      import io.jsonwebtoken.SignatureAlgorithm;
      import java.util.HashMap;
      import java.util.Map;
      
      public class JwtExample {
       public static void main(String[] args) {
           String token = Jwts.builder()
                   .setSubject("john")
                   .claim("name", "John Doe")
                   .claim("admin", false)
                   .signWith(SignatureAlgorithm.HS256, "secret")
                   .compact();
      
           System.out.println(token);
       }
      }
  2. 获取用户信息

    • 客户端发送带有JWT的请求,服务器验证JWT并返回用户信息。
    • 示例代码:

      import io.jsonwebtoken.Claims;
      import io.jsonwebtoken.Jwts;
      
      public class JwtExample {
       public static void main(String[] args) {
           String token = "eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJzdWIiOiAiam9obyIsICJuYW1lIjogIkpvaG4gRG9lIiwgImFkbWluIjogIjJuaW51cyJ9.LdK2y3pZtXzmnKo6cPvXa0eU5kPfZ6iPf370Q2j";
           try {
               Claims claims = Jwts.parser()
                       .setSigningKey("secret")
                       .parseClaimsJws(token)
                       .getBody();
      
               System.out.println(claims.getSubject());
               System.out.println(claims.get("name"));
               System.out.println(claims.get("admin"));
           } catch (Exception e) {
               e.printStackTrace();
           }
       }
      }
6. 常见问题与解答

6.1 JWT的存储方式

JWT可以通过以下方式存储:

  • 存储在前端

    • 本地存储:可以将JWT存储在浏览器的localStoragesessionStorage中。
    • HTTP-only Cookie:将JWT存储在HTTP-Only Cookie中,这样只能通过服务器端获取JWT。
    • 示例代码:
      
      // 存储在localStorage
      localStorage.setItem('token', token);

    // 存储在HTTP-only Cookie
    document.cookie = token=${token}; HttpOnly; Secure; SameSite=Strict;

  • 存储在后端
    • 将JWT存储在服务器端的会话中,当客户端需要时,通过请求获取JWT。
    • 示例代码:
      session['token'] = token

6.2 JWT的安全性问题

JWT的安全性问题包括但不限于以下几点:

  • 密钥泄露
    • 如果密钥泄露,任何人都可以生成有效的JWT。因此,密钥需要妥善保管,避免泄露。最好将密钥存储在安全的地方,并定期更换。
  • 篡改数据
    • 如果使用了不安全的算法(如HS256),攻击者可以通过篡改负载数据来获取敏感信息。因此,需要使用安全的算法,并确保JWT的签名算法能够防止篡改。
  • 过期时间
    • 设置合理的过期时间可以减少JWT被滥用的风险。过期时间设置得太短,可能会影响用户体验;设置得太长,可能增加风险。建议设置为合理的时长,既方便用户操作,又能保证安全性。
  • 跨站请求伪造(CSRF)攻击
    • 使用HTTP-only Cookie可以防止CSRF攻击。确保在前后端交互中使用HTTP-only Cookie存储JWT。
  • 公开传输
    • JWT通常通过HTTP协议传输,如果使用HTTPS协议,可以防止数据在传输过程中被窃取。建议在所有网络通信中使用HTTPS协议。
  • 存储位置
    • 将JWT存储在本地存储时,需要注意防止XSS攻击。确保客户端代码能够安全地处理JWT,避免恶意代码篡改或窃取JWT。

6.3 JWT与Cookie的区别

  • Cookie

    • 存储在客户端的HTTP协议头中。
    • 可以设置过期时间,过期后自动删除。
    • 使用HTTP-only Cookie可以防止XSS攻击,确保JWT的安全性。
    • 可以存储在服务器端的会话中,但会话的生命周期受到服务器端的限制。
    • 在浏览器中,Cookie可以被浏览器自动发送到服务器,方便实现后端的会话管理。
  • JWT
    • 存储在客户端,可以存储在本地存储或HTTP-only Cookie中。
    • 可以设置过期时间,但过期时间由JWT本身携带,更加灵活。
    • JWT本身携带了签名,可以防止数据被篡改。
    • 不依赖于服务器端的会话,可以在多个不同服务器之间传递,适用于分布式系统或微服务架构。
    • JWT可以存储在任意客户端环境中,不仅限于浏览器,还可以用于移动应用或服务器间通信。

通过以上介绍,相信你已经对JWT有了一个全面的了解,可以开始尝试在自己的项目中使用JWT进行认证和授权了。如果还有更多疑问,可以参考相关的技术文档或在社区中寻求帮助。

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP