Architecture
网络基础
Get 和 Post
GET
- 参数位置:URL(?key=value)
- 大小限制:
- 浏览器:约 2KB~8KB(不同浏览器不同)
- 服务器:默认 8KB 左右,超出返回 414 URI Too Long
- 特点:明文可见,可缓存,适合小数据(如搜索)
POST
- 参数位置:HTTP 请求体(Request Body)
- 大小限制:
- 服务器可配置(默认几 MB 到几 GB)
- 超出返回 413 Request Entity Too Large
- 特点:不可见,不缓存,适合大数据(如表单、文件上传)
Nginx
数据库
MySQL
Redis
ES
MongoDB
协作
Git 协同
安全
Web 安全
业务设计
JWT
概念
用于在网络应用间安全传输信息,通常用于身份验证和信息交换
其核心特点是通过紧凑且自包含的 JSON 对象传递数据,无需服务端存储会话状态。
- Header (头部) - 包含令牌类型和使用的哈希算法
- Token 类型:通常是 JWT。
- 加密算法:例如 HS256(HMAC SHA-256)、RS256(RSA SHA-256)等。
- Payload (负载) - 包含声明(用户信息和其他数据)
- 标准声明(Registered Claims):预定义的字段,如 iss(发行者)、exp (过期时间)、sub(主题)等。
- 公共声明(Public Claims):用户自定义的字段,例如用户 ID、用户名、角色等。
- 私有声明(Private Claims):在特定场景下使用的字段,通常用于内部系统。
- Signature (签名) - 用于验证消息在传递过程中没有被更改
import jwt
import datetime
from jwt.exceptions import ExpiredSignatureError, InvalidTokenError
# 密钥,实际应用中应该从安全的地方获取
SECRET_KEY = "your-256-bit-secret"
# 创建JWT
def create_jwt(user_id: str, username: str, is_admin: bool) -> str:
"""
创建JWT令牌
:param user_id: 用户ID
:param username: 用户名
:param is_admin: 是否是管理员
:return: JWT令牌字符串
"""
# 设置过期时间(例如30分钟后)
expiration_time = datetime.datetime.utcnow() + datetime.timedelta(minutes=30)
# 创建payload
payload = {
"sub": user_id, # 主题(通常是用户ID)
"username": username, # 自定义声明
"admin": is_admin, # 自定义声明
"exp": expiration_time, # 过期时间
"iat": datetime.datetime.utcnow() # 签发时间
}
# 生成JWT
token = jwt.encode(payload, SECRET_KEY, algorithm="HS256")
return token
执行过程
- 用户登录与令牌生成
- 用户通过用户名和密码发起登录请求。
- 服务端验证用户凭证,若验证成功,则使用 JWT 工具类生成令牌:
- Header:指定算法(如 HS256)和令牌类型(JWT)。
- Payload:包含用户信息(如用户 ID、角色)和声明(如过期时间 exp)。
- Signature:使用密钥对 Header 和 Payload 进行签名,确保令牌不可篡改。
- 客户端存储令牌
- 服务端将生成的 JWT 返回给客户端(通常通过响应体或 Header)。
- 客户端(如浏览器或移动端)将令牌存储在本地(如 LocalStorage 或 Cookie)。
- 请求携带令牌客户端在后续请求的 Authorization Header 中以 Bearer格式携带 JWT。
- 服务端验证令牌
- 拦截器/过滤器:Spring Boot 通过自定义拦截器或 Spring Security 过滤器链拦截请求,
- 提取并验证 JWT:
- 签名验证:使用密钥校验签名是否有效。
- 过期检查:检查 exp 字段是否过期。
- 用户信息提取:解析 Payload 中的用户信息(如用户 ID),用于后续权限控制。
- 授权与响应
- 若验证通过,服务端处理请求并返回数据。
- 若验证失败(如令牌过期或签名错误),返回 401 状态码或自定义错误信息。
优缺点
缺点:
- 不要存储敏感信息:JWT可以被解码,所以不要存储密码等敏感信息
- 使用HTTPS:防止令牌被拦截
- 设置合理的过期时间:减少令牌被盗用的风险
- 考虑刷新令牌机制:用于长期会话
- 妥善存储客户端令牌:使用HttpOnly cookies或安全的本地存储
PHP 短信验证码防刷机制
1)、时间限制:60 秒后才能再次发送从发送验证码开始,前端(客户端)会进行一个 60 秒的倒数,在这一分钟之内,用户是无法提交多次发送信息的请求的。这种方法虽然使用得比较普遍,但是却不是非常有用,技术稍微好点的人完全可以绕过这个限制,直接发送短信验证码。
2)、手机号限制:同一个手机号,24 小时之内不能够超过 5 条对使用同一个手机号码进行注册或者其他发送短信验证码的操作的时候,系统可以对这个手机号码进行限制,例如,24 小时只能发送 5 条短信验证码,超出限制则进行报错(如:系统繁忙,请稍后再试)。然而,这也只能够避免人工手动刷短信而已,对于批量使用不同手机号码来刷短信的机器,这种方法也是无可奈何的。
3)、短信验证码限制:30 分钟之内发送同一个验证码网上还有一种方法说:30 分钟之内,所有的请求,所发送的短信验证码都是同一个验证码。第一次请求短信接口,然后缓存短信验证码结果,30 分钟之内再次请求,则直接返回缓存的内容。对于这种方式,不是很清楚短信接口商会不会对发送缓存信息收取费用,如果有兴趣可以了解了解。
4)、前后端校验:提交 Token 参数校验这种方式比较少人说到,个人觉得可以这种方法值得一试。前端(客户端)在请求发送短信的时候,同时向服务端提交一个 Token 参数,服务端对这个 Token 参数进行校验,校验通过之后,再向请求发送短信的接口向用户手机发送短信。
5)、唯一性限制:微信产品,限制同一个微信 ID 用户的请求数量如果是微信的产品的话,可以通过微信 ID 来进行识别,然后对同一个微信 ID 的用户限制,24 小时之内最多只能够发送一定量的短信。
6)、产品流程限制:分步骤进行例如注册的短信验证码使用场景,我们将注册的步骤分成 2 步,用户在输入手机号码并设置了密码之后,下一步才进入验证码的验证步骤。
7)、图形验证码限制:图形验证通过后再请求接口用户输入图形验证码并通过之后,再请求短信接口获取验证码。为了有更好的用户体验,也可以设计成:一开始不需要输入图形验证码,在操作达到一定量之后,才需要输入图形验证码。具体情况请根据具体场景来进行设计。
8)、IP 及 Cookie 限制:限制相同的 IP/Cookie 信息最大数量使用 Cookie 或者 IP,能够简单识别同一个用户,然后对相同的用户进行限制(如:24 小时内最多只能够发送 20 条短信)。然而,Cookie 能够清理、IP 能够模拟,而且 IP 还会出现局域网相同 IP 的情况,因此,在使用此方法的时候,应该根据具体情况来思考。
9)、短信预警机制,做好出问题之后的防护以上的方法并不一定能够完全杜绝短信被刷,因此,我们也应该做好短信的预警机制,即当短信的使用量达到一定量之后,向管理员发送预警信息,管理员可以立刻对短信的接口情况进行监控和防护。
如何设计一个高并发的系统
- 数据库的优化,包括合理的事务隔离级别、SQL 语句优化、索引的优化
- 使用缓存,尽量减少数据库 IO
- 分布式数据库、分布式缓存
- 服务器的负载均衡
参考文档: https://mp.weixin.qq.com/s/Wp6ErsgUKOYOjry7eRczEQ