如何基于用户名密码生成JWT令牌及AR-JWT令牌?
如何基于用户名密码生成JWT令牌及AR-JWT的实现方法
嘿,我来帮你梳理下基于用户名密码生成JWT,以及AR-JWT的实现方法——这俩在API认证场景里都挺常用的,话不多说直接上干货:
一、基于用户名密码生成普通JWT令牌
核心流程
这是最常见的API认证流程,步骤很清晰:
- 用户向服务端的认证端点(比如
/login)发送POST请求,携带用户名和密码 - 服务端验证凭证:通常是把用户提交的密码哈希后,和数据库中存储的哈希值比对
- 验证通过后,服务端生成包含用户身份信息的JWT,返回给客户端
- 后续客户端请求API时,在请求头里带上
Authorization: Bearer <token>即可
JWT的结构拆解
JWT由三个Base64URL编码的部分组成,用.分隔:
- Header:指定签名算法(比如HS256对称加密、RS256非对称加密)和令牌类型(固定为
JWT) - Payload:存放用户ID、角色、过期时间等声明(注意:Payload是明文编码的,绝对不能放密码、手机号这类敏感信息)
- Signature:用密钥对Header+Payload的组合进行签名,防止令牌被篡改
代码示例
Node.js(使用jsonwebtoken库)
const jwt = require('jsonwebtoken'); // 假设服务端已经验证用户名密码通过,拿到用户信息 const authenticatedUser = { id: 123, username: 'john_doe', role: 'editor' }; const serverSecret = 'your_strong_production_secret'; // 生产环境一定要用环境变量存储,别硬编码! // 生成JWT,设置1小时过期,用HS256算法 const accessToken = jwt.sign(authenticatedUser, serverSecret, { expiresIn: '1h', algorithm: 'HS256' }); console.log('生成的JWT令牌:', accessToken);
Python(使用PyJWT库)
import jwt from datetime import datetime, timedelta # 验证通过后的用户信息 authenticated_user = {"id": 123, "username": "john_doe", "role": "editor"} server_secret = "your_strong_production_secret" expiry_time = datetime.utcnow() + timedelta(hours=1) # 生成JWT access_token = jwt.encode( {"user": authenticated_user, "exp": expiry_time}, server_secret, algorithm="HS256" ) print("生成的JWT令牌:", access_token)
关键注意事项
- 生产环境优先用非对称加密算法(比如RS256):签名用服务端私钥,验证用公钥,比对称的HS256更安全
- 用户密码必须哈希存储(用bcrypt、Argon2这类算法),绝对不能明文存在数据库里
- JWT一旦生成无法撤销,所以过期时间不要设置太长,可配合刷新令牌机制实现长期登录
二、AR-JWT(Attestation JWT)的生成方法
AR-JWT全称是Attestation JWT,主要用于设备认证、强身份验证场景——它在普通JWT基础上增加了「身份证明」相关的字段,用来确认请求者是可信的设备/实体,而不是随便伪造的请求。
核心特点
- 几乎都用非对称加密签名:私钥由设备/客户端持有,服务端用公钥验证
- 包含专属声明字段,常见的有:
nonce:服务端下发的随机值,防止重放攻击x5c:证书链,用来证明客户端的公钥是由可信CA签发的attestation_type:证明类型(比如basic基础证明、self自签名证明)device_info:设备硬件型号、操作系统版本等信息
生成流程
- 服务端先给客户端/设备下发一个唯一的
nonce(随机字符串) - 客户端生成密钥对(或使用预存的设备专属密钥)
- 构造AR-JWT的Payload,包含
nonce、设备ID、设备信息等 - 用客户端私钥对JWT进行签名,同时在Header里带上证书链
x5c - 客户端把AR-JWT发送给服务端,服务端验证签名、证书链、
nonce合法性后,确认身份
代码示例(Node.js模拟设备生成AR-JWT)
const jwt = require('jsonwebtoken'); const fs = require('fs'); // 设备的私钥和证书链(假设设备有CA签发的证书) const devicePrivateKey = fs.readFileSync('device_private_key.pem', 'utf8'); const certificateChain = [ fs.readFileSync('device_cert.pem', 'utf8').replace(/(\r\n|\n|\r)/gm, ''), // 去掉换行符 fs.readFileSync('root_ca_cert.pem', 'utf8').replace(/(\r\n|\n|\r)/gm, '') ]; // 服务端下发的nonce const serverNonce = 'unique_nonce_abc123xyz'; // AR-JWT的Payload const attestationPayload = { sub: 'device_123456', // 设备唯一ID nonce: serverNonce, attestation_type: 'basic', device_info: { model: 'iPhone 15', os_version: 'iOS 17.4' }, exp: Math.floor(Date.now() / 1000) + 3600 // 1小时过期 }; // 生成AR-JWT const arJwtToken = jwt.sign(attestationPayload, devicePrivateKey, { algorithm: 'RS256', header: { x5c: certificateChain } }); console.log('生成的AR-JWT令牌:', arJwtToken);
服务端验证要点
- 用证书链中的公钥验证JWT签名是否合法
- 检查证书链是否由可信的根CA签发
- 验证
nonce是否是服务端下发的,且未被使用过 - 检查令牌是否过期
内容的提问来源于stack exchange,提问作者Udara Jayawardana
相关产品推荐
相关产品推荐

