#sqlx #session #axum #authentication #tower

已删除 axum_sessions_auth

提供用户身份验证和权限令牌检查的库。它需要Axum_Database_Sessions库。

1个稳定版本

7.0.0 2023年2月20日
6.0.0 2023年2月20日
5.0.1 2022年12月18日
5.0.0 2022年11月26日
0.2.0 2022年3月21日

#115 in #tower

Download history 2/week @ 2024-03-29 1/week @ 2024-04-05

540 每月下载量

MIT 协议

39KB
573

会话身份验证

提供用户身份验证和权限令牌检查的库。它需要_Database_Sessions库。该库将帮助确保用户ID或授权不存储在客户端,而是存储在服务器端。授权通过存储在客户端的客户端服务器端会话ID进行链接。

https://crates.io/crates/axum_sessions_auth Docs

  • 封装axum_database_sessions进行数据管理服务器端。
  • 权限管理API
  • 页面加载时自动加载用户数据。
  • 用户数据缓存,以避免在不需要时重复调用数据库。

帮助

如果您需要关于此库的帮助或有建议,请访问我们的Discord群组

安装

会话身份验证使用tokio运行时和['axum_database_sessions'];

# Cargo.toml
[dependencies]
# Postgres + rustls
axum_sessions_auth = { version = "7.0.0", features = [ "postgres-rustls" ] }

Cargo功能标志

default: postgres-rustls

sqlite-rustls: Sqlx支持自带的SQLite数据库引擎和rustls

sqlite-native: Sqlx支持自带的SQLite数据库引擎和native-tls

postgres-rustls: Sqlx支持Postgres数据库服务器和rustls

postgres-native: Sqlx支持Postgres数据库服务器和native-tls

mysql-rustls: Sqlx支持MySQL/MariaDB数据库服务器和rustls

mysql-native: Sqlx支持MySQL/MariaDB数据库服务器和native-tls

redis-db: redis 0.21.5会话支持。

示例

use sqlx::{PgPool, ConnectOptions, postgres::{PgPoolOptions, PgConnectOptions}};
use std::net::SocketAddr;
use axum_database_sessions::{SessionPgPool, Session, SessionConfig, SessionLayer, DatabasePool};
use axum_sessions_auth::{AuthSession, AuthSessionLayer, Authentication, AuthConfig};
use axum::{
    Router,
    routing::get,
};

#[tokio::main]
async fn main() {
    # async {
    let poll = connect_to_database().await.unwrap();

    let session_config = SessionConfig::default()
        .with_database("test")
        .with_table_name("test_table");
    let auth_config = AuthConfig::<i64>::default().with_anonymous_user_id(Some(1));
    let session_store = SessionStore::<SessionPgPool>::new(Some(poll.clone().into()), session_config);

    // Build our application with some routes
    let app = Router::new()
        .route("/greet/:name", get(greet))
        .layer(SessionLayer::new(session_store))
        .layer(AuthSessionLayer::<User, i64, SessionPgPool, PgPool>::new(Some(poll)).with_config(auth_config));

    // Run it
    let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
    tracing::debug!("listening on {}", addr);
    axum::Server::bind(&addr)
        .serve(app.into_make_service())
        .await
        .unwrap();
    # };
}

// We can get the Method to compare with what Methods we allow. Useful if this supports multiple methods.
// When called auth is loaded in the background for you.
async fn greet(method: Method, auth: AuthSession<User, i64, SessionPgPool, PgPool>) -> &'static str {
    let mut count: usize = session.get("count").unwrap_or(0);
    count += 1;

    // Session is Also included with Auth so no need to require it in the function arguments if your using
    // AuthSession.
    auth.session.set("count", count);

    // If for some reason you needed to update your Users Permissions or data then you will want to clear the user cache if it is enabled.
    // The user Cache is enabled by default. To clear simply use.
    auth.cache_clear_user(1).await;
    //or to clear all for a large update
    auth.cache_clear_all().await;

    if let Some(cur_user) = current_user {
        if !Auth::<User, i64, PgPool>::build([Method::Get], false)
            .requires(Rights::none([
                Rights::permission("Token::UseAdmin"),
                Rights::permission("Token::ModifyPerms"),
            ]))
            .validate(&cur_user, &method, None)
            .await
        {
            return format!("No Permissions! for {}", cur_user.username)[];
        }

        let username = if !auth.is_authenticated() {
            // Set the user ID of the User to the Session so it can be Auto Loaded the next load or redirect
            auth.login_user(2);
            "".to_string()
        } else {
            // If the user is loaded and is Authenticated then we can use it.
            if let Some(user) = auth.current_user {
                user.username.clone()
            } else {
                "".to_string()
            }
        };

        format!("{}-{}", username, count)[..]
    } else {
        if !auth.is_authenticated() {
            // Set the user ID of the User to the Session so it can be Auto Loaded the next load or redirect
            auth.login_user(2);
            // Set the session to be long term. Good for Remember me type instances.
            auth.remember_user(true);
            // Redirect here after login if we did indeed login.
        }

        "No Permissions!"
    }
}

#[derive(Clone, Debug)]
pub struct User {
    pub id: i32,
    pub anonymous: bool,
    pub username: String,
}

// This is only used if you want to use Token based Authentication checks
#[async_trait]
impl HasPermission<PgPool> for User {
    async fn has(&self, perm: &String, _pool: &Option<&PgPool>) -> bool {
        match &perm[..] {
            "Token::UseAdmin" => true,
            "Token::ModifyUser" => true,
            _ => false,
        }
    }
}

#[async_trait]
impl Authentication<User, i64, PgPool> for User {
    async fn load_user(userid: i64, _pool: Option<&PgPool>) -> Result<User> {
        Ok(User {
            id: userid,
            anonymous: true,
            username: "Guest".to_string(),
        })
    }

    fn is_authenticated(&self) -> bool {
        !self.anonymous
    }

    fn is_active(&self) -> bool {
        !self.anonymous
    }

    fn is_anonymous(&self) -> bool {
        self.anonymous
    }
}

async fn connect_to_database() -> anyhow::Result<sqlx::Pool<sqlx::Postgres>> {
    // ...
    # unimplemented!()
}

依赖项

~9–28MB
~436K SLoC