Java教程

JWT 用户校验学习:简易教程与实战演练

本文主要是介绍JWT 用户校验学习:简易教程与实战演练,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
概述

JWT用户校验学习是一项重要的技术,它通过JSON Web Token来实现用户身份验证和信息传递。本文详细介绍了JWT的工作原理、组成部分以及如何生成和验证JWT,帮助读者快速掌握JWT的使用方法。

1. JWT 简介

1.1 什么是 JWT

JWT(JSON Web Token)是一种开放标准(RFC 7519),用于在各方之间安全地将信息作为JSON对象传输。JWT的核心思想是通过一个紧凑且自包含的令牌来传递信息,该令牌可以被验证和信任,以确保信息的真实性。JWT通常用于身份验证和信息交换,在现代Web和移动应用中广泛应用。

1.2 JWT 的工作原理

JWT的工作原理可以分为三个主要步骤:

  1. 生成令牌:在用户成功登录的情况下,服务器会生成一个JWT令牌。令牌由三部分组成:头部(Header)、载荷(Payload)和签名(Signature)。头部包含令牌的类型和所使用的签名算法。载荷包含用户数据,如用户ID、用户名等。签名用于验证令牌的完整性和真实性。

  2. 签名验证:每次客户端尝试访问受保护的资源时,都会携带JWT令牌。后端需要验证这个令牌是否有效。验证过程包括检查签名是否与预期的密钥相匹配,以及载荷是否未被篡改。

  3. 信息传递:前端可以将JWT存储在本地(如localStorage或cookies),并在后续请求中包含它以获取所需资源。后端通过验证JWT来确认用户身份,确保请求的安全性。

1.3 JWT 与 Cookies 的区别

尽管两者都是用于存储和验证用户身份的技术,但它们在某些方面存在显著差异:

  • 存储机制

    • Cookies通常存储在用户的浏览器中,服务器可以在请求中读取或写入它们。
    • JWT是一个独立的令牌,通常存储在本地存储中,而不是浏览器的cookies。
  • 安全性

    • Cookies可以被设置为HTTPOnly,这样脚本就无法访问它们,但是它们仍然可以被注入到跨站请求伪造攻击中。
    • JWT不依赖于客户端存储的机制,而是直接作为令牌在HTTP头中传输,安全性更高。
  • 传输
    • Cookies会自动附加到每个客户端请求中,即使它们不需要,这可能会引入不必要的带宽消耗。
    • JWT只有在需要时才会被发送,这可以提高性能。

2. 基础概念

2.1 Header

Header是JWT的第一部分,通常包含两组信息:

  • alg:指定了所使用的签名算法,例如HS256(HMAC with SHA-256)。
  • typ:令牌的类型,通常是JWT

示例 Header JSON 格式如下:

{
    "alg": "HS256",
    "typ": "JWT"
}

Header的编码步骤:

  1. 将Header作为JSON字符串进行Base64编码。
  2. 将编码后的Header字符串作为JWT的头部部分。

2.2 Payload

Payload是JWT的第二部分,载荷包含了声明(Claims)。这些声明分三类:

  • 标准声明(如:iss - 颁发者,exp - 过期时间等)。
  • 公共声明(如:sub - 主题,iat - 发行时间等)。
  • 私有声明(仅用于开发人员自定义用途)。

示例 Payload JSON 格式如下:

{
    "sub": "1234567890",
    "name": "John Doe",
    "admin": true,
    "exp": 1618966440
}

Payload的编码步骤:

  1. 将Payload作为JSON字符串进行Base64编码。
  2. 将编码后的Payload字符串作为JWT的负载部分。

2.3 Signature

Signature是JWT的第三部分,用于验证整个JWT的完整性和真实性。JWT的签名由Header和Payload的Base64编码后的字符串以及一个私钥生成。

示例签名生成代码:

const jwt = require('jsonwebtoken');

const header = {
    alg: 'HS256',
    typ: 'JWT'
};

const payload = {
    sub: '1234567890',
    name: 'John Doe',
    admin: true,
    exp: 1618966440
};

const secret = 'mysecret';

const token = jwt.sign({ header, payload }, secret, { algorithm: 'HS256' });
console.log(token);

3. 实现步骤

3.1 生成 JWT

生成JWT需要三个组件:Header、Payload和Secret。Header和Payload已经定义,Secret是私钥,用于签名JWT。生成JWT的过程如下:

  1. 编码Header和Payload,然后连接。
  2. 使用Secret对连接后的字符串进行签名。
  3. 最后将Header、Payload和Signature用.分割,形成最终的JWT令牌。

示例代码:

const jwt = require('jsonwebtoken');

const header = {
    alg: 'HS256',
    typ: 'JWT'
};

const payload = {
    sub: '1234567890',
    name: 'John Doe',
    admin: true,
    exp: 1618966440
};

const secret = 'mysecret';

const token = jwt.sign(payload, secret, { algorithm: 'HS256' });
console.log(token);

