added signin endpoint
This commit is contained in:
parent
e0e58811a8
commit
2856b1bbd8
99
src/main.rs
99
src/main.rs
@ -1,16 +1,28 @@
|
||||
use axum::{
|
||||
extract::{Query, State},
|
||||
extract::State,
|
||||
http::StatusCode,
|
||||
response::IntoResponse,
|
||||
routing::{get, post},
|
||||
Json, Router,
|
||||
};
|
||||
use jsonwebtoken::{EncodingKey, Header};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::json;
|
||||
use sqlx::postgres::PgPoolOptions;
|
||||
use sqlx::PgPool;
|
||||
use std::net::SocketAddr;
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, Debug, Hash)]
|
||||
struct Claims {
|
||||
username: String,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct AppState {
|
||||
db_pool: PgPool,
|
||||
jwt_key: EncodingKey,
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
// initialize tracing
|
||||
@ -21,6 +33,8 @@ async fn main() {
|
||||
let db_url = std::env::var("DATABASE_URL")
|
||||
.expect("Set `DATABASE_URL` to the url of the postgres database.");
|
||||
|
||||
let jwt_secret = std::env::var("SAAPI_JWT_SECRET").unwrap_or("Sdb\\y5PP`,hmG+98".into());
|
||||
|
||||
let pool = PgPoolOptions::new()
|
||||
.max_connections(50)
|
||||
.connect(&db_url)
|
||||
@ -33,7 +47,11 @@ async fn main() {
|
||||
.route("/", get(root))
|
||||
// `POST /users` goes to `create_user`
|
||||
.route("/user/signup", post(signup))
|
||||
.with_state(pool);
|
||||
.route("/user/signin", post(signin))
|
||||
.with_state(AppState {
|
||||
db_pool: pool,
|
||||
jwt_key: EncodingKey::from_secret(jwt_secret.as_bytes()),
|
||||
});
|
||||
|
||||
// run our app with hyper
|
||||
// `axum::Server` is a re-export of `hyper::Server`
|
||||
@ -50,20 +68,23 @@ async fn root() -> &'static str {
|
||||
"Hello, World!"
|
||||
}
|
||||
|
||||
async fn signup(State(pool): State<PgPool>, Json(signup): Json<Signup>) -> impl IntoResponse {
|
||||
async fn signup(
|
||||
State(app_state): State<AppState>,
|
||||
Json(signup): Json<Signup>,
|
||||
) -> impl IntoResponse {
|
||||
// insert your application logic here
|
||||
let pass_hash = sha256::digest(&*signup.password);
|
||||
|
||||
let result = sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO users (username, password)
|
||||
VALUES ( $1, $2 )
|
||||
RETURNING id;
|
||||
INSERT INTO users (username, password)
|
||||
VALUES ( $1, $2 )
|
||||
RETURNING id;
|
||||
"#,
|
||||
signup.username,
|
||||
pass_hash.as_bytes(),
|
||||
)
|
||||
.fetch_one(&pool)
|
||||
.fetch_one(&app_state.db_pool)
|
||||
.await;
|
||||
|
||||
match result {
|
||||
@ -92,13 +113,75 @@ RETURNING id;
|
||||
}
|
||||
}
|
||||
|
||||
// the input to our `create_user` handler
|
||||
async fn signin(
|
||||
State(app_state): State<AppState>,
|
||||
Json(signin): Json<Signin>,
|
||||
) -> impl IntoResponse {
|
||||
let pass_hash = sha256::digest(&*signin.password);
|
||||
|
||||
let result = sqlx::query!(
|
||||
r#"
|
||||
SELECT username
|
||||
FROM users
|
||||
WHERE username = $1 AND password = $2
|
||||
"#,
|
||||
signin.username,
|
||||
pass_hash.as_bytes(),
|
||||
)
|
||||
.fetch_optional(&app_state.db_pool)
|
||||
.await;
|
||||
|
||||
match result {
|
||||
Ok(Some(user)) => {
|
||||
let claims = Claims {
|
||||
username: user.username,
|
||||
};
|
||||
let token = match jsonwebtoken::encode(&Header::default(), &claims, &app_state.jwt_key)
|
||||
{
|
||||
Ok(token) => token,
|
||||
Err(err) => {
|
||||
return (
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
Json(json!({
|
||||
"error": format!("Unknown error signing in when creating JWT: {}", err)
|
||||
})),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
return (StatusCode::OK, Json(json!({ "data": token })));
|
||||
}
|
||||
Ok(None) => {
|
||||
return (
|
||||
StatusCode::UNAUTHORIZED,
|
||||
Json(json!({
|
||||
"error": format!("Incorrect username or password")
|
||||
})),
|
||||
)
|
||||
}
|
||||
Err(err) => {
|
||||
return (
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
Json(json!({
|
||||
"error": format!("Unknown error signing in: {}", err)
|
||||
})),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
struct Signup {
|
||||
username: String,
|
||||
password: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
struct Signin {
|
||||
username: String,
|
||||
password: String,
|
||||
}
|
||||
|
||||
// the output to our `create_user` handler
|
||||
#[derive(Serialize, sqlx::FromRow)]
|
||||
struct User {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user