server (http): add jwt token validator and route `/auth/whoami`
This commit is contained in:
parent
5164a94a55
commit
2924e38592
|
@ -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",
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
}
|
|
@ -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)),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
pub mod login;
|
||||
pub mod whoami;
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct Response {
|
||||
pub username: String,
|
||||
}
|
|
@ -11,6 +11,9 @@ pub enum Error {
|
|||
#[error("generate jwt token")]
|
||||
TokenGenerate,
|
||||
|
||||
#[error("invalid jwt token")]
|
||||
InvalidToken,
|
||||
|
||||
#[error("unknow error")]
|
||||
UnknowError(String),
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue