< 返回版块

C-Jeril 发表于 2024-01-26 19:24

报错内容
[{
	"resource": "/e:/jsc-hi/Backend/src/auth.rs",
	"owner": "rustc",
	"code": {
		"value": "Click for full compiler diagnostic",
		"target": {
			"$mid": 1,
			"path": "/diagnostic message [0]",
			"scheme": "rust-analyzer-diagnostics-view",
			"query": "0",
			"fragment": "file:///e%3A/jsc-hi/Backend/src/auth.rs"
		}
	},
	"severity": 8,
	"message": "method `from_request` has an incompatible type for trait\nexpected signature `fn(axum::http::Request<_>, &'life0 B) -> Pin<_>`\n   found signature `fn(axum::http::Request<_>, &'life0 ()) -> Pin<_>`",
	"source": "rustc",
	"startLineNumber": 82,
	"startColumn": 50,
	"endLineNumber": 82,
	"endColumn": 53,
	"relatedInformation": [
		{
			"startLineNumber": 76,
			"startColumn": 6,
			"endLineNumber": 76,
			"endColumn": 7,
			"message": "expected this type parameter",
			"resource": "/e:/jsc-hi/Backend/src/auth.rs"
		},
		{
			"startLineNumber": 82,
			"startColumn": 50,
			"endLineNumber": 82,
			"endColumn": 53,
			"message": "change the parameter type to match the trait: `&'life0 B`",
			"resource": "/e:/jsc-hi/Backend/src/auth.rs"
		}
	]
}]

// src/auth.rs jwt令牌,用户认证
use crate::auth;
use axum::body::Body;
use axum::http::header;
use axum::http::Request;
use axum::{
    async_trait,
    extract::FromRequest,
    http::{Response, StatusCode},
    response::IntoResponse,
};
use jsonwebtoken::{decode, encode, DecodingKey, EncodingKey, Header, Validation};
use serde::{Deserialize, Serialize};
use std::env;

// JWT生成函数:将生成JWT Token的逻辑封装成一个函数,包括设置Token的过期时间、加密算法等
pub fn generate_jwt(user: &AuthenticatedUser) -> Result<String, jsonwebtoken::errors::Error> {
    let expiration = 3600; // 设置 token 过期时间为 1 小时,10000000000基本为长期
    let claims = Claims {
        sub: user.id.to_string(),
        exp: expiration,
    };

    // 密钥管理:将从环境变量或配置文件中获取JWT密钥的逻辑封装成一个函数,以及密钥的安全管理。
    let secret = env::var("JWT_SECRET").expect("JWT_SECRET must be set"); // 使用 env::var("JWT_SECRET") 从环境变量中获取 JWT 密钥,且环境变量不存在时返回自定义错误;
    encode(
        &Header::default(),
        &claims,
        &EncodingKey::from_secret(secret.as_ref()),
    )
}

//JWT验证函数:将验证JWT Token的逻辑封装成一个函数,包括解析Token并验证其有效性。
pub fn validate_jwt(token: &str) -> Result<auth::Claims, jsonwebtoken::errors::Error> {
    let secret = env::var("JWT_SECRET").expect("JWT_SECRET must be set");
    decode::<auth::Claims>(
        token,
        &DecodingKey::from_secret(secret.as_ref()),
        &Validation::default(),
    )
    .map(|data| data.claims) // 直接返回Claims对象
}

//  错误处理:自定义错误类型,用于描述身份验证过程中,比如JWT生成、验证等可能发生的各种错误类型
#[derive(Debug)]
enum AuthError {
    MissingHeader, // 缺少授权头部
    InvalidToken,  // Token无效或格式错误
    DecodingError(String), // 解码错误,包含详细的错误信息
                   // 其他错误类型...
}

// 实现 `IntoResponse` 特征,使得 AuthError 可以被转换成 HTTP 响应,避免解析授权头部错误后没有后续响应导致程序 panic
impl IntoResponse for AuthError {
    fn into_response(self) -> Response<Body> {
        match self {
            // 缺少头部或 Token 无效时,返回 401 未授权错误
            AuthError::MissingHeader | AuthError::InvalidToken => {
                StatusCode::UNAUTHORIZED.into_response()
            }
            // 解码出错时,返回包含错误信息的 401 未授权错误
            AuthError::DecodingError(msg) => {
                let body = format!("JWT Decoding Error: {}", msg);
                Response::builder()
                    .status(StatusCode::UNAUTHORIZED)
                    .header(header::CONTENT_TYPE, "text/plain")
                    .body(Body::from(body))
                    .unwrap()
            }
        }
    }
}

// 使用 `async_trait` 特征实现 `FromRequest`,用于从请求中异步提取 `AuthenticatedUser`
#[async_trait]
impl<B> FromRequest<B> for AuthenticatedUser
where
    B: Send,
{
    type Rejection = AuthError;

    async fn from_request(req: Request<Body>, _: &()) -> Result<Self, Self::Rejection> {
        // 尝试从请求头部获取 'Authorization' 字段
        let authorization = req
            .headers()
            .get("Authorization")
            .ok_or(AuthError::MissingHeader)?;

        // 将头部的值转换为字符串,如果失败则返回 InvalidToken 错误
        let token = authorization
            .to_str()
            .map_err(|_| AuthError::InvalidToken)?;

        // 尝试从环境变量中获取 JWT 密钥,如果失败则返回 DecodingError
        let secret = env::var("JWT_SECRET").map_err(|_| AuthError::DecodingError("JWT_SECRET must be set".to_string()))?;

        // 使用提取的 Token 和密钥尝试解码 JWT
        match decode::<Claims>(
            token,
            &DecodingKey::from_secret(secret.as_ref()),
            &Validation::default(),
        ) {
            Ok(decoded) => {
                let user_id = decoded.claims.sub.parse::<i32>()
                    .map_err(|_| AuthError::DecodingError("Invalid user ID".to_string()))?;
                Ok(AuthenticatedUser { id: user_id })
            },
            Err(e) => Err(AuthError::DecodingError(e.to_string())),
        }
    }
}

// 结构体定义
// 假设您有一个用户结构体
#[derive(Serialize, Deserialize)]
pub struct AuthenticatedUser {
    pub id: i32,
    // 可以添加其他对身份验证有用的字段,比如用户名、角色等
}

// 用户登录的声明:定义JWT的Claims结构体,用于描述Token中包含的声明
#[derive(Debug, Serialize, Deserialize)]
pub struct Claims {
    pub sub: String, // 由开发者自己定义的合法标识符
    pub exp: i64,    // 通常JWT Token中的过期时间(exp)应该是一个Unix时间戳
}

评论区

写评论
作者 C-Jeril 2024-01-29 14:03

最后改为这样通过了,感谢

    async fn from_request(req: Request<Body>, _: &B) -> Result<Self, Self::Rejection> {

--  
👇  
Bai-Jinlin: ```
async fn from_request(req: Request<Body>, _: &()) -> Result<Self, Self::Rejection>

第二个参数()换成你定义的B

Bai-Jinlin 2024-01-26 21:13
async fn from_request(req: Request<Body>, _: &()) -> Result<Self, Self::Rejection>

第二个参数()换成你定义的B

1 共 2 条评论, 1 页