OAuth2 vs Session vs JWT:一张表看懂三种认证方式

OAuth2 vs Session vs JWT:一张表看懂三种认证方式

认证方式对比

引言:选择困难症的终极问题

作为开发者,你可能经常纠结:我的App该用哪种认证方式?

Session、JWT、OAuth2……这些名词听起来都很高大上,但到底有什么区别?

今天,我用最白话的方式,给你讲明白这三种认证方式的区别。

第一章:三种认证方式的本质

一句话解释

  • Session:服务器记住你是谁
  • JWT:自己证明自己是谁
  • OAuth2:让别人证明你是谁

生活中的例子

Session就像酒店入住

  • 你办理入住,酒店给你房卡
  • 酒店在系统里记录你的信息
  • 你用房卡开门,酒店验证你的身份
  • 你退房,酒店删除你的记录

JWT就像身份证

  • 你有一张身份证
  • 身份证上有你的信息
  • 任何人看到身份证都知道你是谁
  • 身份证有有效期,过期了就不能用

OAuth2就像代取快递

  • 你让朋友帮你取快递
  • 你给朋友一个授权码
  • 朋友拿着授权码去取快递
  • 快递员验证授权码,把快递给朋友

第二章:Session认证

工作原理

1
2
3
4
5
6
7
8
9
用户 → 输入用户名密码

服务器 → 验证密码,创建Session

服务器 → 返回Session ID(Cookie)

用户 → 每次请求带上Session ID

服务器 → 验证Session ID,返回数据

优点

优点 说明
简单 实现简单,学习成本低
安全 令牌存储在服务端,安全
可控 服务端可以随时撤销Session
成熟 大量框架支持

缺点

缺点 说明
扩展性差 多服务器需要共享Session
内存占用 每个用户都要存储Session
跨域困难 Cookie有跨域限制
不适合API 不适合RESTful API

适用场景

  • 传统Web应用:有服务端渲染
  • 单体应用:不需要跨域
  • 对安全要求高:需要服务端控制

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
from flask import Flask, session

app = Flask(__name__)
app.secret_key = 'your-secret-key'

@app.route('/login', methods=['POST'])
def login():
username = request.form['username']
password = request.form['password']

# 验证密码
if verify_password(username, password):
session['user_id'] = get_user_id(username)
session['logged_in'] = True
return '登录成功'

return '登录失败', 401

@app.route('/profile')
def profile():
if not session.get('logged_in'):
return '未登录', 401

user_id = session['user_id']
return get_user_profile(user_id)

第三章:JWT认证

工作原理

1
2
3
4
5
6
7
8
9
用户 → 输入用户名密码

服务器 → 验证密码,生成JWT

服务器 → 返回JWT

用户 → 每次请求带上JWT

服务器 → 验证JWT签名,返回数据

JWT的结构

JWT由三部分组成:

1
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
  • Header:算法和类型
  • Payload:用户信息
  • Signature:签名,防篡改

优点

优点 说明
无状态 服务端不需要存储
扩展性好 适合分布式系统
跨域支持 可以在任何地方使用
自包含 包含用户信息

缺点

缺点 说明
不能撤销 一旦签发,无法撤销
体积大 比Session ID大
安全风险 实现不当可能泄露信息
续期复杂 过期后需要重新获取

适用场景

  • RESTful API:无状态API
  • 微服务:服务间通信
  • 单页应用:前端渲染
  • 移动App:原生应用

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import jwt
from datetime import datetime, timedelta

SECRET_KEY = 'your-secret-key'

def create_jwt(user_id):
payload = {
'sub': user_id,
'iat': datetime.utcnow(),
'exp': datetime.utcnow() + timedelta(hours=1)
}
return jwt.encode(payload, SECRET_KEY, algorithm='HS256')

def verify_jwt(token):
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=['HS256'])
return payload['sub']
except jwt.ExpiredSignatureError:
return None # 令牌过期
except jwt.InvalidTokenError:
return None # 令牌无效

@app.route('/profile')
def profile():
token = request.headers.get('Authorization').replace('Bearer ', '')
user_id = verify_jwt(token)

if not user_id:
return '未授权', 401

return get_user_profile(user_id)

第四章:OAuth2认证

工作原理

1
2
3
4
5
6
7
8
9
用户 → 点击"微信登录"

App → 跳转到微信授权页面

微信 → 用户确认授权,返回授权码