生成JWT的具体过程:

  1. 编码Header和Payload:

    const headerEncoded = Buffer.from(JSON.stringify(header)).toString('base64');
    const payloadEncoded = Buffer.from(JSON.stringify(payload)).toString('base64');
  2. 将Header和Payload连接:

    const tokenBase = `${headerEncoded}.${payloadEncoded}`;
  3. 使用Secret进行签名:

    const signature = Buffer.from(tokenBase).toString('base64');
  4. 最终生成JWT:
    const token = `${tokenBase}.${signature}`;
    console.log(token);

3.2 验证 JWT

验证JWT的有效性,需要以下步骤:

  1. 拆分JWT令牌,获取Header、Payload和Signature。
  2. 使用Header中的算法和Payload重新生成Signature。
  3. 比较生成的Signature和原始Signature是否相同。

示例代码:

const jwt = require('jsonwebtoken');
const secret = 'mysecret';

function verifyToken(token) {
    try {
        const decoded = jwt.verify(token, secret, { algorithms: ['HS256'] });
        console.log('Token is valid:', decoded);
    } catch (error) {
        console.log('Token is invalid:', error);
    }
}

const token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMiwidXNlcklkIjoiMjM0NTY3ODkwIn0.Ww5TmV9l20FvV7cY909zC0ZJwT0UQOi27zX7XCZ0';

verifyToken(token);

3.3 解码 JWT

解码JWT意味着获取Header和Payload中的信息,但不验证Signature。

示例代码:

const jwt = require('jsonwebtoken');

const token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMiwidXNlcklkIjoiMjM0NTY3ODkwIn0.Ww5TmV9l20FvV7cY909zC0ZJwT0UQOi27zX7XCZ0';

const decoded = jwt.decode(token, { complete: true });
console.log('Decoded Header:', decoded.header);
console.log('Decoded Payload:', decoded.payload);

3.4 示例代码(使用 Node.js)

上述示例代码已经使用了Node.js的jsonwebtoken库来实现JWT的生成、验证和解码。jsonwebtoken是常用的JWT操作库,适合在Node.js环境中使用。以下是完整的实现步骤:

  1. 安装jsonwebtoken
npm install jsonwebtoken
  1. 生成JWT
const jwt = require('jsonwebtoken');

const payload = {
    id: 1,
    username: 'johndoe',
    isAdmin: true,
    exp: Math.floor(Date.now() / 1000) + (60 * 60) // 有效期为1小时
};

const secret = 'mysecretkey';

const token = jwt.sign(payload, secret, { algorithm: 'HS256' });
console.log(token);
  1. 验证JWT
const jwt = require('jsonwebtoken');
const secret = 'mysecretkey';

function verifyToken(token) {
    try {
        const decoded = jwt.verify(token, secret, { algorithms: ['HS256'] });
        console.log('Token is valid:', decoded);
    } catch (error) {
        console.log('Token is invalid:', error);
    }
}

const token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMiwidXNlcklkIjoiMjM0NTY3ODkwIn0.Ww5TmV9l20FvV7cY909zC0ZJwT0UQOi27zX7XCZ0';

verifyToken(token);
  1. 解码JWT
const jwt = require('jsonwebtoken');

const token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMiwidXNlcklkIjoiMjM0NTY3ODkwIn0.Ww5TmV9l20FvV7cY909zC0ZJwT0UQOi27zX7XCZ0';

const decoded = jwt.decode(token, { complete: true });
console.log('Decoded Header:', decoded.header);
console.log('Decoded Payload:', decoded.payload);

4. 常见问题与解决方案

4.1 JWT 存储

JWT通常存储在客户端的本地存储中,如localStoragesessionStorage。这些存储机制允许JWT在客户端持久化,以便在不同页面之间共享。

示例代码:

// 生成JWT后存储
localStorage.setItem('token', token);

// 从localStorage中获取JWT
const token = localStorage.getItem('token');

4.2 JWT 过期处理

JWT包含一个过期时间(exp字段),在验证JWT时会检查此字段。如果JWT已过期,验证将失败。

示例代码:

const jwt = require('jsonwebtoken');
const secret = 'mysecretkey';

function verifyToken(token) {
    try {
        const decoded = jwt.verify(token, secret, { algorithms: ['HS256'] });
        console.log('Token is valid:', decoded);
    } catch (error) {
        console.log('Token is invalid:', error);
    }
}

const token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMiwidXNlcklkIjoiMjM0NTY3ODkwIn0.Ww5TmV9l20FvV7cY909zC0ZJwT0UQOi27zX7XCZ0';

verifyToken(token);

4.3 JWT 安全性考虑

JWT的安全性主要依赖于密钥的安全管理。密钥需要保密,避免泄露。此外,JWT的过期时间应合理设置,以减少泄露风险。

示例代码:

const jwt = require('jsonwebtoken');

const payload = {
    id: 1,
    username: 'johndoe',
    isAdmin: true,
    exp: Math.floor(Date.now() / 1000) + (60 * 60) // 有效期为1小时
};

const secret = 'mysecretkey';

const token = jwt.sign(payload, secret, { algorithm: 'HS256' });
console.log('Token:', token);

4.4 常见错误与调试技巧

  • 签名错误:确保签名使用了正确的密钥和算法。
  • 过期令牌:确保验证过程中检查了过期时间。
  • 无效令牌:确保在生成和验证过程中使用的Payload一致。

