访问控制
企业需求 🔐
一个周一的上午,我收到一封企业客户的邮件:
“你好,我们的内部文档链接,不想让外部人员访问。能不能加个密码?”
另外,有些链接只想让公司内部的人访问,可以按IP限制吗?
我意识到,短链接服务已经不能只是简单的”点击即跳转”了。企业用户有强烈的安全需求——他们需要访问控制。
访问控制(Access Control)是保护资源不被未授权用户访问的机制。在短链接场景中,我需要实现多层防护:
- 密码保护:只有知道密码的人才能访问
- IP白名单:只允许特定IP地址访问
- 访问次数限制:只允许前N个人访问
- 时间窗口限制:只在特定时间段内可访问
让我逐一实现这些功能。
| 字段 | 类型 | 说明 |
|---|---|---|
| id | BIGINT | 全局 ID |
| short_code | VARCHAR(16) | 短码,唯一索引 |
| long_url | VARCHAR(2048) | 原始 URL |
| status | VARCHAR(20) | 跳转状态 |
| risk_level | VARCHAR(20) | 风险等级 |
| audit_status | VARCHAR(20) | 审核状态 |
| blocked_reason | TEXT | 封禁原因 |
密码保护 🔑
为什么需要密码保护?
密码保护是最基础也是最常用的访问控制方式。企业客户用它来保护:
- 内部文档链接
- 限时优惠链接
- 私密分享的文件
- 测试环境的入口
我面临的第一个问题是:如何安全地存储密码?
数据库设计
我需要在 urls 表中添加密码相关字段:
数据设计要点
- 这是一次表结构演进:随着链接管理能力增加,把新状态、新时间点或新归属关系补进数据模型。
密码哈希:为什么不用 MD5?
在实现密码存储时,我需要考虑安全性。很多人会用 MD5 或 SHA1 来哈希密码:
落地思路
- 这里省略具体语法,只保留设计层面的职责边界。
- 读这段时重点看:输入是什么、系统做哪些判断、状态如何变化、失败时如何兜底。
为什么不这样做?
MD5 和 SHA1 是快速哈希算法,设计初衷是快速计算校验和,而非安全存储密码。攻击者可以:
- 彩虹表攻击:预先计算常见密码的哈希值(如 “123456”、“password”),然后用查表方式破解
- 暴力破解:因为计算速度快,一秒钟可以尝试数十亿次
使用 bcrypt:正确的做法
我选择了 bcrypt——专门为密码哈希设计的算法:
落地思路
- 这里省略具体语法,只保留设计层面的职责边界。
- 读这段时重点看:输入是什么、系统做哪些判断、状态如何变化、失败时如何兜底。
bcrypt 的优势:
- 自动加盐:每次生成的哈希都不同,防止彩虹表攻击
- 计算成本可调:通过 work factor 参数控制计算时间,增加暴力破解成本
- 抗GPU攻击:算法设计使得GPU并行计算优势不明显
创建带密码的短链接
落地思路
- 这里省略具体语法,只保留设计层面的职责边界。
- 读这段时重点看:输入是什么、系统做哪些判断、状态如何变化、失败时如何兜底。
访问流程:密码验证
当用户访问带密码的短链接时,我需要:
- 检查链接是否设置了密码
- 检查用户是否已经通过验证(Session)
- 如果未验证,显示密码输入页面
- 验证密码正确性,防止暴力破解
落地思路
- 这里省略具体语法,只保留设计层面的职责边界。
- 读这段时重点看:输入是什么、系统做哪些判断、状态如何变化、失败时如何兜底。
密码输入页面
落地思路
- 这里省略具体语法,只保留设计层面的职责边界。
- 读这段时重点看:输入是什么、系统做哪些判断、状态如何变化、失败时如何兜底。
IP 白名单 🌐
需求场景
密码保护可以防止未授权访问,但企业客户有更高的安全需求:
“我们的内部链接,只允许公司网络访问。能不能按IP限制?”
IP 白名单是更严格的访问控制方式,常用于:
- 内网资源保护:只允许公司内网IP访问
- 地域限制:只允许特定国家/地区的IP访问
- API访问控制:只允许合作伙伴服务器的IP调用
IP 地址的挑战
实现 IP 白名单有几个技术难点:
- 获取真实IP:需要处理代理、负载均衡器的情况
- IP范围匹配:单个IP不够,需要支持CIDR格式(如
192.168.1.0/24) - IPv4和IPv6兼容:需要同时支持两种协议
获取真实 IP
在 Flask 中,直接使用 request.remote_addr 可能不准确:
落地思路
- 这里省略具体语法,只保留设计层面的职责边界。
- 读这段时重点看:输入是什么、系统做哪些判断、状态如何变化、失败时如何兜底。
正确做法是检查 X-Forwarded-For 头:
落地思路
- 这里省略具体语法,只保留设计层面的职责边界。
- 读这段时重点看:输入是什么、系统做哪些判断、状态如何变化、失败时如何兜底。
CIDR 匹配算法
企业客户不会只允许单个IP,而是整个IP段。CIDR(无类别域间路由)是标准表示法:
192.168.1.0/24:表示 192.168.1.0 到 192.168.1.255(256个IP)10.0.0.0/8:表示 10.0.0.0 到 10.255.255.255(1600万个IP)
我需要实现CIDR匹配算法:
落地思路
- 这里省略具体语法,只保留设计层面的职责边界。
- 读这段时重点看:输入是什么、系统做哪些判断、状态如何变化、失败时如何兜底。
数据库设计
数据设计要点
- 核心是在
urls里保存业务事实,而不是把规则散落在应用逻辑里。- 这是一次表结构演进:随着链接管理能力增加,把新状态、新时间点或新归属关系补进数据模型。
- 索引服务于高频查询,重点关注
AUTOINCREMENT、idx_ip_logs_short_code、idx_ip_logs_time。- 关键字段包括
id、short_code、ip_address、access_time、allowed,它们决定了后续查询和管理能力。
IP 白名单实现
落地思路
- 这里省略具体语法,只保留设计层面的职责边界。
- 读这段时重点看:输入是什么、系统做哪些判断、状态如何变化、失败时如何兜底。
创建带IP限制的短链接
落地思路
- 这里省略具体语法,只保留设计层面的职责边界。
- 读这段时重点看:输入是什么、系统做哪些判断、状态如何变化、失败时如何兜底。
IP 访问统计
落地思路
- 这里省略具体语法,只保留设计层面的职责边界。
- 读这段时重点看:输入是什么、系统做哪些判断、状态如何变化、失败时如何兜底。
访问次数限制 🎫
需求场景
一个营销客户找到我:
“我们要发限时优惠券,只给前100名用户。能不能实现’前100人可以访问,其他人不行’?”
这就是访问次数限制的需求:
- 限量抢购:只允许前N人访问
- 试用期限制:免费版只能访问100次
- 配额管理:防止资源被过度消耗
数据库设计
我在密码保护部分已经添加了相关字段:
数据设计要点
- 这是一次表结构演进:随着链接管理能力增加,把新状态、新时间点或新归属关系补进数据模型。
访问次数限制实现
落地思路
- 这里省略具体语法,只保留设计层面的职责边界。
- 读这段时重点看:输入是什么、系统做哪些判断、状态如何变化、失败时如何兜底。
限制页面模板
落地思路
- 这里省略具体语法,只保留设计层面的职责边界。
- 读这段时重点看:输入是什么、系统做哪些判断、状态如何变化、失败时如何兜底。
创建限次访问的短链接
落地思路
- 这里省略具体语法,只保留设计层面的职责边界。
- 读这段时重点看:输入是什么、系统做哪些判断、状态如何变化、失败时如何兜底。
实时访问计数查询
落地思路
- 这里省略具体语法,只保留设计层面的职责边界。
- 读这段时重点看:输入是什么、系统做哪些判断、状态如何变化、失败时如何兜底。
时间窗口限制 ⏰
需求场景
又有一个企业客户提出需求:
“我们的内部链接,只在工作时间可以访问,下班后不行。”
这就是时间窗口限制:
- 工作时间限制:只在周一到周五的9:00-18:00可访问
- 活动时间限制:限时促销,只在一个日期范围内有效
- 试用期限制:新用户注册后7天内可访问
数据库设计
数据设计要点
- 这是一次表结构演进:随着链接管理能力增加,把新状态、新时间点或新归属关系补进数据模型。
时间范围限制
落地思路
- 这里省略具体语法,只保留设计层面的职责边界。
- 读这段时重点看:输入是什么、系统做哪些判断、状态如何变化、失败时如何兜底。
每周时间段限制
落地思路
- 这里省略具体语法,只保留设计层面的职责边界。
- 读这段时重点看:输入是什么、系统做哪些判断、状态如何变化、失败时如何兜底。
创建时间限制的短链接
落地思路
- 这里省略具体语法,只保留设计层面的职责边界。
- 读这段时重点看:输入是什么、系统做哪些判断、状态如何变化、失败时如何兜底。
完整的时间检查流程
落地思路
- 这里省略具体语法,只保留设计层面的职责边界。
- 读这段时重点看:输入是什么、系统做哪些判断、状态如何变化、失败时如何兜底。
访问控制方案对比 📊
我已经实现了四种访问控制方案,每种都有其适用场景:
| 方案 | 实现难度 | 安全性 | 性能影响 | 适用场景 |
|---|---|---|---|---|
| 密码保护 | ⭐⭐ 中等 | ⭐⭐⭐ 中等 | ⭐⭐ 低 | 内部文档、私密分享 |
| IP白名单 | ⭐⭐ 中等 | ⭐⭐⭐⭐ 高 | ⭐⭐ 低 | 企业内网、地域限制 |
| 访问次数限制 | ⭐ 简单 | ⭐⭐ 低 | ⭐ 低 | 限量抢购、试用版 |
| 时间窗口限制 | ⭐⭐⭐ 较难 | ⭐⭐ 低 | ⭐ 低 | 限时活动、工作时间 |
组合使用
这些方案可以组合使用:
落地思路
- 这里省略具体语法,只保留设计层面的职责边界。
- 读这段时重点看:输入是什么、系统做哪些判断、状态如何变化、失败时如何兜底。
性能考虑
访问控制会增加响应延迟,我做了优化:
- 数据库索引:在
short_code上建索引,快速查询 - 缓存Session:密码验证后缓存,避免重复查询
- IP匹配优化:使用高效的CIDR匹配算法
- 异步日志:访问日志异步写入,不影响主流程
下一步:批量管理 ⏭️
单个链接的访问控制已经实现了。但企业客户又提出新问题:
“我们有1000个内部链接,能不能批量设置IP白名单?” “每个月都要更新密码,能不能批量操作?”
单个链接管理已经不够了,我需要实现批量管理功能。
下一节,我会实现:
- 批量设置访问控制
- 批量更新密码
- 批量导入导出
- 权限组管理
(继续下一节:批量操作)