JWT单点登录原理学习入门介绍了JWT的基础概念和工作原理,详细阐述了如何结合JWT实现单点登录,并提供了实际应用中的安全注意事项和实践教程。
1. JWT基础概念介绍1.1 什么是JWT
JWT(JSON Web Token)是一种开放标准(RFC 7519),用于在各方之间安全地传输信息。JWT是由三部分组成的字符串,中间用点(.
)分隔。这些部分分别是头部(Header)、载荷(Payload)和签名(Signature)。JWT可以用于多种场景,如用户认证、授权、信息交换等。
1.2 JWT的工作原理
JWT的工作原理可以分为以下几个步骤:
- 生成Token:服务端生成一个JWT,其中包含用户信息(如用户名、用户ID等)和可能的安全信息(如token的过期时间)。
- 验证Token:客户端在需要验证用户身份时,将JWT发送给服务端。服务端会通过JWT中的信息(如过期时间)来验证Token的有效性。
- 处理Token:如果Token验证成功,服务端可以处理用户的请求;如果验证失败,就拒绝请求。
1.3 JWT的基本组成部分
JWT由三个主要部分组成:
- Header:头部通常包含两种信息,分别是token类型(例如JWT)和加密算法(例如HMAC SHA256或RSA)。头部的结构如下:
{ "alg": "HS256", "typ": "JWT" }
- Payload:载荷是JWT的核心,通常包含声明(claims)。这些声明可以分为三大类:注册声明(registered claims)、公开声明(public claims)和私有声明(private claims)。注册声明有具体的定义,例如iss(发行者)、exp(过期时间)等。载荷的结构如下:
{ "sub": "1234567890", "name": "John Doe", "iat": 1516239022 }
-
Signature:签名确保JWT在传输过程中未被篡改。签名部分通过使用Header声明的加密算法,对Header和Payload进行编码,并进行加密。其生成方式如下:
import base64 import hashlib import hmac def create_signature(header, payload, secret): header_encoded = base64.urlsafe_b64encode(json.dumps(header).encode()).rstrip(b'=') payload_encoded = base64.urlsafe_b64encode(json.dumps(payload).encode()).rstrip(b'=') message = f"{header_encoded.decode()}.{payload_encoded.decode()}" signature = hmac.new(secret.encode(), message.encode(), hashlib.sha256).digest() return base64.urlsafe_b64encode(signature).rstrip(b'=').decode() header = {"alg": "HS256", "typ": "JWT"} payload = {"sub": "1234567890", "name": "John Doe", "iat": 1516239022} secret = 'secret' signature = create_signature(header, payload, secret)
2.1 单点登录的概念
单点登录(Single Sign-On,简称SSO)是一种身份验证机制,允许用户使用一组凭证(例如用户名和密码)登录一个系统后,无需再次输入凭证即可访问其他相关系统。它简化了用户身份验证过程,提高了用户体验。
2.2 SSO的优势和应用场景
优势:
- 提高用户体验:用户只需一次登录即可访问多个服务,避免了反复登录的繁琐。
- 简化系统维护:减少了系统之间重复的身份验证,从而减少了系统维护的工作量。
- 安全性增强:通过集中管理用户凭证,减少了密码泄露的风险。
应用场景:
- 企业内部系统:例如员工需要访问多个内部系统(如邮件系统、ERP系统等)。
- 跨应用服务:用户在一个网站上登录后,可以无需重新登录即可访问该网站内的其他应用。
- 跨域服务:用户在一个网站上登录后,可以无需重新登录即可访问该网站内的其他子域名或独立域名下的应用。
3.1 为什么要使用JWT实现SSO
使用JWT实现SSO有以下几个原因:
- 轻量级:JWT是一种基于JSON的认证协议,数据量小,适合在不同系统间传递。
- 无状态:JWT的验证过程只需要Token本身,不需要访问数据库或其他服务,减少了服务器的负担。
- 跨域支持:JWT可以存储在前端的LocalStorage或Cookie中,支持跨域的身份验证。
- 安全性:JWT使用数字签名(通常是HMAC),可以防止Token被篡改。
3.2 JWT实现SSO的基本流程
使用JWT实现SSO的流程大致如下:
- 用户登录:用户在登录页面输入用户名和密码,系统验证后生成JWT Token。
- Token存储:将生成的JWT Token存储在客户端(如LocalStorage或Cookie)。
- Token验证:用户访问需要验证身份的资源时,将Token发送给服务端。服务端验证Token的有效性。
- 权限控制:如果Token有效,则根据Token中的信息(如用户角色)进行权限控制。
- Token刷新:Token经过一定时间后会过期,用户需要通过刷新Token来延长其有效期。
4.1 创建JWT Token
创建JWT Token通常需要以下几个步骤:
-
生成Header:定义JWT的类型和加密算法。
import json import base64 def create_header(): header_data = { "alg": "HS256", "typ": "JWT" } header_encoded = base64.urlsafe_b64encode(json.dumps(header_data).encode()).rstrip(b'=').decode() return header_encoded
-
生成Payload:包含用户信息和其他声明。
def create_payload(user_id, username, expiration_time): payload_data = { "user_id": user_id, "username": username, "exp": expiration_time } payload_encoded = base64.urlsafe_b64encode(json.dumps(payload_data).encode()).rstrip(b'=').decode() return payload_encoded
-
生成Signature:使用Header和Payload生成签名。
import hmac import hashlib def create_signature(header, payload, secret): message = f"{header}.{payload}" signature = hmac.new(secret.encode(), message.encode(), hashlib.sha256).digest() return base64.urlsafe_b64encode(signature).rstrip(b'=').decode()
- 组合Token:将Header、Payload和Signature组合成完整的JWT。
def create_jwt_token(user_id, username, expiration_time, secret): header = create_header() payload = create_payload(user_id, username, expiration_time) signature = create_signature(header, payload, secret) return f"{header}.{payload}.{signature}"
4.2 验证JWT Token
验证JWT Token通常需要以下几个步骤:
-
分离Token:将Token拆分成Header、Payload和Signature。
def parse_jwt_token(token): parts = token.split('.') header = base64.urlsafe_b64decode(parts[0] + '===').decode() payload = base64.urlsafe_b64decode(parts[1] + '===').decode() signature = parts[2] return header, payload, signature
-
验证Signature:使用Header和Payload重新生成签名,并与Token中的签名进行比较。
def validate_signature(header, payload, signature, secret): expected_signature = create_signature(header, payload, secret) return signature == expected_signature
-
验证Payload:检查Payload中的声明是否有效,如过期时间等。
import json import time def validate_payload(payload): payload_data = json.loads(base64.urlsafe_b64decode(payload + '===').decode()) if 'exp' in payload_data and payload_data['exp'] < time.time(): return False return True
4.3 Token的存储与刷新
存储Token:
Token通常存储在前端的LocalStorage或Cookie中。
// 存储Token到LocalStorage
localStorage.setItem('token', 'your_jwt_token_here');
// 存储Token到Cookie
document.cookie = "token=your_jwt_token_here; path=/";
刷新Token:
Token通常包含一个过期时间,当Token过期时,可以通过刷新Token来延长其有效期。
def refresh_token(user_id, username, expiration_time, secret):
new_token = create_jwt_token(user_id, username, expiration_time, secret)
return new_token
5. JWT安全注意事项
5.1 如何保证JWT的安全
- 使用强加密算法:如HS256或RS256。
- 限制Token的有效时间:设置合理的过期时间,通常不超过几小时。
- 保护密钥:用于生成签名的密钥需要安全地存储和传输。
- 验证Token:每次使用Token时都要验证其有效性。
5.2 常见的安全问题及解决方案
安全问题:
- 密钥泄露:如果用于签名的密钥泄露,攻击者可以伪造Token。
- Token篡改:攻击者可以篡改Payload中的数据。
- Token盗用:攻击者可以盗用用户的Token进行非法操作。
解决方案:
- 使用HTTPS:确保Token只能通过安全的HTTPS传输。
- 限制Token权限:在生成Token时,限制Token的使用范围。
- Token刷新机制:当Token过期或需要更新权限时,刷新Token。
6.1 准备工作
为了实现一个简单的JWT单点登录系统,你需要以下环境:
- Python环境(如Python3.6+)
- Flask框架(用于构建简单的Web服务)
- PyJWT库(用于生成和验证JWT)
安装所需的库:
pip install pyjwt flask
6.2 步骤详解
- 创建JWT Token:在用户登录时生成JWT Token,并返回给客户端。
- 验证JWT Token:在用户请求资源时,验证JWT Token的有效性。
- 存储Token:将Token存储在客户端的LocalStorage或Cookie中。
- 刷新Token:当Token过期时,刷新Token以延长其有效期。
6.3 示例代码
以下是示例代码,展示了如何使用Python和Flask实现一个简单的JWT单点登录系统。
创建JWT Token
import json
import base64
import hmac
import hashlib
import time
import flask
from flask import Flask, request, jsonify
from flask_jwt_extended import JWTManager, jwt_required, create_access_token
app = Flask(__name__)
# 配置JWT参数
app.config['JWT_SECRET_KEY'] = 'super-secret' # 用于生成签名的密钥
jwt = JWTManager(app)
# 用户信息数据库(模拟)
users = {
'john': 'password',
'jane': 'secret'
}
@app.route('/login', methods=['POST'])
def login():
username = request.json.get('username', '')
password = request.json.get('password', '')
if username not in users or users[username] != password:
return jsonify({"error": "Invalid credentials"}), 401
# 生成JWT Token
token = create_access_token(identity=username, expires_delta=False)
return jsonify({"token": token})
@app.route('/protected', methods=['GET'])
@jwt_required()
def protected():
# 验证Token有效性的装饰器
return jsonify({"msg": "Access granted"}), 200
if __name__ == '__main__':
app.run(debug=True)
验证JWT Token
在上述代码中,已通过@jwt_required()
装饰器验证了Token的有效性,该装饰器会自动处理Token的验证过程。
存储Token
在客户端(如JavaScript)中,可以将Token存储在LocalStorage或Cookie中。
// 使用JavaScript存储Token到LocalStorage
fetch('/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
username: 'john',
password: 'password'
})
}).then(response => response.json())
.then(data => localStorage.setItem('token', data.token));
// 使用JavaScript存储Token到Cookie
document.cookie = "token=" + localStorage.getItem('token') + "; path=/";
刷新Token
当Token过期时,可以通过刷新Token来延长其有效期。
@app.route('/refresh', methods=['GET'])
@jwt_required(refresh=True)
def refresh():
current_user = get_jwt_identity()
new_token = create_access_token(identity=current_user, expires_delta=False)
return jsonify({"token": new_token})
通过以上步骤和示例代码,你可以实现一个简单的JWT单点登录系统。
共同學(xué)習(xí),寫下你的評論
評論加載中...
作者其他優(yōu)質(zhì)文章