Comments (6)
Would your use case be able to leverage this pattern?
let PgStore = axum_login::PostgresStore<User, UserRole>;
Or do you need to reimplement load_user
altogether ?
from axum-login.
Where exactly would I use that? Currently, when I define user_store, I do:
let user_store = PostgresStore::<User, UserRole>::new(pool.clone());
Additionally, if I mock the load_user fn to just return a standard user instead of going into the db, when I hit the endpoint that uses AuthContext, I get this error:
thread 'tokio-runtime-worker' panicked at 'Auth extension missing. Is the auth layer installed?: MissingExtension(MissingExtension(Error { inner: "Extension of type `axum_login::extractors::AuthContext<be::entities::user::User, axum_login::sqlx_store::SqlxStore<sqlx_core::pool::Pool<sqlx_core::postgres::database::Postgres>, be::entities::user::User>, be::entities::user::UserRole>` was not found. Perhaps you forgot to add it? See `axum::Extension`." }))
My main.rs looks like this:
use axum::{
extract::State,
routing::{get, post},
Json, Router,
};
use axum_login::{
axum_sessions::{async_session::MemoryStore, SessionLayer},
AuthLayer, PostgresStore,
};
use rand::Rng;
use sqlx::postgres::PgPoolOptions;
use sqlx::PgPool;
use std::net::SocketAddr;
mod entities;
use entities::user::{User, UserRole};
#[tokio::main]
async fn main() {
let secret = rand::thread_rng().gen::<[u8; 64]>();
let session_store = MemoryStore::new();
let session_layer = SessionLayer::new(session_store, &secret).with_secure(false);
dotenvy::dotenv().ok();
let database_connection_uri = dotenvy::var("DATABASE_URL").unwrap();
let pool = PgPoolOptions::new()
.max_connections(5)
.connect(&database_connection_uri)
.await
.unwrap();
let user_store = PostgresStore::<User, UserRole>::new(pool.clone());
let auth_layer = AuthLayer::new(user_store, &secret);
let app = Router::new()
.route("/login", post(login))
.layer(auth_layer)
.layer(session_layer)
.with_state(pool);
let addr = SocketAddr::from(([127, 0, 0, 1], 5000));
axum::Server::bind(&addr)
.serve(app.into_make_service())
.await
.unwrap();
}
type AuthContext = axum_login::extractors::AuthContext<User, PostgresStore<User>, UserRole>;
#[derive(serde::Deserialize)]
struct Login {
username: String,
password: String,
}
#[axum::debug_handler]
async fn login(
mut auth: AuthContext,
State(pool): State<PgPool>,
Json(payload): Json<Login>,
) -> impl axum::response::IntoResponse {
let password_hash = hash_password(payload.password);
let user_result =
sqlx::query_as::<_, User>("SELECT * FROM users WHERE username = $1 AND password_hash = $2")
.bind(payload.username)
.bind(password_hash)
.fetch_one(&pool)
.await;
let user: User = match user_result {
Ok(value) => value,
Err(_) => return Err((axum::http::StatusCode::UNAUTHORIZED, ())),
};
auth.login(&user).await.unwrap();
Ok(())
}
from axum-login.
Without a more complete example, it's going to be difficult to advise.
The auth context missing usually means that the middleware isn't installed for that route.
from axum-login.
I've updated my above comment to include the full main.rs, and the error
from axum-login.
Are you able to share your routes as well? The error is about the middleware not being present.
Edit: Oh I see it's in your main.rs. I'll try to take a closer look.
from axum-login.
All right, so I'm not going to be able to run your code directly since there's a few missing dependencies and modules internal to your project.
That said, I tried my best to replicate your situation with the SQLite example. Here's the diff in case you'd like to see (you'll also have to modify the user_store.db
with the role column):
diff --git a/examples/sqlite/src/main.rs b/examples/sqlite/src/main.rs
index 565e23e..0e84e3a 100644
--- a/examples/sqlite/src/main.rs
+++ b/examples/sqlite/src/main.rs
@@ -8,19 +8,26 @@ use axum::{response::IntoResponse, routing::get, Extension, Router};
use axum_login::{
axum_sessions::{async_session::MemoryStore, SessionLayer},
secrecy::SecretVec,
- AuthLayer, AuthUser, RequireAuthorizationLayer, SqliteStore,
+ AuthLayer, AuthUser, RequireAuthorizationLayer,
};
use rand::Rng;
use sqlx::sqlite::SqlitePoolOptions;
-#[derive(Debug, Default, Clone, sqlx::FromRow)]
+#[derive(Clone, Debug, PartialEq, PartialOrd, sqlx::Type)]
+pub enum UserRole {
+ Standard,
+ Admin,
+}
+
+#[derive(Debug, Clone, sqlx::FromRow)]
struct User {
id: i64,
password_hash: String,
name: String,
+ role: UserRole,
}
-impl AuthUser for User {
+impl AuthUser<UserRole> for User {
fn get_id(&self) -> String {
format!("{}", self.id)
}
@@ -28,9 +35,14 @@ impl AuthUser for User {
fn get_password_hash(&self) -> SecretVec<u8> {
SecretVec::new(self.password_hash.clone().into())
}
+
+ fn get_role(&self) -> Option<UserRole> {
+ Some(self.role.clone())
+ }
}
-type AuthContext = axum_login::extractors::AuthContext<User, SqliteStore<User>>;
+type SqliteStore = axum_login::SqliteStore<User, UserRole>;
+type AuthContext = axum_login::extractors::AuthContext<User, SqliteStore, UserRole>;
#[tokio::main]
async fn main() {
@@ -44,8 +56,8 @@ async fn main() {
.await
.unwrap();
- let user_store = SqliteStore::<User>::new(pool);
- let auth_layer = AuthLayer::new(user_store, &secret);
+ let user_store = SqliteStore::new(pool);
+ let auth_layer = AuthLayer::<SqliteStore, User, UserRole>::new(user_store, &secret);
async fn login_handler(mut auth: AuthContext) {
let pool = SqlitePoolOptions::new()
@@ -71,7 +83,7 @@ async fn main() {
let app = Router::new()
.route("/protected", get(protected_handler))
- .route_layer(RequireAuthorizationLayer::<User>::login())
+ .route_layer(RequireAuthorizationLayer::<User, UserRole>::login())
.route("/login", get(login_handler))
.route("/logout", get(logout_handler))
.layer(auth_layer)
diff --git a/examples/sqlite/user_store.db b/examples/sqlite/user_store.db
index d26f080..f0b7743 100644
Binary files a/examples/sqlite/user_store.db and b/examples/sqlite/user_store.db differ
In your example, this line seems to be missing something:
type AuthContext = axum_login::extractors::AuthContext<User, PostgresStore<User>, UserRole>;
The PostgresStore
should also indicate the concrete role type because otherwise it will default to the unit type. Does changing that line address the issue for you?
from axum-login.
Related Issues (20)
- Support tower-sessions HOT 3
- Feature Request: Locking user out HOT 2
- Consider reorganizing examples into a workspace
- Make the `DATA_KEY` configurable
- Evaluate better management of sensitive data HOT 1
- Bring coverage back HOT 2
- Macro hygiene is broken
- Error type made public HOT 5
- Custom `Debug` implementation for `User` but not `Credentials` in SQLite example? HOT 1
- Could not find `http` in `$crate` HOT 1
- Is 2FA possible?
- `AuthnBackend#Credentials: Clone` breaks `oauth2::PkceCodeVerifier` HOT 1
- Session Cookie Removed on Reload
- Can't extract auth session. Is `AuthManagerLayer` enabled? HOT 8
- login_required macro generates invalid redirect URL HOT 3
- State isn't saved when using axum-login with leptos
- Going back to login page should not complete if the user logged HOT 2
- Dependency on time crate in "Duration"
- Session expiration has no effect
- examples/sqlite database in wrong folder and useless files HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from axum-login.