forked from spacebar/spfn-website
Move Generate Token to Backend
This commit is contained in:
parent
fa2c7d9ca5
commit
91882fe4ae
7 changed files with 113 additions and 7 deletions
8
.env.example
Normal file
8
.env.example
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
# Specify the host and port the website will be hosted on, defaults to these
|
||||
APP_HOST=0.0.0.0
|
||||
APP_PORT=80
|
||||
|
||||
# Account Client and Secret
|
||||
# Token generation will always fail if no secret is specified
|
||||
ACCOUNT_CLIENT_ID=account
|
||||
ACCOUNT_CLIENT_SECRET=secret
|
||||
|
|
@ -6,5 +6,7 @@ edition = "2024"
|
|||
[dependencies]
|
||||
axum = "0.8.9"
|
||||
dotenvy = "0.15.7"
|
||||
reqwest = { version = "0.13.4", features = ["json", "form"] }
|
||||
serde = { version = "1.0.228", features = ["derive"] }
|
||||
tokio = { version = "1.52.3", features = ["full"] }
|
||||
tower-http = { version = "0.7.0", features = ["fs"] }
|
||||
|
|
|
|||
8
src/api/mod.rs
Normal file
8
src/api/mod.rs
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
use axum::Router;
|
||||
|
||||
pub mod v1;
|
||||
|
||||
pub fn router() -> Router {
|
||||
Router::new()
|
||||
.nest("/v1", v1::router())
|
||||
}
|
||||
78
src/api/v1/login.rs
Normal file
78
src/api/v1/login.rs
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
use std::env;
|
||||
use axum::{Router, Json};
|
||||
use axum::routing::post;
|
||||
use reqwest::StatusCode;
|
||||
use reqwest::Client;
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct GenerateTokenRequest {
|
||||
username: String,
|
||||
password: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct TokenRequest {
|
||||
grant_type: String,
|
||||
username: String,
|
||||
password: String,
|
||||
client_id: String,
|
||||
client_secret: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct TokenResponse {
|
||||
access_token: String,
|
||||
token_type: String,
|
||||
expires_in: i64,
|
||||
}
|
||||
|
||||
pub fn router() -> Router {
|
||||
Router::new()
|
||||
.route("/login/generate_token", post(gen_token))
|
||||
}
|
||||
|
||||
async fn gen_token(Json(payload): Json<GenerateTokenRequest>) -> Result<Json<TokenResponse>, StatusCode> {
|
||||
let client = Client::new();
|
||||
|
||||
let client_id = env::var("ACCOUNT_CLIENT_ID").unwrap_or("account".into());
|
||||
let client_secret = match env::var("ACCOUNT_CLIENT_SECRET") {
|
||||
Ok(secret) => secret,
|
||||
Err(_) => {
|
||||
println!("No account client secret specified - Token generation will always fail");
|
||||
return Err(StatusCode::INTERNAL_SERVER_ERROR)
|
||||
},
|
||||
};
|
||||
|
||||
let body = TokenRequest {
|
||||
grant_type: "password".into(),
|
||||
username: payload.username,
|
||||
password: payload.password,
|
||||
client_id,
|
||||
client_secret,
|
||||
};
|
||||
|
||||
let response = client
|
||||
.post(format!("{}/api/v2/oauth2/generate_token", "https://account.spfn.net"))
|
||||
.form(&body)
|
||||
.send()
|
||||
.await;
|
||||
|
||||
match response {
|
||||
Ok(res) => {
|
||||
let body = res.json::<TokenResponse>().await;
|
||||
|
||||
match body {
|
||||
Ok(b) => return Ok(Json(b)),
|
||||
Err(_) => return Err(StatusCode::BAD_GATEWAY)
|
||||
};
|
||||
},
|
||||
Err(e) => match e.status() {
|
||||
Some(code) => return Err(code),
|
||||
None => {
|
||||
println!("[/api/v1/login/generate_token] No status error returned from upstream: {}", e);
|
||||
return Err(StatusCode::BAD_GATEWAY);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
8
src/api/v1/mod.rs
Normal file
8
src/api/v1/mod.rs
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
use axum::Router;
|
||||
|
||||
pub mod login;
|
||||
|
||||
pub fn router() -> Router {
|
||||
Router::new()
|
||||
.merge(login::router())
|
||||
}
|
||||
|
|
@ -3,6 +3,8 @@ use axum::Router;
|
|||
use tower_http::services::ServeDir;
|
||||
use dotenvy::dotenv;
|
||||
|
||||
mod api;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
dotenv().ok();
|
||||
|
|
@ -11,6 +13,7 @@ async fn main() {
|
|||
let port = env::var("APP_PORT").unwrap_or("80".into());
|
||||
|
||||
let app = Router::new()
|
||||
.nest("/api", api::router())
|
||||
.fallback_service(ServeDir::new("static"));
|
||||
|
||||
let listener = tokio::net::TcpListener::bind(format!("{}:{}", host, port))
|
||||
|
|
|
|||
|
|
@ -12,18 +12,17 @@ function loginError(message, code = null) {
|
|||
}
|
||||
|
||||
async function generateToken(username, password) {
|
||||
const credentials = btoa(`${username} ${password}`);
|
||||
|
||||
const body = `grant_type=password&username=${username}&password=${password}&client_id=website`
|
||||
|
||||
let response;
|
||||
try {
|
||||
response = await fetch("https://account.spfn.net/api/v2/oauth2/generate_token", {
|
||||
response = await fetch("/api/v1/login/generate_token", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded"
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body,
|
||||
body: JSON.stringify({
|
||||
username,
|
||||
password,
|
||||
}),
|
||||
})
|
||||
} catch (err) {
|
||||
loginError(`Internal Server Error: ${err.message}`)
|
||||
|
|
|
|||
Loading…
Reference in a new issue