fixes
This commit is contained in:
parent
7e5e390eb0
commit
f54ead4334
|
|
@ -0,0 +1,31 @@
|
||||||
|
# Сервер
|
||||||
|
SERVER_IP=192.168.1.8
|
||||||
|
# Для домена замените на:
|
||||||
|
# SERVER_IP=yourdomain.com
|
||||||
|
# FRONTEND_URL=https://yourdomain.com
|
||||||
|
# BACKEND_URL=https://api.yourdomain.com
|
||||||
|
|
||||||
|
# Порты
|
||||||
|
FRONTEND_PORT=8095
|
||||||
|
BACKEND_PORT=8094
|
||||||
|
MINIO_API_PORT=9090
|
||||||
|
MINIO_CONSOLE_PORT=9091
|
||||||
|
REDIS_PORT=6388
|
||||||
|
|
||||||
|
# S3 Storage
|
||||||
|
S3_DATA_PATH=/mnt/data/s3
|
||||||
|
|
||||||
|
# Безопасность (ОБЯЗАТЕЛЬНО ПОМЕНЯЙТЕ В PRODUCTION!)
|
||||||
|
JWT_SECRET=dev-secret-key-change-in-production
|
||||||
|
MINIO_ROOT_USER=minioadmin
|
||||||
|
MINIO_ROOT_PASSWORD=minioadmin
|
||||||
|
|
||||||
|
# CORS Origins (добавьте свой домен)
|
||||||
|
# Для production:
|
||||||
|
# CORS_ORIGINS=https://yourdomain.com,https://www.yourdomain.com
|
||||||
|
CORS_ORIGINS=http://${SERVER_IP}:${FRONTEND_PORT},http://localhost:${FRONTEND_PORT}
|
||||||
|
|
||||||
|
# API URL для frontend
|
||||||
|
# Для production:
|
||||||
|
# VITE_API_URL=https://api.yourdomain.com
|
||||||
|
VITE_API_URL=http://${SERVER_IP}:${BACKEND_PORT}
|
||||||
|
|
@ -0,0 +1,95 @@
|
||||||
|
# Инструкция по развертыванию
|
||||||
|
|
||||||
|
## Текущая конфигурация (разработка)
|
||||||
|
|
||||||
|
Сейчас проект настроен для локальной сети на IP `192.168.1.8`:
|
||||||
|
- Frontend: http://192.168.1.8:8095
|
||||||
|
- Backend: http://192.168.1.8:8094
|
||||||
|
- MinIO Console: http://192.168.1.8:9091
|
||||||
|
|
||||||
|
## Переход на домен (production)
|
||||||
|
|
||||||
|
Когда будете ставить на домен, просто отредактируйте файл `.env`:
|
||||||
|
|
||||||
|
### Вариант 1: Домен без поддомена
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# .env
|
||||||
|
SERVER_IP=yourdomain.com
|
||||||
|
CORS_ORIGINS=https://yourdomain.com,https://www.yourdomain.com
|
||||||
|
VITE_API_URL=https://yourdomain.com:8094
|
||||||
|
|
||||||
|
# Рекомендуется сменить порты на стандартные через nginx:
|
||||||
|
# FRONTEND_PORT=80 (или 443 для HTTPS)
|
||||||
|
# BACKEND_PORT=8080 (скрыть за nginx reverse proxy)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Вариант 2: С поддоменом для API (рекомендуется)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# .env
|
||||||
|
SERVER_IP=yourdomain.com
|
||||||
|
CORS_ORIGINS=https://yourdomain.com,https://www.yourdomain.com,https://api.yourdomain.com
|
||||||
|
VITE_API_URL=https://api.yourdomain.com
|
||||||
|
|
||||||
|
# Настроить nginx reverse proxy:
|
||||||
|
# yourdomain.com -> frontend:8095
|
||||||
|
# api.yourdomain.com -> backend:8094
|
||||||
|
```
|
||||||
|
|
||||||
|
### Обязательно измените в production:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
JWT_SECRET=ваш-очень-длинный-случайный-секретный-ключ
|
||||||
|
MINIO_ROOT_USER=ваш-логин
|
||||||
|
MINIO_ROOT_PASSWORD=ваш-сильный-пароль
|
||||||
|
```
|
||||||
|
|
||||||
|
## Настройка HTTPS (nginx + Let's Encrypt)
|
||||||
|
|
||||||
|
Создайте `nginx.conf`:
|
||||||
|
|
||||||
|
```nginx
|
||||||
|
# Frontend
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name yourdomain.com www.yourdomain.com;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://localhost:8095;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Backend API
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name api.yourdomain.com;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://localhost:8094;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Затем установите SSL сертификаты:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com -d api.yourdomain.com
|
||||||
|
```
|
||||||
|
|
||||||
|
## Быстрая смена конфигурации
|
||||||
|
|
||||||
|
1. Отредактируйте `.env`
|
||||||
|
2. Перезапустите контейнеры:
|
||||||
|
```bash
|
||||||
|
docker-compose down
|
||||||
|
docker-compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
Готово! 🚀
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
"""Security utilities for authentication and authorization."""
|
"""Security utilities for authentication and authorization."""
|
||||||
|
|
||||||
from datetime import datetime, timedelta
|
import hashlib
|
||||||
|
from datetime import datetime, timedelta, timezone
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from jose import JWTError, jwt
|
from jose import JWTError, jwt
|
||||||
|
|
@ -16,15 +17,22 @@ pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
|
||||||
|
|
||||||
def hash_password(password: str) -> str:
|
def hash_password(password: str) -> str:
|
||||||
"""
|
"""
|
||||||
Hash a password using bcrypt.
|
Hash a password using bcrypt with SHA256 pre-hashing.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
password: Plain text password
|
password: Plain text password (any length supported)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Hashed password
|
Hashed password
|
||||||
|
|
||||||
|
Note:
|
||||||
|
Uses SHA256 pre-hashing to support passwords of any length,
|
||||||
|
avoiding bcrypt's 72-byte limitation.
|
||||||
"""
|
"""
|
||||||
return pwd_context.hash(password)
|
# Pre-hash with SHA256 to support unlimited password length
|
||||||
|
# This is a common technique to work around bcrypt's 72-byte limit
|
||||||
|
password_hash = hashlib.sha256(password.encode('utf-8')).hexdigest()
|
||||||
|
return pwd_context.hash(password_hash)
|
||||||
|
|
||||||
|
|
||||||
def verify_password(plain_password: str, hashed_password: str) -> bool:
|
def verify_password(plain_password: str, hashed_password: str) -> bool:
|
||||||
|
|
@ -38,7 +46,9 @@ def verify_password(plain_password: str, hashed_password: str) -> bool:
|
||||||
Returns:
|
Returns:
|
||||||
True if password matches, False otherwise
|
True if password matches, False otherwise
|
||||||
"""
|
"""
|
||||||
return pwd_context.verify(plain_password, hashed_password)
|
# Apply same SHA256 pre-hashing as hash_password
|
||||||
|
password_hash = hashlib.sha256(plain_password.encode('utf-8')).hexdigest()
|
||||||
|
return pwd_context.verify(password_hash, hashed_password)
|
||||||
|
|
||||||
|
|
||||||
def create_access_token(data: dict, expires_delta: Optional[timedelta] = None) -> str:
|
def create_access_token(data: dict, expires_delta: Optional[timedelta] = None) -> str:
|
||||||
|
|
@ -54,9 +64,9 @@ def create_access_token(data: dict, expires_delta: Optional[timedelta] = None) -
|
||||||
"""
|
"""
|
||||||
to_encode = data.copy()
|
to_encode = data.copy()
|
||||||
if expires_delta:
|
if expires_delta:
|
||||||
expire = datetime.utcnow() + expires_delta
|
expire = datetime.now(timezone.utc) + expires_delta
|
||||||
else:
|
else:
|
||||||
expire = datetime.utcnow() + timedelta(seconds=settings.jwt_access_ttl_seconds)
|
expire = datetime.now(timezone.utc) + timedelta(seconds=settings.jwt_access_ttl_seconds)
|
||||||
|
|
||||||
to_encode.update({"exp": expire, "type": "access"})
|
to_encode.update({"exp": expire, "type": "access"})
|
||||||
encoded_jwt = jwt.encode(to_encode, settings.jwt_secret, algorithm=settings.jwt_algorithm)
|
encoded_jwt = jwt.encode(to_encode, settings.jwt_secret, algorithm=settings.jwt_algorithm)
|
||||||
|
|
@ -74,7 +84,7 @@ def create_refresh_token(data: dict) -> str:
|
||||||
Encoded JWT token
|
Encoded JWT token
|
||||||
"""
|
"""
|
||||||
to_encode = data.copy()
|
to_encode = data.copy()
|
||||||
expire = datetime.utcnow() + timedelta(seconds=settings.jwt_refresh_ttl_seconds)
|
expire = datetime.now(timezone.utc) + timedelta(seconds=settings.jwt_refresh_ttl_seconds)
|
||||||
to_encode.update({"exp": expire, "type": "refresh"})
|
to_encode.update({"exp": expire, "type": "refresh"})
|
||||||
encoded_jwt = jwt.encode(to_encode, settings.jwt_secret, algorithm=settings.jwt_algorithm)
|
encoded_jwt = jwt.encode(to_encode, settings.jwt_secret, algorithm=settings.jwt_algorithm)
|
||||||
return encoded_jwt
|
return encoded_jwt
|
||||||
|
|
|
||||||
|
|
@ -4,17 +4,17 @@ services:
|
||||||
backend:
|
backend:
|
||||||
build: ./backend
|
build: ./backend
|
||||||
ports:
|
ports:
|
||||||
- "8094:8000"
|
- "${BACKEND_PORT:-8094}:8000"
|
||||||
environment:
|
environment:
|
||||||
- APP_ENV=dev
|
- APP_ENV=dev
|
||||||
- DATABASE_URL=sqlite+aiosqlite:////app/data/app.db
|
- DATABASE_URL=sqlite+aiosqlite:////app/data/app.db
|
||||||
- S3_ENDPOINT_URL=http://minio:9000
|
- S3_ENDPOINT_URL=http://minio:9000
|
||||||
- S3_REGION=us-east-1
|
- S3_REGION=us-east-1
|
||||||
- S3_ACCESS_KEY_ID=minioadmin
|
- S3_ACCESS_KEY_ID=${MINIO_ROOT_USER:-minioadmin}
|
||||||
- S3_SECRET_ACCESS_KEY=minioadmin
|
- S3_SECRET_ACCESS_KEY=${MINIO_ROOT_PASSWORD:-minioadmin}
|
||||||
- MEDIA_BUCKET=itcloud-media
|
- MEDIA_BUCKET=itcloud-media
|
||||||
- JWT_SECRET=dev-secret-key-change-in-production
|
- JWT_SECRET=${JWT_SECRET:-dev-secret-key-change-in-production}
|
||||||
- CORS_ORIGINS=http://192.168.1.8:8095,http://localhost:8095,http://localhost:3000
|
- CORS_ORIGINS=${CORS_ORIGINS}
|
||||||
- REDIS_URL=redis://redis:6379/0
|
- REDIS_URL=redis://redis:6379/0
|
||||||
volumes:
|
volumes:
|
||||||
- ./backend/src:/app/src
|
- ./backend/src:/app/src
|
||||||
|
|
@ -27,13 +27,13 @@ services:
|
||||||
minio:
|
minio:
|
||||||
image: minio/minio:latest
|
image: minio/minio:latest
|
||||||
ports:
|
ports:
|
||||||
- "9090:9000"
|
- "${MINIO_API_PORT:-9090}:9000"
|
||||||
- "9091:9001"
|
- "${MINIO_CONSOLE_PORT:-9091}:9001"
|
||||||
environment:
|
environment:
|
||||||
- MINIO_ROOT_USER=minioadmin
|
- MINIO_ROOT_USER=${MINIO_ROOT_USER:-minioadmin}
|
||||||
- MINIO_ROOT_PASSWORD=minioadmin
|
- MINIO_ROOT_PASSWORD=${MINIO_ROOT_PASSWORD:-minioadmin}
|
||||||
volumes:
|
volumes:
|
||||||
- /mnt/data/s3:/data
|
- ${S3_DATA_PATH:-/mnt/data/s3}:/data
|
||||||
command: server /data --console-address ":9001"
|
command: server /data --console-address ":9001"
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
|
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
|
||||||
|
|
@ -57,7 +57,7 @@ services:
|
||||||
redis:
|
redis:
|
||||||
image: redis:7-alpine
|
image: redis:7-alpine
|
||||||
ports:
|
ports:
|
||||||
- "6388:6379"
|
- "${REDIS_PORT:-6388}:6379"
|
||||||
volumes:
|
volumes:
|
||||||
- redis-data:/data
|
- redis-data:/data
|
||||||
healthcheck:
|
healthcheck:
|
||||||
|
|
@ -69,9 +69,9 @@ services:
|
||||||
frontend:
|
frontend:
|
||||||
build: ./frontend
|
build: ./frontend
|
||||||
ports:
|
ports:
|
||||||
- "8095:5173"
|
- "${FRONTEND_PORT:-8095}:5173"
|
||||||
environment:
|
environment:
|
||||||
- VITE_API_URL=http://192.168.1.8:8094
|
- VITE_API_URL=${VITE_API_URL}
|
||||||
volumes:
|
volumes:
|
||||||
- ./frontend/src:/app/src
|
- ./frontend/src:/app/src
|
||||||
- ./frontend/public:/app/public
|
- ./frontend/public:/app/public
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue