server (http): add jwt token validator and route `/auth/whoami`

This commit is contained in:
MedzikUser 2022-04-23 23:48:20 +02:00
parent 5164a94a55
commit 2924e38592
No known key found for this signature in database
GPG Key ID: A5FAC1E185C112DB
10 changed files with 90 additions and 0 deletions

13
Cargo.lock generated
View File

@ -120,6 +120,17 @@ dependencies = [
"tower-service",
]
[[package]]
name = "axum-auth"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a78cc399f2af2dd7adf88e0fcc0e21dbf730258c1b34785f47816ff224238f74"
dependencies = [
"axum",
"base64",
"http",
]
[[package]]
name = "axum-core"
version = "0.2.2"
@ -609,9 +620,11 @@ name = "homedisk-server"
version = "0.0.0"
dependencies = [
"axum",
"axum-auth",
"homedisk-database",
"homedisk-types",
"hyper",
"jsonwebtoken",
"log",
"rust_utilities",
"serde",

View File

@ -66,6 +66,24 @@ impl Database {
password,
})
}
pub async fn find_user_by_id(&self, id: String) -> Result<User, Error> {
let query = sqlx::query_as::<_, User>("SELECT * FROM user WHERE id = ?").bind(id);
let mut stream = self.conn.fetch(query);
let row = stream.try_next().await?.ok_or(Error::UserNotFound)?;
let id = row.try_get("id")?;
let username = row.try_get("username")?;
let password = row.try_get("password")?;
Ok(User {
id,
username,
password,
})
}
}
#[cfg(test)]

View File

@ -13,3 +13,5 @@ hyper = { version = "0.14.18", features = ["full"] }
rust_utilities = { version = "0.2.0", features = ["jsonwebtoken"] }
homedisk-database = { path = "../database" }
homedisk-types = { path = "../types", features = ["axum"] }
axum-auth = "0.2.0"
jsonwebtoken = "8.1.0"

View File

@ -1,5 +1,6 @@
pub mod login;
pub mod register;
pub mod whoami;
pub fn app() -> axum::Router {
use axum::routing::post;
@ -7,4 +8,5 @@ pub fn app() -> axum::Router {
axum::Router::new()
.route("/login", post(login::handle))
.route("/register", post(register::handle))
.route("/whoami", post(whoami::handle))
}

35
server/src/auth/whoami.rs Normal file
View File

@ -0,0 +1,35 @@
use axum::{Extension, Json};
use axum_auth::AuthBearer;
use homedisk_database::{Database, Error};
use homedisk_types::{
auth::whoami::Response,
config::types::Config,
errors::{AuthError, ServerError},
};
use crate::middleware::validate_jwt;
pub async fn handle(
db: Extension<Database>,
config: Extension<Config>,
AuthBearer(token): AuthBearer,
) -> Result<Json<Response>, ServerError> {
let token = validate_jwt(config.jwt.secret.as_bytes(), &token)?;
let response = match db.find_user_by_id(token.claims.sub).await {
Ok(res) => Response {
username: res.username,
},
Err(err) => match err {
Error::UserNotFound => return Err(ServerError::AuthError(AuthError::UserNotFound)),
_ => {
return Err(ServerError::AuthError(AuthError::UnknowError(
err.to_string(),
)))
}
},
};
Ok(Json(response))
}

View File

@ -1 +1,10 @@
use homedisk_types::errors::{AuthError, ServerError};
use jsonwebtoken::TokenData;
use rust_utilities::crypto::jsonwebtoken::{Claims, Token};
pub fn validate_jwt(secret: &[u8], token: &str) -> Result<TokenData<Claims>, ServerError> {
match Token::decode(secret, token.to_string()) {
Ok(claims) => Ok(claims),
Err(_) => Err(ServerError::AuthError(AuthError::InvalidToken)),
}
}

View File

@ -1 +1,2 @@
pub mod login;
pub mod whoami;

6
types/src/auth/whoami.rs Normal file
View File

@ -0,0 +1,6 @@
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Response {
pub username: String,
}

View File

@ -11,6 +11,9 @@ pub enum Error {
#[error("generate jwt token")]
TokenGenerate,
#[error("invalid jwt token")]
InvalidToken,
#[error("unknow error")]
UnknowError(String),
}

View File

@ -41,6 +41,7 @@ impl axum::response::IntoResponse for ServerError {
AuthError::UserAlreadyExists => StatusCode::NOT_ACCEPTABLE,
AuthError::TokenGenerate => StatusCode::INTERNAL_SERVER_ERROR,
AuthError::UnknowError(_) => StatusCode::INTERNAL_SERVER_ERROR,
AuthError::InvalidToken => StatusCode::BAD_REQUEST,
},
Self::MissingJsonContentType => StatusCode::BAD_REQUEST,