用 Rust 构建安全认证服务:令牌、加密与 Redis
在 Rust 中打造一个可靠的认证服务,需要深入理解密码学、令牌管理和巧妙的抽象设计。本文基于实战经验,详细讲解 JWT 和不透明令牌的生成、验证,以及 Redis 存储。
令牌架构与生成
服务采用两种令牌:访问令牌(JWT)用于短期会话,刷新令牌(不透明)实现无缝续期,无需重新认证。
JWT 令牌使用 RS256 非对称加密算法,签名需私钥,验证用公钥。不透明令牌是随机 base64 字符串,不含客户端可读信息,提升安全性。
密钥生成组件
- JwtTokenProvider:用于基于声明和私钥生成 JWT 的 trait。
- OpaqueTokenProvider:通过随机字节生成不透明令牌的 trait。
- Claims 结构:包含标准字段,如 sub(用户 ID)、jti(令牌 ID)、iat(签发时间)和 exp(过期时间)。
JwtTokenProvider 示例实现:
pub trait IJwtTokenProvider {
type Claims: Send + Sync;
type Error;
fn generate(&self, claims: &Self::Claims, pem: &str) -> Result<String, Self::Error>;
}
令牌验证与校验
JWT 验证使用公钥防范私钥泄露。IJwtTokenValidator trait 处理签名检查和令牌完整性。
验证要点
- PEM 格式:密钥存储在 PEM 文件中,支持证书和信任链。
- 加密算法:支持对称(如 HS256)和非对称(如 RS256),优先后者以提升安全。
- 声明转换:领域模型适配库要求,如 DateTime 转为 usize。
验证代码示例:
pub trait IJwtTokenValidator {
type Claims: Send + Sync;
type Error;
fn verify(&self, token: &str, pem: &str) -> Result<Self::Claims, Self::Error>;
}
令牌存储与协调
TokenManager 和 KeyManager 管理令牌与密钥。TokenManager 生成、验证并将令牌存入 Redis,利用灵活抽象。
RedisIO 实现
RedisIO 简化存储操作,提供 setex、get 和 delete 方法,减少样板代码,提高可读性。
示例:
impl<Storage> RedisIO<Storage>
where Storage: redis::AsyncCommands + Send + Sync
{
pub async fn setex(&mut self, key: &str, data: &str, exp: u64) -> Result<(), redis::RedisError> {
self.redis_storage.set_ex::<&str, String, (>(&key, data.to_string(), exp).await?;
Ok(())
}
}
TokenManager 特性
使用泛型支持提供者和验证器,便于替换。主要方法:
- generate_pair:生成访问/刷新令牌对,存入 Redis 并设置 TTL。
- verify_access:校验访问令牌存在性和完整性。
使用示例:
pub async fn generate_pair(&mut self, claims: &Claims, pem: &str) -> Result<(String, String), TokenManagerError> {
let access_token = self.access_provider.generate(&claims, &pem)?;
let refresh_token = self.refresh_provider.generate();
// Redis 存储逻辑
Ok((access_token, refresh_token))
}
核心要点
- RS256 非对称加密让 JWT 安全性远超对称方法。
- 不透明令牌作为随机 base64 字符串,难以伪造。
- Trait 便于测试和替换组件。
- Redis TTL 存储高效管理会话,减轻数据库压力。
- 严格分离公私钥,避免泄露风险。
常见问题与解决方案
开发中发现的问题:
- Base64 膨胀:32 字节扩展至 43 字节,可能引发存储问题。
- 密钥误用:验证时用私钥是大忌。
- 类型不匹配:DateTime 转 usize 需要校验。
解决方案:
- 测试各种数据大小的边界情况。
- 强制严格的密钥类型/格式检查。
- 借助成熟的 JWT/加密库。
— Editorial Team
暂无评论。