Fix .gitignore and add missing authentication source files
This commit fixes overly broad .gitignore patterns that were excluding important source code files from version control. Previously, wildcard patterns like *auth*, *token*, *secret*, *connection*, and *credential* were excluding ALL files containing these words, including critical application code. Changes: - Updated .gitignore with specific patterns for sensitive config files (*.json, *.txt, *.yml, *.yaml extensions only) - Removed broad wildcards that excluded source code files Added missing source files: - shared/auth/ (9 files): Complete authentication system - JWT handler, middleware, auth service, models, routes - reports-app/backend/app/routers/auth.py: Authentication API router - reports-app/backend/app/auth_middleware_wrapper.py: Middleware wrapper - reports-app/frontend/src/stores/auth.js: Vue.js auth store - reports-app/frontend/tests/: E2E tests and fixtures for auth - reports-app/telegram-bot/app/auth/: Telegram auth linking module - deployment/windows/scripts/Setup-ClaudeAuth.ps1: Windows deployment script - security/secrets_scanner.py: Security scanning utility These files are essential for the application to function and should have been included in the initial commit. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
649
shared/auth/README.md
Normal file
649
shared/auth/README.md
Normal file
@@ -0,0 +1,649 @@
|
||||
# 🔐 ROA2WEB Shared Authentication System
|
||||
|
||||
Sistem de autentificare JWT partajat între toate aplicațiile din ecosistemul ROA2WEB, integrat cu Oracle Database și optimizat pentru aplicații FastAPI.
|
||||
|
||||
## 📋 Table of Contents
|
||||
|
||||
- [Features](#features)
|
||||
- [Architecture](#architecture)
|
||||
- [Quick Start](#quick-start)
|
||||
- [Components](#components)
|
||||
- [Integration Guide](#integration-guide)
|
||||
- [Security Features](#security-features)
|
||||
- [API Reference](#api-reference)
|
||||
- [Testing](#testing)
|
||||
- [Deployment](#deployment)
|
||||
- [Troubleshooting](#troubleshooting)
|
||||
|
||||
## ✨ Features
|
||||
|
||||
### Core Features
|
||||
- **JWT Authentication**: Secure token-based authentication cu access și refresh tokens
|
||||
- **Oracle Database Integration**: Folosește `pack_drepturi.verificautilizator` pentru autentificare
|
||||
- **Multi-Company Support**: Acces controlat la multiple firme/schemas Oracle
|
||||
- **Permission System**: Sistem granular de permisiuni (read, write, admin, reports)
|
||||
- **FastAPI Integration**: Dependencies și middleware native pentru FastAPI
|
||||
- **Rate Limiting**: Protecție împotriva brute force attacks
|
||||
- **Caching**: Cache inteligent pentru performanță optimă
|
||||
|
||||
### Security Features
|
||||
- **Token Expiration**: Configurabil pentru access și refresh tokens
|
||||
- **SQL Injection Protection**: Parametri legați în toate query-urile
|
||||
- **Rate Limiting**: Configurabil per IP și endpoint
|
||||
- **CORS Protection**: Configurare flexibilă pentru origins
|
||||
- **Header Security**: Security headers automate
|
||||
- **Token Blacklisting**: Suport pentru invalidarea token-urilor (în dezvoltare)
|
||||
|
||||
## 🏗️ Architecture
|
||||
|
||||
```
|
||||
ROA2WEB Authentication Flow:
|
||||
┌─────────────┐ ┌──────────────┐ ┌─────────────┐ ┌──────────────┐
|
||||
│ Client │───▶│ FastAPI │───▶│ JWT │───▶│ Oracle │
|
||||
│ (Frontend) │ │ Application │ │ Handler │ │ Database │
|
||||
└─────────────┘ └──────────────┘ └─────────────┘ └──────────────┘
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
┌──────────────┐ ┌─────────────┐ ┌──────────────┐
|
||||
│ Auth Service │ │ Middleware │ │ User Cache │
|
||||
└──────────────┘ └─────────────┘ └──────────────┘
|
||||
```
|
||||
|
||||
### Components Overview
|
||||
|
||||
```
|
||||
shared/auth/
|
||||
├── jwt_handler.py # JWT token creation și validation
|
||||
├── auth_service.py # Oracle database integration
|
||||
├── models.py # Pydantic models pentru data validation
|
||||
├── middleware.py # FastAPI middleware pentru auto-authentication
|
||||
├── dependencies.py # FastAPI dependencies pentru protected routes
|
||||
├── routes.py # Pre-built authentication routes
|
||||
├── test_auth.py # Comprehensive test suite
|
||||
├── demo_app.py # Demo application cu examples
|
||||
└── README.md # Această documentație
|
||||
```
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
### 1. Environment Setup
|
||||
|
||||
```bash
|
||||
# Copy și configurează environment variables
|
||||
cp .env.example .env
|
||||
|
||||
# Edit .env cu configurările tale
|
||||
JWT_SECRET_KEY=your-super-secret-jwt-key-change-in-production
|
||||
ORACLE_USER=your_oracle_username
|
||||
ORACLE_PASSWORD=your_oracle_password
|
||||
ORACLE_DSN=your_oracle_connection_string
|
||||
```
|
||||
|
||||
### 2. Basic Integration
|
||||
|
||||
```python
|
||||
from fastapi import FastAPI, Depends
|
||||
from roa2web.shared.auth import (
|
||||
AuthenticationMiddleware, create_auth_router,
|
||||
get_current_user, CurrentUser
|
||||
)
|
||||
from roa2web.shared.database import oracle_pool
|
||||
|
||||
app = FastAPI(title="My ROA2WEB App")
|
||||
|
||||
# Add authentication middleware
|
||||
app.add_middleware(
|
||||
AuthenticationMiddleware,
|
||||
excluded_paths=["/", "/docs", "/health", "/auth/login"]
|
||||
)
|
||||
|
||||
# Include authentication routes
|
||||
auth_router = create_auth_router()
|
||||
app.include_router(auth_router)
|
||||
|
||||
@app.on_event("startup")
|
||||
async def startup():
|
||||
await oracle_pool.initialize()
|
||||
|
||||
@app.get("/protected")
|
||||
async def protected_endpoint(
|
||||
current_user: CurrentUser = Depends(get_current_user)
|
||||
):
|
||||
return {"message": f"Hello {current_user.username}!"}
|
||||
```
|
||||
|
||||
### 3. Test Authentication
|
||||
|
||||
```bash
|
||||
# Start demo application
|
||||
cd roa2web/shared/auth
|
||||
python demo_app.py
|
||||
|
||||
# Open browser
|
||||
open http://localhost:8000/docs
|
||||
|
||||
# Login prin Swagger UI cu credențialele Oracle
|
||||
```
|
||||
|
||||
## 🧩 Components
|
||||
|
||||
### JWT Handler (`jwt_handler.py`)
|
||||
|
||||
Gestionează crearea, validarea și refresh-ul token-urilor JWT.
|
||||
|
||||
```python
|
||||
from roa2web.shared.auth import jwt_handler
|
||||
|
||||
# Create access token
|
||||
token = jwt_handler.create_access_token(
|
||||
username="admin",
|
||||
companies=["COMP1", "COMP2"],
|
||||
permissions=["read", "write", "reports"]
|
||||
)
|
||||
|
||||
# Verify token
|
||||
token_data = jwt_handler.verify_token(token)
|
||||
if token_data:
|
||||
print(f"Valid token for user: {token_data.username}")
|
||||
```
|
||||
|
||||
### Auth Service (`auth_service.py`)
|
||||
|
||||
Integrează cu Oracle Database pentru autentificare și management utilizatori.
|
||||
|
||||
```python
|
||||
from roa2web.shared.auth import auth_service
|
||||
|
||||
# Authenticate user
|
||||
success, token_response, error = await auth_service.authenticate_and_create_tokens(
|
||||
"username", "password"
|
||||
)
|
||||
|
||||
if success:
|
||||
print(f"Access token: {token_response.access_token}")
|
||||
else:
|
||||
print(f"Authentication failed: {error}")
|
||||
```
|
||||
|
||||
### FastAPI Dependencies (`dependencies.py`)
|
||||
|
||||
Oferă dependencies pentru protejarea endpoint-urilor.
|
||||
|
||||
```python
|
||||
from fastapi import Depends
|
||||
from roa2web.shared.auth import (
|
||||
get_current_user, require_company_access,
|
||||
require_permissions, PermissionType
|
||||
)
|
||||
|
||||
@app.get("/admin-only")
|
||||
async def admin_endpoint(
|
||||
user: CurrentUser = Depends(require_permissions([PermissionType.ADMIN]))
|
||||
):
|
||||
return {"message": "Admin access granted"}
|
||||
|
||||
@app.get("/company/{company_code}/data")
|
||||
async def company_data(
|
||||
company_code: str,
|
||||
user: CurrentUser = Depends(require_company_access(company_code))
|
||||
):
|
||||
return {"company": company_code, "data": "..."}
|
||||
```
|
||||
|
||||
### Authentication Routes (`routes.py`)
|
||||
|
||||
Pre-built routes pentru operații de autentificare.
|
||||
|
||||
```python
|
||||
from roa2web.shared.auth import create_auth_router
|
||||
|
||||
# Basic auth router
|
||||
auth_router = create_auth_router()
|
||||
app.include_router(auth_router)
|
||||
|
||||
# Auth router cu admin routes
|
||||
auth_router_admin = create_auth_router(include_admin_routes=True)
|
||||
app.include_router(auth_router_admin)
|
||||
```
|
||||
|
||||
Available routes:
|
||||
- `POST /auth/login` - User authentication
|
||||
- `POST /auth/refresh` - Token refresh
|
||||
- `POST /auth/logout` - User logout
|
||||
- `GET /auth/me` - Current user info
|
||||
- `GET /auth/companies` - User companies
|
||||
- `GET /auth/status` - Authentication status
|
||||
|
||||
## 🔧 Integration Guide
|
||||
|
||||
### Full FastAPI Application
|
||||
|
||||
```python
|
||||
from fastapi import FastAPI, Depends, HTTPException
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from contextlib import asynccontextmanager
|
||||
|
||||
from roa2web.shared.auth import (
|
||||
AuthenticationMiddleware, create_auth_router,
|
||||
get_current_user, require_company_access,
|
||||
CurrentUser, PermissionType
|
||||
)
|
||||
from roa2web.shared.database import oracle_pool
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI):
|
||||
# Startup
|
||||
await oracle_pool.initialize()
|
||||
yield
|
||||
# Shutdown
|
||||
await oracle_pool.close_pool()
|
||||
|
||||
app = FastAPI(
|
||||
title="ROA2WEB Application",
|
||||
lifespan=lifespan
|
||||
)
|
||||
|
||||
# CORS
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["http://localhost:3000"],
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
|
||||
# Authentication
|
||||
app.add_middleware(
|
||||
AuthenticationMiddleware,
|
||||
excluded_paths=["/", "/docs", "/health"],
|
||||
rate_limit_paths=["/auth/login"]
|
||||
)
|
||||
|
||||
# Routes
|
||||
auth_router = create_auth_router()
|
||||
app.include_router(auth_router)
|
||||
|
||||
# Protected endpoints
|
||||
@app.get("/")
|
||||
async def public_endpoint():
|
||||
return {"message": "Public endpoint"}
|
||||
|
||||
@app.get("/me")
|
||||
async def my_info(current_user: CurrentUser = Depends(get_current_user)):
|
||||
return current_user
|
||||
|
||||
@app.get("/company/{company_code}/invoices")
|
||||
async def get_invoices(
|
||||
company_code: str,
|
||||
current_user: CurrentUser = Depends(require_company_access(company_code))
|
||||
):
|
||||
# Business logic here
|
||||
return {"company": company_code, "invoices": []}
|
||||
```
|
||||
|
||||
### Custom Permissions
|
||||
|
||||
```python
|
||||
from roa2web.shared.auth import require_permissions, PermissionType
|
||||
|
||||
# Define custom permissions
|
||||
class CustomPermissionType(str, Enum):
|
||||
INVOICE_READ = "invoice_read"
|
||||
INVOICE_WRITE = "invoice_write"
|
||||
REPORT_EXPORT = "report_export"
|
||||
|
||||
# Use in endpoints
|
||||
@app.get("/invoices")
|
||||
async def get_invoices(
|
||||
user: CurrentUser = Depends(require_permissions([CustomPermissionType.INVOICE_READ]))
|
||||
):
|
||||
return {"invoices": []}
|
||||
```
|
||||
|
||||
### Company-Specific Endpoints
|
||||
|
||||
```python
|
||||
from fastapi import Header
|
||||
from roa2web.shared.auth import get_current_company_from_header
|
||||
|
||||
@app.get("/current-company-data")
|
||||
async def get_current_company_data(
|
||||
company_code: str = Depends(get_current_company_from_header),
|
||||
current_user: CurrentUser = Depends(get_current_user)
|
||||
):
|
||||
# company_code is automatically extracted from X-Company-Code header
|
||||
# and validated against user's accessible companies
|
||||
return {"company": company_code, "data": "..."}
|
||||
```
|
||||
|
||||
## 🔒 Security Features
|
||||
|
||||
### JWT Configuration
|
||||
|
||||
```python
|
||||
# Environment variables
|
||||
JWT_SECRET_KEY=your-super-secret-jwt-key-change-in-production
|
||||
JWT_ALGORITHM=HS256
|
||||
ACCESS_TOKEN_EXPIRE_MINUTES=30
|
||||
REFRESH_TOKEN_EXPIRE_DAYS=7
|
||||
```
|
||||
|
||||
### Rate Limiting
|
||||
|
||||
```python
|
||||
from roa2web.shared.auth import RateLimiter, AuthenticationMiddleware
|
||||
|
||||
# Custom rate limiter
|
||||
custom_rate_limiter = RateLimiter(
|
||||
max_requests=10, # 10 requests
|
||||
time_window=60 # per minute
|
||||
)
|
||||
|
||||
app.add_middleware(
|
||||
AuthenticationMiddleware,
|
||||
rate_limit_paths=["/auth/login", "/auth/register"],
|
||||
rate_limiter=custom_rate_limiter
|
||||
)
|
||||
```
|
||||
|
||||
### Security Headers
|
||||
|
||||
Middleware-ul adaugă automat header-e de securitate:
|
||||
|
||||
```
|
||||
X-Content-Type-Options: nosniff
|
||||
X-Frame-Options: DENY
|
||||
X-XSS-Protection: 1; mode=block
|
||||
```
|
||||
|
||||
## 📚 API Reference
|
||||
|
||||
### JWT Handler Methods
|
||||
|
||||
```python
|
||||
class JWTHandler:
|
||||
def create_access_token(username, companies, user_id=None, permissions=None) -> str
|
||||
def create_refresh_token(username, user_id=None) -> str
|
||||
def verify_token(token) -> Optional[TokenData]
|
||||
def refresh_access_token(refresh_token, companies, permissions=None) -> Optional[str]
|
||||
def create_token_response(username, companies, ...) -> TokenResponse
|
||||
```
|
||||
|
||||
### Auth Service Methods
|
||||
|
||||
```python
|
||||
class UserAuthService:
|
||||
async def verify_user_credentials(username, password) -> bool
|
||||
async def get_user_companies(username) -> List[str]
|
||||
async def get_user_permissions(username, company) -> List[str]
|
||||
async def authenticate_and_create_tokens(username, password) -> Tuple[bool, TokenResponse, str]
|
||||
async def validate_user_company_access(username, company) -> bool
|
||||
```
|
||||
|
||||
### FastAPI Dependencies
|
||||
|
||||
```python
|
||||
# User dependencies
|
||||
get_current_user() -> CurrentUser
|
||||
get_optional_user() -> Optional[CurrentUser]
|
||||
|
||||
# Permission dependencies
|
||||
require_permissions(permissions: List[PermissionType])
|
||||
require_company_access(company_code: str)
|
||||
require_company_and_permissions(company_code: str, permissions: List[PermissionType])
|
||||
|
||||
# Utility dependencies
|
||||
get_current_company_from_header() -> str
|
||||
```
|
||||
|
||||
## 🧪 Testing
|
||||
|
||||
### Running Tests
|
||||
|
||||
```bash
|
||||
# Install test dependencies
|
||||
pip install pytest pytest-asyncio httpx
|
||||
|
||||
# Run all tests
|
||||
cd roa2web/shared/auth
|
||||
python -m pytest test_auth.py -v
|
||||
|
||||
# Run specific test categories
|
||||
python -m pytest test_auth.py::TestJWTHandler -v
|
||||
python -m pytest test_auth.py::TestUserAuthService -v
|
||||
python -m pytest test_auth.py::TestSecurityFeatures -v
|
||||
|
||||
# Run with coverage
|
||||
python -m pytest test_auth.py --cov=. --cov-report=html
|
||||
```
|
||||
|
||||
### Test Categories
|
||||
|
||||
- **Unit Tests**: JWT operations, auth service methods
|
||||
- **Integration Tests**: Database integration, full auth flow
|
||||
- **Security Tests**: Token tampering, SQL injection, rate limiting
|
||||
- **Performance Tests**: Token creation/verification speed
|
||||
|
||||
### Demo Application
|
||||
|
||||
```bash
|
||||
# Start demo app for manual testing
|
||||
cd roa2web/shared/auth
|
||||
python demo_app.py
|
||||
|
||||
# Available demo endpoints:
|
||||
# http://localhost:8000/ - Home page cu documentație
|
||||
# http://localhost:8000/docs - Swagger UI pentru testare
|
||||
# http://localhost:8000/demo/* - Various demo endpoints
|
||||
```
|
||||
|
||||
## 🚀 Deployment
|
||||
|
||||
### Production Configuration
|
||||
|
||||
```bash
|
||||
# Strong JWT secret key
|
||||
JWT_SECRET_KEY=$(python -c "import secrets; print(secrets.token_urlsafe(32))")
|
||||
|
||||
# Shorter token expiration
|
||||
ACCESS_TOKEN_EXPIRE_MINUTES=15
|
||||
REFRESH_TOKEN_EXPIRE_DAYS=1
|
||||
|
||||
# Strict rate limiting
|
||||
RATE_LIMIT_MAX_REQUESTS=3
|
||||
RATE_LIMIT_TIME_WINDOW=300
|
||||
|
||||
# Secure headers
|
||||
SECURE_SSL_REDIRECT=true
|
||||
SESSION_COOKIE_SECURE=true
|
||||
```
|
||||
|
||||
### Docker Integration
|
||||
|
||||
```dockerfile
|
||||
# În Dockerfile-ul aplicației
|
||||
FROM python:3.11-slim
|
||||
|
||||
WORKDIR /app
|
||||
COPY requirements.txt .
|
||||
RUN pip install -r requirements.txt
|
||||
|
||||
COPY . .
|
||||
|
||||
# Environment pentru container
|
||||
ENV JWT_SECRET_KEY=${JWT_SECRET_KEY}
|
||||
ENV ORACLE_USER=${ORACLE_USER}
|
||||
ENV ORACLE_PASSWORD=${ORACLE_PASSWORD}
|
||||
ENV ORACLE_DSN=${ORACLE_DSN}
|
||||
|
||||
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
|
||||
```
|
||||
|
||||
### Health Checks
|
||||
|
||||
```python
|
||||
@app.get("/health")
|
||||
async def health_check():
|
||||
# Test database connection
|
||||
try:
|
||||
async with oracle_pool.get_connection() as conn:
|
||||
with conn.cursor() as cursor:
|
||||
cursor.execute("SELECT 1 FROM DUAL")
|
||||
db_status = "healthy"
|
||||
except Exception as e:
|
||||
db_status = f"error: {str(e)}"
|
||||
|
||||
return {
|
||||
"status": "healthy" if db_status == "healthy" else "degraded",
|
||||
"database": db_status,
|
||||
"jwt": "functional",
|
||||
"timestamp": datetime.now().isoformat()
|
||||
}
|
||||
```
|
||||
|
||||
## 🔧 Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
#### 1. "Invalid token" errors
|
||||
|
||||
```python
|
||||
# Check JWT secret key consistency
|
||||
print(f"JWT Secret: {os.getenv('JWT_SECRET_KEY')}")
|
||||
|
||||
# Verify token creation and validation
|
||||
token = jwt_handler.create_access_token("test", ["COMP1"])
|
||||
token_data = jwt_handler.verify_token(token)
|
||||
print(f"Token valid: {token_data is not None}")
|
||||
```
|
||||
|
||||
#### 2. Database connection errors
|
||||
|
||||
```python
|
||||
# Test Oracle connection
|
||||
try:
|
||||
async with oracle_pool.get_connection() as conn:
|
||||
with conn.cursor() as cursor:
|
||||
cursor.execute("SELECT 1 FROM DUAL")
|
||||
result = cursor.fetchone()
|
||||
print("Database connection: OK")
|
||||
except Exception as e:
|
||||
print(f"Database error: {e}")
|
||||
```
|
||||
|
||||
#### 3. Rate limiting issues
|
||||
|
||||
```python
|
||||
# Check rate limiter stats
|
||||
from roa2web.shared.auth import default_rate_limiter
|
||||
|
||||
client_ip = "192.168.1.1"
|
||||
allowed = default_rate_limiter.is_allowed(client_ip)
|
||||
reset_time = default_rate_limiter.get_reset_time(client_ip)
|
||||
print(f"IP {client_ip} allowed: {allowed}, resets at: {reset_time}")
|
||||
```
|
||||
|
||||
#### 4. Permission denied errors
|
||||
|
||||
```python
|
||||
# Check user companies and permissions
|
||||
companies = await auth_service.get_user_companies("username")
|
||||
permissions = await auth_service.get_user_permissions("username", "COMP1")
|
||||
print(f"User companies: {companies}")
|
||||
print(f"User permissions: {permissions}")
|
||||
```
|
||||
|
||||
### Debug Mode
|
||||
|
||||
```python
|
||||
import logging
|
||||
|
||||
# Enable debug logging
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
|
||||
# Specific loggers
|
||||
logging.getLogger("roa2web.shared.auth").setLevel(logging.DEBUG)
|
||||
```
|
||||
|
||||
### Environment Validation
|
||||
|
||||
```python
|
||||
from roa2web.shared.utils.config import shared_config
|
||||
|
||||
# Validate configuration
|
||||
print(f"Oracle User: {shared_config.oracle_user}")
|
||||
print(f"JWT Secret set: {'***' if shared_config.jwt_secret_key else 'NOT SET'}")
|
||||
print(f"Token expiry: {shared_config.access_token_expire_minutes} minutes")
|
||||
```
|
||||
|
||||
## 📈 Performance Optimization
|
||||
|
||||
### Caching
|
||||
|
||||
```python
|
||||
# Cache configuration
|
||||
AUTH_CACHE_TTL_MINUTES=15 # User data cache TTL
|
||||
|
||||
# Monitor cache performance
|
||||
stats = auth_service.get_cache_stats()
|
||||
print(f"Cache hit ratio: {stats['cache_hit_ratio']:.2%}")
|
||||
```
|
||||
|
||||
### Connection Pooling
|
||||
|
||||
```python
|
||||
# Oracle pool configuration
|
||||
DB_MIN_CONNECTIONS=2
|
||||
DB_MAX_CONNECTIONS=10
|
||||
DB_CONNECTION_INCREMENT=1
|
||||
```
|
||||
|
||||
### Token Optimization
|
||||
|
||||
```python
|
||||
# Optimize token size by limiting payload
|
||||
token = jwt_handler.create_access_token(
|
||||
username="user",
|
||||
companies=["COMP1"], # Limit companies in token
|
||||
permissions=["read"] # Essential permissions only
|
||||
)
|
||||
```
|
||||
|
||||
## 🤝 Contributing
|
||||
|
||||
Pentru contribuții la sistemul de autentificare:
|
||||
|
||||
1. **Fork repository-ul** și creează o ramură pentru feature
|
||||
2. **Implementează schimbările** cu tests comprehensive
|
||||
3. **Rulează toate testele** pentru a verifica compatibilitatea
|
||||
4. **Actualizează documentația** dacă este necesar
|
||||
5. **Creează Pull Request** cu descriere detaliată
|
||||
|
||||
### Development Setup
|
||||
|
||||
```bash
|
||||
# Clone repository
|
||||
git clone [repository-url]
|
||||
cd roa-flask
|
||||
|
||||
# Setup environment
|
||||
python -m venv venv
|
||||
source venv/bin/activate # Linux/Mac
|
||||
# or
|
||||
venv\Scripts\activate # Windows
|
||||
|
||||
pip install -r requirements.txt
|
||||
|
||||
# Run tests
|
||||
cd roa2web/shared/auth
|
||||
python -m pytest test_auth.py -v
|
||||
```
|
||||
|
||||
## 📜 License
|
||||
|
||||
Acest sistem de autentificare face parte din proiectul ROA2WEB și este disponibil sub aceleași condiții de licențiere ca și proiectul principal.
|
||||
|
||||
---
|
||||
|
||||
**ROA2WEB Authentication System v1.0.0**
|
||||
*Secure, scalable, Oracle-integrated authentication pentru aplicații moderne*
|
||||
Reference in New Issue
Block a user