This commit is contained in:
2025-05-08 08:05:19 +03:00
parent 4274fdaf93
commit 433606eb25
12 changed files with 207 additions and 147 deletions

View File

@@ -2,16 +2,6 @@
This guide provides detailed instructions on how to integrate Gitea authentication into your Hostbasket application.
## Table of Contents
1. [Introduction](#introduction)
2. [Prerequisites](#prerequisites)
3. [Setting Up Gitea OAuth Application](#setting-up-gitea-oauth-application)
4. [Configuring Hostbasket for Gitea Authentication](#configuring-hostbasket-for-gitea-authentication)
5. [Implementing the OAuth Flow](#implementing-the-oauth-flow)
6. [Testing the Integration](#testing-the-integration)
7. [Troubleshooting](#troubleshooting)
## Introduction
Gitea is a self-hosted Git service that provides a GitHub-like interface. By integrating Gitea authentication into your Hostbasket application, you can allow users to log in using their Gitea accounts, simplifying the authentication process and providing a seamless experience.
@@ -27,7 +17,7 @@ Before you begin, ensure you have:
## Setting Up Gitea OAuth Application
1. Log in to your Gitea instance as an administrator
2. Navigate to **Site Administration** > **Applications**
2. Navigate to **Site Administration** > **Integrations** > **Applications**
3. Click **Create a New OAuth2 Application**
4. Fill in the application details:
- **Application Name**: Hostbasket
@@ -96,11 +86,11 @@ impl GiteaOAuthConfig {
.expect("Missing GITEA_CLIENT_SECRET environment variable");
let instance_url = env::var("GITEA_INSTANCE_URL")
.expect("Missing GITEA_INSTANCE_URL environment variable");
// Create OAuth client
let auth_url = format!("{}/login/oauth/authorize", instance_url);
let token_url = format!("{}/login/oauth/access_token", instance_url);
let client = BasicClient::new(
ClientId::new(client_id),
Some(ClientSecret::new(client_secret)),
@@ -110,7 +100,7 @@ impl GiteaOAuthConfig {
.set_redirect_uri(
RedirectUrl::new("http://localhost:9999/auth/gitea/callback".to_string()).unwrap(),
);
Self {
client,
instance_url,
@@ -158,16 +148,16 @@ impl GiteaAuthController {
.add_scope(Scope::new("read:user".to_string()))
.add_scope(Scope::new("user:email".to_string()))
.url();
// Store the CSRF token in the session
session.insert("oauth_csrf_token", csrf_token.secret())?;
// Redirect to the authorization URL
Ok(HttpResponse::Found()
.append_header((header::LOCATION, auth_url.to_string()))
.finish())
}
// Handle the OAuth callback
pub async fn callback(
oauth_config: web::Data<GiteaOAuthConfig>,
@@ -177,11 +167,11 @@ impl GiteaAuthController {
// Verify the CSRF token
let csrf_token = session.get::<String>("oauth_csrf_token")?
.ok_or_else(|| actix_web::error::ErrorBadRequest("Missing CSRF token"))?;
if csrf_token != query.state {
return Err(actix_web::error::ErrorBadRequest("Invalid CSRF token"));
}
// Exchange the authorization code for an access token
let token = oauth_config
.client
@@ -189,11 +179,11 @@ impl GiteaAuthController {
.request_async(oauth2::reqwest::async_http_client)
.await
.map_err(|e| actix_web::error::ErrorInternalServerError(format!("Token exchange error: {}", e)))?;
// Get the user information from Gitea
let client = Client::new();
let user_info_url = format!("{}/api/v1/user", oauth_config.instance_url);
let gitea_user = client
.get(&user_info_url)
.bearer_auth(token.access_token().secret())
@@ -203,26 +193,26 @@ impl GiteaAuthController {
.json::<crate::config::oauth::GiteaUser>()
.await
.map_err(|e| actix_web::error::ErrorInternalServerError(format!("JSON parsing error: {}", e)))?;
// Create or update the user in your system
let mut user = User::new(
gitea_user.full_name.clone(),
gitea_user.email.clone(),
);
// Set the user ID and role
user.id = Some(gitea_user.id as i32);
user.role = UserRole::User;
// Generate JWT token
let token = AuthController::generate_token(&user.email, &user.role)
.map_err(|_| actix_web::error::ErrorInternalServerError("Failed to generate token"))?;
// Store user data in session
let user_json = serde_json::to_string(&user).unwrap();
session.insert("user", &user_json)?;
session.insert("auth_token", &token)?;
// Create a cookie with the JWT token
let cookie = Cookie::build("auth_token", token)
.path("/")
@@ -230,7 +220,7 @@ impl GiteaAuthController {
.secure(false) // Set to true in production with HTTPS
.max_age(actix_web::cookie::time::Duration::hours(24))
.finish();
// Redirect to the home page with JWT token in cookie
Ok(HttpResponse::Found()
.cookie(cookie)
@@ -258,7 +248,7 @@ use crate::config::oauth::GiteaOAuthConfig;
pub fn configure_routes(cfg: &mut web::ServiceConfig) {
// Create the OAuth configuration
let oauth_config = web::Data::new(GiteaOAuthConfig::new());
// Configure session middleware with the consistent key
let session_middleware = SessionMiddleware::builder(
CookieSessionStore::default(),
@@ -273,7 +263,7 @@ pub fn configure_routes(cfg: &mut web::ServiceConfig) {
.wrap(session_middleware)
.app_data(oauth_config.clone())
// Existing routes...
// Gitea OAuth routes
.route("/auth/gitea", web::get().to(GiteaAuthController::login))
.route("/auth/gitea/callback", web::get().to(GiteaAuthController::callback))
@@ -310,9 +300,9 @@ Update your login page template (`src/views/auth/login.html`) to include a "Logi
</div>
<button type="submit" class="btn btn-primary">Login</button>
</form>
<hr>
<div class="text-center">
<p>Or login with:</p>
<a href="/auth/gitea" class="btn btn-secondary">