App → 用授权码换访问令牌

App → 用访问令牌获取用户信息

优点

优点 说明
安全 密码不泄露
标准 行业标准,广泛支持
灵活 支持多种授权流程
用户友好 一键登录

缺点

缺点 说明
复杂 实现复杂,学习成本高
依赖第三方 依赖授权服务器
配置繁琐 需要注册应用、配置回调

适用场景

  • 第三方登录:微信、GitHub登录
  • API授权:允许第三方访问用户数据
  • 单点登录:一次登录,到处使用

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import requests

CLIENT_ID = 'your-client-id'
CLIENT_SECRET = 'your-client-secret'
REDIRECT_URI = 'https://your-app.com/callback'

def get_wechat_auth_url():
return f"https://open.weixin.qq.com/connect/oauth2/authorize?" + \
f"appid={CLIENT_ID}&" + \
f"redirect_uri={REDIRECT_URI}&" + \
f"response_type=code&" + \
f"scope=snsapi_userinfo"

def get_wechat_token(code):
url = "https://api.weixin.qq.com/sns/oauth2/access_token"
data = {
'appid': CLIENT_ID,
'secret': CLIENT_SECRET,
'code': code,
'grant_type': 'authorization_code'
}
response = requests.get(url, params=data)
return response.json()['access_token']

def get_wechat_user_info(access_token, openid):
url = "https://api.weixin.qq.com/sns/userinfo"
params = {
'access_token': access_token,
'openid': openid,
'lang': 'zh_CN'
}
response = requests.get(url, params=params)
return response.json()

第五章:三种方式对比

一张表对比

维度 Session JWT OAuth2
本质 服务端存储 自包含令牌 授权框架
状态 有状态 无状态 取决于实现
存储位置 服务端 客户端 客户端
扩展性
安全性
跨域 困难 容易 容易
撤销 容易 困难 容易
适用场景 传统Web API 第三方授权

选择决策树

1
2
3
4
5
你的App需要第三方登录吗?
├── 是 → 使用OAuth2
└── 否 → 你的App是API服务吗?
├── 是 → 使用JWT
└── 否 → 使用Session

组合使用

在实际项目中,这三种方式可以组合使用

场景一:OAuth2 + JWT

  • 用OAuth2获取授权
  • 用JWT作为令牌格式
  • 优点:安全且无状态

场景二:Session + JWT

  • 用Session管理用户状态
  • 用JWT作为API令牌
  • 优点:兼顾安全和性能

第六章:实战建议

新项目推荐

项目类型 推荐方案 原因
传统Web应用 Session 简单、安全
RESTful API JWT 无状态、扩展性好
单页应用 JWT 跨域友好
移动App JWT + OAuth2 安全且支持第三方登录
微服务 JWT 服务间通信
企业应用 OAuth2 + Session 安全且可控

迁移建议

从Session迁移到JWT

  1. 逐步替换,不要一次性迁移
  2. 保持向后兼容
  3. 充分测试

添加OAuth2支持

  1. 使用成熟的OAuth2库
  2. 不要自己实现
  3. 遵循最佳实践

第七章:常见问题

Q1:JWT比Session更安全吗?

:不一定。JWT的安全性取决于实现方式。错误的JWT实现可能比Session更危险。

Q2:OAuth2是认证协议吗?

:不是。OAuth2是授权协议。OpenID Connect才是认证协议,它建立在OAuth2之上。

Q3:我应该自己实现JWT吗?

强烈不推荐。使用成熟的JWT库,如PyJWT、jsonwebtoken等。

Q4:Session过时了吗?

:没有。Session在传统Web应用中仍然是最佳选择。

总结

核心要点

  1. Session:服务端存储,简单安全,适合传统Web应用
  2. JWT:无状态,扩展性好,适合API和微服务
  3. OAuth2:授权框架,适合第三方登录和API授权
  4. 组合使用:根据场景选择合适的组合

选择建议

  • 简单Web应用:Session
  • RESTful API:JWT
  • 第三方登录:OAuth2
  • 微服务:JWT
  • 企业应用:OAuth2 + Session

给开发者的建议

  • 不要盲目追新:选择适合场景的方案
  • 安全第一:任何方案都要注意安全
  • 使用成熟库:不要自己实现认证逻辑
  • 持续学习:认证技术在不断演进

没有最好的认证方式,只有最适合的认证方式。