调试技巧:

  • 使用jwt.decode函数查看生成的JWT内容。
  • 打印详细的错误信息,以便更好地定位问题。

示例代码:

const jwt = require('jsonwebtoken');

const token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMiwidXNlcklkIjoiMjM0NTY3ODkwIn0.Ww5TmV9l20FvV7cY909zC0ZJwT0UQOi27zX7XCZ0';

const decoded = jwt.decode(token, { complete: true });
console.log('Decoded Header:', decoded.header);
console.log('Decoded Payload:', decoded.payload);

5. 实战演练

5.1 创建用户登录接口

用户登录接口负责验证用户凭证,并生成JWT令牌。

示例代码:

const express = require('express');
const jwt = require('jsonwebtoken');
const app = express();

app.use(express.json());

const users = [
    { id: 1, username: 'johndoe', password: 'password123' },
    { id: 2, username: 'janedoe', password: 'password456' }
];

const secret = 'mysecretkey';

app.post('/login', (req, res) => {
    const { username, password } = req.body;

    const user = users.find(u => u.username === username && u.password === password);

    if (!user) {
        return res.status(401).json({ message: 'Invalid credentials' });
    }

    const payload = {
        id: user.id,
        username: user.username,
        exp: Math.floor(Date.now() / 1000) + (60 * 60) // 有效期为1小时
    };

    const token = jwt.sign(payload, secret, { algorithm: 'HS256' });

    res.json({ token });
});

app.listen(3000, () => {
    console.log('Server running on port 3000');
});

5.2 用户验证接口

用户验证接口用于检查JWT的有效性,确保用户有权访问系统内的资源。

示例代码:

app.get('/protected', (req, res) => {
    const token = req.headers.authorization?.split(' ')[1];

    if (!token) {
        return res.status(401).json({ message: 'No token provided' });
    }

    try {
        const decoded = jwt.verify(token, secret, { algorithms: ['HS256'] });
        res.json({ message: 'Access granted', user: decoded });
    } catch (error) {
        if (error.name === 'TokenExpiredError') {
            return res.status(401).json({ message: 'Token expired' });
        }
        res.status(403).json({ message: 'Invalid token', error: error.message });
    }
});

5.3 保护资源接口

保护资源接口是应用中的核心部分,任何请求都需要有效的JWT令牌来访问资源。

示例代码:

app.get('/resources', (req, res) => {
    const token = req.headers.authorization?.split(' ')[1];

    if (!token) {
        return res.status(401).json({ message: 'No token provided' });
    }

    try {
        const decoded = jwt.verify(token, secret, { algorithms: ['HS256'] });
        res.json({ message: 'Resource accessed', user: decoded });
    } catch (error) {
        if (error.name === 'TokenExpiredError') {
            return res.status(401).json({ message: 'Token expired' });
        }
        res.status(403).json({ message: 'Invalid token', error: error.message });
    }
});

5.4 代码实现与注释说明

以上代码展示了如何使用Node.js和Express创建一个完整的JWT认证系统。其中包含了用户登录接口、用户验证接口和保护资源接口的实现。

  1. 用户登录接口:接收用户凭证,验证成功后生成JWT。
  2. 用户验证接口:检查JWT的有效性并返回用户信息。
  3. 保护资源接口:确保请求携带有效的JWT,否则返回错误信息。

6. 总结与进阶

6.1 JWT 的应用场景

JWT广泛应用于现代Web和移动应用中,特别是在需要处理用户身份验证和信息传递的场景。JWT适用于以下场景:

  • 用户身份验证:确保用户身份的真实性。
  • 信息交换:安全地传递JSON对象。
  • 会话管理:替代传统的服务器端Session存储。

6.2 进一步学习资源推荐

  • 慕课网(imooc.com):提供了丰富的在线课程,涵盖从基础到高级的JWT学习路径。
  • 官方文档:参考jsonwebtoken库的官方文档,获取详细的API和示例代码。

6.3 常见框架集成(如 Express)

JWT可以集成到各种Web框架中,如Node.js的Express。以下是一些常见的集成步骤:

  1. 安装库

    npm install jsonwebtoken express
  2. 创建中间件

    • 验证JWT

      const jwt = require('jsonwebtoken');
      
      function authenticateToken(req, res, next) {
       const authHeader = req.headers['authorization'];
       const token = authHeader && authHeader.split(' ')[1];
      
       if (token == null) return res.sendStatus(401);
      
       jwt.verify(token, secret, (err, user) => {
           if (err) return res.sendStatus(403);
           req.user = user;
           next();
       });
      }
  3. 使用中间件

    • 保护路由

      const express = require('express');
      const app = express();
      
      app.use(express.json());
      app.use(authenticateToken);
      
      app.get('/protected', (req, res) => {
       res.json({ message: 'Resource accessed', user: req.user });
      });
      
      app.listen(3000, () => {
       console.log('Server running on port 3000');
      });

通过上述步骤,你可以在Express应用中轻松集成JWT,实现用户身份验证和资源保护。

这篇关于JWT 用户校验学习:简易教程与实战演练的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!