121 lines
3.6 KiB
Rust
121 lines
3.6 KiB
Rust
use chrono::Utc;
|
||
use jsonwebtoken::{Algorithm, DecodingKey, EncodingKey, Header, Validation, decode, encode};
|
||
|
||
use crate::models::{Claims, TempTokenClaims};
|
||
use actix_web::{
|
||
Error, HttpMessage, body::MessageBody, dev::ServiceRequest, dev::ServiceResponse,
|
||
middleware::Next,
|
||
}; // 新增:用于包装中间件函数
|
||
|
||
// 中间件函数:泛型 B 约束为 MessageBody,返回 Result<ServiceResponse<B>, Error>
|
||
pub async fn jwt_middleware<B: MessageBody>(
|
||
req: ServiceRequest,
|
||
next: Next<B>,
|
||
) -> Result<ServiceResponse<B>, Error> {
|
||
// (保持原有逻辑不变)
|
||
let auth_header = req
|
||
.headers()
|
||
.get("Authorization")
|
||
.ok_or_else(|| actix_web::error::ErrorUnauthorized("缺少Authorization头"))?
|
||
.to_str()
|
||
.map_err(|_| actix_web::error::ErrorUnauthorized("Authorization格式无效"))?;
|
||
|
||
let token = auth_header.strip_prefix("Bearer ").ok_or_else(|| {
|
||
actix_web::error::ErrorUnauthorized("Authorization格式应为 Bearer <token>")
|
||
})?;
|
||
|
||
let jwt_secret = std::env::var("JWT_SECRET")
|
||
.map_err(|_| actix_web::error::ErrorInternalServerError("服务器未配置JWT密钥"))?;
|
||
|
||
let claims = verify_token(token, &jwt_secret)
|
||
.map_err(|e| actix_web::error::ErrorUnauthorized(format!("无效的token: {}", e)))?;
|
||
|
||
req.extensions_mut().insert(claims);
|
||
next.call(req).await
|
||
}
|
||
|
||
// 生成JWT的函数
|
||
pub fn generate_token(
|
||
user_id: i32,
|
||
openid: &str,
|
||
user_type: i32,
|
||
secret: &str,
|
||
) -> Result<String, String> {
|
||
// 设置过期时间:当前时间 + 24小时(86400秒)
|
||
let now = Utc::now();
|
||
let exp = (now + chrono::Duration::hours(24)).timestamp();
|
||
let iat = now.timestamp();
|
||
|
||
// 构建Claims
|
||
let claims = Claims {
|
||
exp,
|
||
iat,
|
||
user_id,
|
||
openid: openid.to_string(),
|
||
user_type,
|
||
};
|
||
|
||
// 生成token
|
||
encode(
|
||
&Header::new(Algorithm::HS256), // 使用HS256算法
|
||
&claims,
|
||
&EncodingKey::from_secret(secret.as_bytes()), // 签名密钥
|
||
)
|
||
.map_err(|e| format!("生成JWT失败: {}", e))
|
||
}
|
||
|
||
// 验证并解析JWT的函数
|
||
pub fn verify_token(token: &str, secret: &str) -> Result<Claims, String> {
|
||
// 验证配置(指定算法,默认会检查exp等字段)
|
||
let validation = Validation::new(Algorithm::HS256);
|
||
|
||
// 解析token
|
||
let decoded = decode::<Claims>(
|
||
token,
|
||
&DecodingKey::from_secret(secret.as_bytes()), // 与签发时相同的密钥
|
||
&validation,
|
||
)
|
||
.map_err(|e| format!("JWT验证失败: {}", e))?;
|
||
|
||
Ok(decoded.claims)
|
||
}
|
||
|
||
// 生成临时token(包含openid和resource_id,短期有效)
|
||
pub fn generate_temp_token(
|
||
openid: &str,
|
||
resource_id: i32,
|
||
secret: &str,
|
||
expire_minutes: i64, // 有效期(分钟)
|
||
) -> Result<String, String> {
|
||
let now = Utc::now();
|
||
let exp = (now + chrono::Duration::minutes(expire_minutes)).timestamp();
|
||
let iat = now.timestamp();
|
||
|
||
let claims = TempTokenClaims {
|
||
exp,
|
||
iat,
|
||
openid: openid.to_string(),
|
||
resource_id,
|
||
};
|
||
|
||
encode(
|
||
&Header::new(Algorithm::HS256),
|
||
&claims,
|
||
&EncodingKey::from_secret(secret.as_bytes()),
|
||
)
|
||
.map_err(|e| format!("生成临时token失败: {}", e))
|
||
}
|
||
|
||
// 验证临时token并返回载荷
|
||
pub fn verify_temp_token(token: &str, secret: &str) -> Result<TempTokenClaims, String> {
|
||
let validation = Validation::new(Algorithm::HS256);
|
||
let decoded = decode::<TempTokenClaims>(
|
||
token,
|
||
&DecodingKey::from_secret(secret.as_bytes()),
|
||
&validation,
|
||
)
|
||
.map_err(|e| format!("临时token验证失败: {}", e))?;
|
||
|
||
Ok(decoded.claims)
|
||
}
|