use axum::{
Router,
extract::Json,
http::StatusCode,
response::IntoResponse,
routing::{get, post},
};
use serde::{Deserialize, Serialize};
use seshcookie::{SameSite, Session, SessionConfig, SessionKeys, SessionLayer};
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
struct User {
id: u64,
name: String,
}
#[derive(Deserialize)]
struct LoginRequest {
name: String,
}
async fn login(session: Session<User>, Json(req): Json<LoginRequest>) -> impl IntoResponse {
let user = User {
id: 1,
name: req.name,
};
session.insert(user).await;
StatusCode::NO_CONTENT
}
async fn me(session: Option<Session<User>>) -> impl IntoResponse {
match session {
Some(s) => match s.get().await {
Some(u) => (StatusCode::OK, Json(u)).into_response(),
None => StatusCode::UNAUTHORIZED.into_response(),
},
None => StatusCode::UNAUTHORIZED.into_response(),
}
}
async fn logout(session: Session<User>) -> impl IntoResponse {
session.clear().await;
StatusCode::NO_CONTENT
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let secret = b"0123456789abcdef0123456789abcdef";
let keys = SessionKeys::new(secret)?;
let config = SessionConfig::default()
.secure(false)
.same_site(SameSite::Lax);
let layer = SessionLayer::<User>::new(keys, config)?;
let app = Router::new()
.route("/login", post(login))
.route("/me", get(me))
.route("/logout", post(logout))
.layer(layer);
let listener = tokio::net::TcpListener::bind("127.0.0.1:3000").await?;
println!("listening on http://127.0.0.1:3000");
axum::serve(listener, app).await?;
Ok(())
}