密码安全:bcrypt / Argon2
永远不要存储明文密码。Rust 生态提供了经过安全审计的哈希库:
[dependencies]
argon2 = "0.5"
rand_core = { version = "0.6", features = ["std"] }use argon2::{
password_hash::{rand_core::OsRng, PasswordHash, PasswordHasher, PasswordVerifier, SaltString},
Argon2,
};
pub fn hash_password(password: &str) -> Result<String, argon2::password_hash::Error> {
let salt = SaltString::generate(&mut OsRng);
let argon2 = Argon2::default();
Ok(argon2.hash_password(password.as_bytes(), &salt)?.to_string())
}
pub fn verify_password(password: &str, hash: &str) -> bool {
let parsed_hash = PasswordHash::new(hash).unwrap();
Argon2::default()
.verify_password(password.as_bytes(), &parsed_hash)
.is_ok()
}使用 Argon2id(默认)而非 bcrypt——Argon2id 是 2015 年密码哈希大赛冠军,对 GPU 暴力破解有更强抵抗力。永远用库函数,绝不自己实现哈希。
JWT 认证
[dependencies]
jsonwebtoken = "9"
serde = { version = "1", features = ["derive"] }use jsonwebtoken::{encode, decode, Header, Validation, EncodingKey, DecodingKey};
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
pub struct Claims {
pub sub: String, // subject(用户 ID)
pub role: String, // 用户角色
pub exp: usize, // 过期时间(Unix timestamp)
}
pub fn create_token(user_id: &str, role: &str, secret: &[u8]) -> String {
let expiration = chrono::Utc::now()
.checked_add_signed(chrono::Duration::hours(24))
.unwrap()
.timestamp() as usize;
let claims = Claims {
sub: user_id.to_owned(),
role: role.to_owned(),
exp: expiration,
};
encode(&Header::default(), &claims, &EncodingKey::from_secret(secret)).unwrap()
}
pub fn verify_token(token: &str, secret: &[u8]) -> Result<Claims, jsonwebtoken::errors::Error> {
let token_data = decode::<Claims>(
token,
&DecodingKey::from_secret(secret),
&Validation::default(),
)?;
Ok(token_data.claims)
}Axum JWT 中间件
use axum::{
extract::{Request, State},
http::StatusCode,
middleware::Next,
response::Response,
};
pub async fn auth_middleware(
State(secret): State<Vec<u8>>,
mut req: Request,
next: Next,
) -> Result<Response, StatusCode> {
let token = req
.headers()
.get("Authorization")
.and_then(|v| v.to_str().ok())
.and_then(|v| v.strip_prefix("Bearer "))
.ok_or(StatusCode::UNAUTHORIZED)?;
let claims = verify_token(token, &secret)
.map_err(|_| StatusCode::UNAUTHORIZED)?;
// 将 claims 注入请求扩展,下游 handler 可提取
req.extensions_mut().insert(claims);
Ok(next.run(req).await)
}对比:
JS
JavaScriptapp.use((req, res, next) => {
const token = req.headers.authorization?.split(' ')[1];
if (!token) return res.status(401).json({ error: 'Unauthorized' });
try {
req.user = jwt.verify(token, process.env.JWT_SECRET);
next();
} catch {
res.status(401).json({ error: 'Invalid token' });
}
});Rs
Rust// Axum 类型系统保证:未通过 auth_middleware 的路由
// 无法通过 Extension<Claims> 提取器获取用户信息
// 编译期就阻止了"忘记加认证中间件"的错误
async fn protected_handler(
Extension(claims): Extension<Claims>,
) -> String {
format!("Hello, {}!", claims.sub)
}RBAC:基于角色的权限控制
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum Role {
Admin,
User,
Guest,
}
impl Role {
pub fn can(&self, action: &str) -> bool {
match (self, action) {
(Role::Admin, _) => true,
(Role::User, "read" | "write") => true,
(Role::Guest, "read") => true,
_ => false,
}
}
}
// 角色提取器中间件
pub async fn require_role(
Extension(claims): Extension<Claims>,
State(required_role): State<Role>,
req: Request,
next: Next,
) -> Result<Response, StatusCode> {
let user_role: Role = claims.role.parse().map_err(|_| StatusCode::FORBIDDEN)?;
if user_role == required_role || user_role == Role::Admin {
Ok(next.run(req).await)
} else {
Err(StatusCode::FORBIDDEN)
}
}速率限制
[dependencies]
tower-governor = "0.4"use tower_governor::{governor::GovernorConfigBuilder, GovernorLayer};
let governor_conf = Box::new(
GovernorConfigBuilder::default()
.per_second(2) // 每秒最多 2 个请求
.burst_size(5) // 允许突发 5 个
.finish()
.unwrap(),
);
let app = Router::new()
.route("/login", post(login_handler))
.layer(GovernorLayer { config: governor_conf });速率限制应该在认证路由(/login, /register)上单独配置,比全局限制更严格——防止暴力破解,同时不影响普通 API 路由的性能。
JWT 认证系统实战演示
从注册、登录到受保护路由:密码 Argon2 哈希、JWT 签发、中间件验证、RBAC 权限控制完整实现
视频即将上线
实战项目
完整用户认证服务
初级
构建包含注册(密码 Argon2 哈希)、登录(JWT 签发)、令牌刷新、受保护路由(中间件验证)、基于角色权限控制(Admin/User/Guest)的完整认证微服务。
Argon2JWTAxum 中间件RBAC速率限制SQLx