9个版本

0.1.8 2024年6月13日
0.1.7 2024年1月11日
0.1.4 2023年12月1日
0.1.3 2023年11月26日

身份验证 中排名第 122

Download history 121/week @ 2024-06-12 2/week @ 2024-06-19

每月下载 507

MIT/Apache

15KB
206

axum_jwt_ware集成指南

简单的Axum + JWT身份验证中间件,实现了登录和刷新令牌。

目标

我的目标是简化开发者/独立黑客在启动新项目时的过程,让他们能够专注于编写核心业务逻辑,而不是花费时间重写身份验证。

安装

cargo add axum_jwt_ware

使用示例

有一个标准中间件用于通过JWT验证用户 -- verify_user 中间件。其签名如下

pub async fn verify_user<B>(
    mut req: Request<B>,
    key: &DecodingKey,
    validation: Validation,
    next: Next<B>,
) -> Result<Response, AuthError>

您可以将它传递给路由层,如下所示

use axum_jwt_ware;

let app = Router::new()
        .route(
            "/hello",
            get(hello)
            .layer(middleware::from_fn(move |req, next| {
                let key = axum_jwt_ware::DecodingKey::from_secret(jwt_secret.as_ref());
                let validation = axum_jwt_ware::Validation::default();
                async move { axum_jwt_ware::verify_user(req, &key, validation, next).await }
        })),
    )

登录

您可以选择实现自己的自定义登录或使用库提供的登录。提供的登录使用默认算法,只需您提供“密钥”即可。

以下是如何使用提供的登录的示例

use axum_jwt_ware::{CurrentUser, UserData};

#[derive(Clone, Copy)]
pub struct MyUserData;

impl UserData for MyUserData {
    async fn get_user_by_email(&self, _email: &str) -> Option<CurrentUser> {
        // Implement the logic to fetch a user by email from your database
    }
}

let app = Router::new()
        .route(
            "/login",
            post(move |body: Json<axum_jwt_ware::RequestBody>| {
                let expiry_timestamp = (Utc::now() + Duration::hours(48)).timestamp();
                let user_data = MyUserData;
                let jwt_secret = "secret";
                let refresh_secret = "refresh_secret";

                axum_jwt_ware::login(
                    body,
                    user_data.clone(),
                    jwt_secret,
                    refresh_secret,
                    expiry_timestamp.timestamp(),
                )
            }),
        )

如果您要实现自定义登录,请确保使用 axum_auth_ware::auth_token_encode 方法生成您的令牌。以下是一个使用RSA加密的登录示例

use axum_jwt_ware::{CurrentUser, UserData, Algorithm, auth_token_encode};
let key = EncodingKey::from_rsa_pem(include_bytes!("../jwt_rsa.key")).unwrap();
let mut header = Header::new(Algorithm::RS256);
let expiry_timestamp = (Utc::now() + Duration::hours(48)).timestamp();

let claims = Claims {
    sub: user.id,
    username: user.username.clone(),
    exp: expiry_timestamp,
};
let token = auth_token_encode(claims, header, &key).await;

刷新令牌

刷新令牌允许用户登录(获取新的访问令牌),而无需他们输入用户名和密码(完整登录)。

您可以使用 auth_token_encodeauth_token_decode 函数创建自己的刷新令牌,或者您可以使用刷新令牌处理器,它应如下所示

use axum_jwt_ware;

let app = Router::new()
        .route(
            "/refresh",
            post(move |body: Json<axum_jwt_ware::RefreshBody>| {

                let encoding_context = axum_jwt_ware::EncodingContext {
                    header: axum_jwt_ware::Header::default(),
                    validation: axum_jwt_ware::Validation::default(),
                    key: axum_jwt_ware::EncodingKey::from_secret("refresh_secret".as_ref()),
                };
                let decoding_context = axum_jwt_ware::DecodingContext {
                    header: axum_jwt_ware::Header::default(),
                    validation: axum_jwt_ware::Validation::default(),
                    key: axum_jwt_ware::DecodingKey::from_secret("refresh_secret".as_ref()),
                };
                let claims = axum_jwt_ware::Claims {
                    sub: "jkfajfafghjjfn".to_string(),
                    username: "ezesunday".to_string(),
                    exp: (Utc::now() + Duration::hours(48)).timestamp(),
                };

                axum_jwt_ware::refresh_token(body, encoding_context, decoding_context, Some(claims))
            }),
        )

更全面的示例

use crate::{
    auth,
    service::{hello, MyUserData},
};
use axum::{
    middleware,
    routing::{get, post},
    Json, Router,
};

use chrono::{Duration, Utc};

pub fn create_router() -> Router {
    let user_data = MyUserData;
    let jwt_secret = "secret";

    let app = Router::new()
        .route(
            "/hello",
            get(hello)
                .layer(middleware::from_fn(move |req, next| {
                    let key = auth::DecodingKey::from_secret(jwt_secret.as_ref());
                    let validation  = auth::Validation::default();
                    async move { auth::verify_user(req, &key, validation, next).await }
                })),
        )
        .route(
            "/login",
            post(move |body: Json<auth::RequestBody>| {
                let expiry_timestamp = (Utc::now() + Duration::hours(48)).timestamp();

                auth::login(
                    body,
                    user_data.clone(),
                    jwt_secret,
                    expiry_timestamp.timestamp(),
                )
            }),
        );
    app
}

示例

您可以在 GitHub仓库 的示例目录中找到一个工作示例

您已准备好!

特性

  • 刷新令牌
  • 登录
    • 您可以实施自己的登录
    • 使用提供的登录
  • 身份验证中间件
  • 测试

想要贡献?

  • 创建问题
  • 分叉仓库
  • 创建一个修复问题的PR

依赖关系

~6–16MB
~216K SLoC