#Axum session_token cookie help
17 messages · Page 1 of 1 (latest)
use std::time::Duration;
use axum::{
http::{header::USER_AGENT, HeaderMap, StatusCode},
Extension, Json,
};
use axum_extra::extract::{
cookie::{Cookie, SameSite},
CookieJar,
};
use axum_macros::debug_handler;
use bcrypt::verify;
use serde::Deserialize;
use sqlx::{types::chrono::Utc, SqlitePool};
use uuid::Uuid;
use crate::error::{AppError, AuthError};
#[derive(Deserialize)]
pub struct Login {
pub username: String,
pub password: String,
}
#[debug_handler]
pub async fn login(
Extension(pool): Extension<SqlitePool>,
headers: HeaderMap,
jar: CookieJar,
Json(login): Json<Login>,
) -> Result<(CookieJar, StatusCode), AppError> {
struct User {
id: i64,
password_hash: String,
}
let user = sqlx::query_as!(
User,
r#"SELECT id as "id!", password_hash FROM users WHERE username = ?"#,
login.username
)
.fetch_one(&pool)
.await
.map_err(|e| match e {
sqlx::Error::RowNotFound => AuthError::UserNotFound(login.username.clone()).into(),
_ => <sqlx::Error as Into<AppError>>::into(e),
})?;
match verify(login.password, &user.password_hash)? {
false => Err(AuthError::InvalidCredentials.into()),
true => {
let session_token = Uuid::new_v4().to_string();
let created_at = Utc::now();
let expires_at = created_at + Duration::from_secs(3600);
let user_agent = headers.get(USER_AGENT).and_then(|val| val.to_str().ok());
sqlx::query!(
"INSERT INTO sessions (token, user_id, created_at, expires_at, user_agent) VALUES (?, ?, ?, ?, ?)",
session_token,
user.id,
created_at,
expires_at,
user_agent
)
.execute(&pool)
.await?;
let session_cookie = Cookie::build(("session_token", session_token))
.path("/")
.http_only(true)
.same_site(SameSite::Strict)
.expires(expires_at)
;
let jar = jar.add(session_cookie);
Ok((jar, StatusCode::OK))
}
}
}
error[E0277]: the trait bound `std::option::Option<time::offset_date_time::OffsetDateTime>: From<sqlx::types::chrono::DateTime<Utc>>` is not satisfied
--> src\login.rs:72:26
|
72 | .expires(expires_at)
| ------- ^^^^^^^^^^ the trait `From<sqlx::types::chrono::DateTime<Utc>>` is not implemented for `std::option::Option<time::offset_date_time::OffsetDateTime>`, which is required by `sqlx::types::chrono::DateTime<Utc>: Into<Expiration>`
| |
| required by a bound introduced by this call
|
= help: the following other types implement trait `From<T>`:
<std::option::Option<&'a Id> as From<&'a EnteredSpan>>
<std::option::Option<&'a Id> as From<&'a Span>>
<std::option::Option<&'a Id> as From<&'a tracing_core::span::Current>>
<std::option::Option<&'a T> as From<&'a std::option::Option<T>>>
<std::option::Option<&'a mut T> as From<&'a mut std::option::Option<T>>>
<std::option::Option<&'static tracing::Metadata<'static>> as From<&'a tracing_core::span::Current>>
<std::option::Option<Id> as From<&'a EnteredSpan>>
<std::option::Option<Id> as From<&'a Id>>
and 19 others
= note: required for `sqlx::types::chrono::DateTime<Utc>` to implement `Into<std::option::Option<time::offset_date_time::OffsetDateTime>>`
= note: required for `Expiration` to implement `From<sqlx::types::chrono::DateTime<Utc>>`
= note: 1 redundant requirement hidden
= note: required for `sqlx::types::chrono::DateTime<Utc>` to implement `Into<Expiration>`
note: required by a bound in `cookie::builder::CookieBuilder::<'c>::expires`
--> C:\Users\zahas\.cargo\registry\src\index.crates.io-6f17d22bba15001f\cookie-0.18.1\src\builder.rs:88:23
|
88 | pub fn expires<E: Into<Expiration>>(mut self, when: E) -> Self {
| ^^^^^^^^^^^^^^^^ required by this bound in `CookieBuilder::<'c>::expires`
[dependencies]
axum = "0.7"
axum-extra = { version = "0.9", features = ["cookie"] }
axum-macros = "0.4"
bcrypt = "0.15"
dotenv = "0.15"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
sqlx = { version = "0.8", features = [
"chrono",
"migrate",
"runtime-tokio-native-tls",
"sqlite",
] }
thiserror = "1"
tokio = { version = "1", features = ["full"] }
tower-http = { version = "0.5", features = ["trace"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
uuid = { version = "1.2", features = ["v4"] }
@vernal knot you need to use the time crate instead of chrono. also if you're doing sessions, i would use tower-sessions and that handles it all for you. once the user is authenticated you can add like logged_in = {user_id} to the session store
?crate tower-sessions
do you know any tutorial/blog/video on tower sessions?
on tower-session?
yes
what do you mean by this once the user is authenticated you can add like logged_in = {user_id} to the session store
are you talking about custom extractors?