ws ticket
Build and Push Docker Image / build-and-push (push) Successful in 14s

This commit is contained in:
ciomek committed 2026-08-17 22:19:02 +02:00
1 parent a603566235
commit 7280c5dd07
5 files changed
+66 -10

No files matched your search

+24
View File
@@ -0,0 +1,24 @@
.git/
.gitea/
.gitignore
.venv/
__pycache__/
.pytest_cache/
.mypy_cache/
.ruff_cache/
.uv/
*.py[cod]
*.pyo
*.log
.env
.env.*
.secrets.toml
db.sqlite3
Dockerfile
docker-compose*.yml
README.md
+10 -3
View File
@@ -34,9 +34,9 @@ class JWTAuthBackend(AuthenticationBackend):
if scheme.lower() == "bearer" and credentials: if scheme.lower() == "bearer" and credentials:
return credentials return credentials
# Browser WebSocket APIs cannot set Authorization headers. if conn.scope["type"] == "websocket":
token = conn.query_params.get("token") return conn.query_params.get("token") or None
return token or None return None
async def authenticate( async def authenticate(
self, conn: HTTPConnection self, conn: HTTPConnection
@@ -54,6 +54,13 @@ class JWTAuthBackend(AuthenticationBackend):
if not isinstance(user_id, int): if not isinstance(user_id, int):
raise AuthenticationError("Invalid or expired token") raise AuthenticationError("Invalid or expired token")
typ = payload.get("typ")
if conn.scope["type"] == "websocket":
if typ != "ws":
raise AuthenticationError("Invalid or expired token")
elif typ != "web":
raise AuthenticationError("Invalid or expired token")
with Session(engine) as session: with Session(engine) as session:
user = session.exec(select(User).where(User.id == user_id)).first() user = session.exec(select(User).where(User.id == user_id)).first()
+15 -3
View File
@@ -2,10 +2,11 @@ from fastapi import APIRouter, HTTPException, Request, status
from sqlmodel import Session, select from sqlmodel import Session, select
from loon.web import limiter from loon.web import limiter
from loon.web.auth.middleware import authenticated
from loon.web.auth.schema import JWTResponse, JWTRequest from loon.web.auth.schema import JWTResponse, JWTRequest
from loon.web.db import engine from loon.web.db import engine
from loon.web.users.models import User from loon.web.users.models import User
from loon.web.utils.jwt import generate_token from loon.web.utils.jwt import generate_token, generate_ws_token
from loon.web.utils.password import verify_password from loon.web.utils.password import verify_password
router = APIRouter(prefix="/auth", tags=["auth"]) router = APIRouter(prefix="/auth", tags=["auth"])
@@ -18,11 +19,22 @@ async def get_jwt(request: Request, body: JWTRequest) -> JWTResponse:
statement = select(User).where(User.internal_username == body.username) statement = select(User).where(User.internal_username == body.username)
user = session.exec(statement).first() user = session.exec(statement).first()
if user is None or not verify_password(body.password, user.password): if user is None or user.id is None or not verify_password(body.password, user.password):
raise HTTPException( raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED, status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid username or password", detail="Invalid username or password",
) )
assert user.id is not None
return JWTResponse(access_token=generate_token(user.id)) return JWTResponse(access_token=generate_token(user.id))
@router.post("/ws-token", response_model=JWTResponse)
@authenticated
async def get_ws_token(request: Request) -> JWTResponse:
user_id = request.user.user.id
if user_id is None:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid or expired token",
)
return JWTResponse(access_token=generate_ws_token(user_id))
+14 -3
View File
@@ -1,4 +1,5 @@
import time import time
from typing import Literal
import jwt import jwt
@@ -8,13 +9,23 @@ JWT_SECRET = settings.jwt.secret
JWT_ALGORITHM = "HS256" JWT_ALGORITHM = "HS256"
def generate_token(user_id: int) -> str: def _encode_jwt(user_id: int, ttl: int, typ: Literal["ws", "web"]) -> str:
payload = { payload = {
"user_id": user_id, "user_id": user_id,
"exp": int(time.time()) + 60 * 60 * 24, "exp": int(time.time()) + ttl,
"typ": typ,
} }
return jwt.encode(payload, JWT_SECRET, algorithm=JWT_ALGORITHM) return jwt.encode(payload, JWT_SECRET, algorithm=JWT_ALGORITHM)
def generate_token(user_id: int) -> str:
return _encode_jwt(user_id, settings.jwt.access_ttl, "web")
def generate_ws_token(user_id: int) -> str:
return _encode_jwt(user_id, settings.jwt.ws_ttl, "ws")
def decode_token(token: str) -> dict: def decode_token(token: str) -> dict:
payload = jwt.decode(token, JWT_SECRET) payload = jwt.decode(token, JWT_SECRET)
return payload return payload
+3 -1
View File
@@ -23,4 +23,6 @@ password = 'pwd'
log_data = false log_data = false
[jwt] [jwt]
secret = 'secret' secret = 'secret'
access_ttl = 86400 # 24h
ws_ttl = 45