0.1.1 |
|
---|---|
0.1.0 |
|
#120 in #tower
17KB
246 代码行
axum_sqlx_session_auth
提供用户身份验证和权限令牌检查的库。它需要AxumSQLxSessions库和Tower_cookies库。此库将帮助确保用户ID或授权不存储在客户端,而是存储在服务器端。授权通过存储在客户端的客户端服务器端会话ID进行链接。
示例
pub fn init_pool(config: &ServerConfig) -> anyhow::Result<sqlx::Pool<sqlx::Postgres>> {
let mut connect_opts = PgConnectOptions::new();
connect_opts.log_statements(LevelFilter::Debug);
connect_opts = connect_opts.database(&config.pgsql_database[..]);
connect_opts = connect_opts.username(&config.pgsql_user[..]);
connect_opts = connect_opts.password(&config.pgsql_password[..]);
connect_opts = connect_opts.host(&config.pgsql_host[..]);
connect_opts = connect_opts.port(config.pgsql_port);
let pool = block_on(
PgPoolOptions::new()
.max_connections(5)
.connect_with(connect_opts),
)?;
Ok(pool)
}
#[tokio::main]
async fn main() {
// Set the RUST_LOG, if it hasn't been explicitly defined
if std::env::var_os("RUST_LOG").is_none() {
std::env::set_var("RUST_LOG", "example_templates=debug,tower_http=debug")
}
tracing_subscriber::fmt::init();
let config = //load your config here.
let poll = init_pool(&config).unwrap();
let session_config = SqlxSessionConfig::default()
.with_database("test")
.with_table_name("test_table");
// build our application with some routes
let app = Router::new()
.route("/greet/:name", get(greet))
.layer(tower_cookies::CookieManagerLayer::new())
.layer(SqlxSessionLayer::new(session_config, poll.clone()))
.layer(AuthSessionLayer::new(poll.clone(), Some(1)))
// 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 thius supports multiple methods.
//When called auth is loaded in the background for you.
async fn greet(method: Method, session: SQLxSession, auth: AuthSession<User>) -> &'static str {
let mut count: usize = session.get("count").unwrap_or(0);
count += 1;
session.set("count", count);
if let Some(cur_user) = current_user {
if !Auth::<User>::build(&[Method::Get], false)
.requires(Rights::none(&[
Rights::Permission("Token::UseAdmin".into()),
Rights::Permission("Token::ModifyPerms".into()),
]))
.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);
//redirect here after login if we did indeed login.
}
"No Permissions!"
}
}
#[derive(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 for User {
async fn has(&self, perm: &String, pool: &Option<&mut PoolConnection<sqlx::Postgres>>) -> bool {
match &perm[..] {
"Token::UseAdmin" => true,
"Token::ModifyUser" => true,
_ => false,
}
}
}
#[async_trait]
impl SQLxSessionAuth<User> for User {
async fn load_user(userid: i64, _pool: Option<&mut PoolConnection<sqlx::Postgres>>) -> 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
}
}
依赖项
~26–39MB
~722K SLoC