身份验证 #

JWT 认证 #

添加依赖 #

toml
[dependencies]
jsonwebtoken = "9"
serde = { version = "1", features = ["derive"] }
chrono = { version = "0.4", features = ["serde"] }

JWT 配置 #

rust
use jsonwebtoken::{decode, encode, Algorithm, DecodingKey, EncodingKey, Header, Validation};
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
pub struct Claims {
    pub sub: String,
    pub exp: usize,
    pub iat: usize,
}

pub struct JwtConfig {
    pub secret: String,
    pub expiration: i64,
}

impl JwtConfig {
    pub fn new(secret: String, expiration: i64) -> Self {
        Self { secret, expiration }
    }
    
    pub fn generate_token(&self, user_id: &str) -> Result<String, jsonwebtoken::errors::Error> {
        let now = chrono::Utc::now();
        let exp = now + chrono::Duration::seconds(self.expiration);
        
        let claims = Claims {
            sub: user_id.to_string(),
            exp: exp.timestamp() as usize,
            iat: now.timestamp() as usize,
        };
        
        encode(
            &Header::default(),
            &claims,
            &EncodingKey::from_secret(self.secret.as_bytes()),
        )
    }
    
    pub fn validate_token(&self, token: &str) -> Result<Claims, jsonwebtoken::errors::Error> {
        decode::<Claims>(
            token,
            &DecodingKey::from_secret(self.secret.as_bytes()),
            &Validation::new(Algorithm::HS256),
        )
        .map(|data| data.claims)
    }
}

认证中间件 #

rust
use actix_web::{dev::Payload, Error, FromRequest, HttpRequest};
use futures::future::{ready, Ready};

pub struct AuthUser {
    pub user_id: String,
}

impl FromRequest for AuthUser {
    type Error = Error;
    type Future = Ready<Result<Self, Self::Error>>;

    fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
        let jwt_config = req.app_data::<web::Data<JwtConfig>>().unwrap();
        
        let auth_header = req.headers().get("Authorization");
        
        match auth_header {
            Some(header_value) => {
                let token = header_value
                    .to_str()
                    .unwrap_or("")
                    .strip_prefix("Bearer ")
                    .unwrap_or("");
                
                match jwt_config.validate_token(token) {
                    Ok(claims) => ready(Ok(AuthUser {
                        user_id: claims.sub,
                    })),
                    Err(_) => ready(Err(actix_web::error::ErrorUnauthorized("Invalid token"))),
                }
            }
            None => ready(Err(actix_web::error::ErrorUnauthorized("Missing token"))),
        }
    }
}

使用认证 #

rust
#[actix_web::get("/protected")]
async fn protected(user: AuthUser) -> impl Responder {
    web::Json(serde_json::json!({
        "user_id": user.user_id,
        "message": "Access granted"
    }))
}

登录接口 #

rust
#[derive(Deserialize)]
struct LoginRequest {
    username: String,
    password: String,
}

#[actix_web::post("/login")]
async fn login(
    body: web::Json<LoginRequest>,
    jwt_config: web::Data<JwtConfig>,
) -> impl Responder {
    if body.username == "admin" && body.password == "secret" {
        match jwt_config.generate_token("user_123") {
            Ok(token) => HttpResponse::Ok().json(serde_json::json!({
                "token": token
            })),
            Err(e) => HttpResponse::InternalServerError()
                .json(serde_json::json!({ "error": e.to_string() })),
        }
    } else {
        HttpResponse::Unauthorized().json(serde_json::json!({
            "error": "Invalid credentials"
        }))
    }
}

下一步 #

继续学习 授权控制,了解权限管理!

最后更新:2026-03-29