feat(auth): implement auto guest mode and enhance token system

- Add role-based token system with metadata support
- Implement automatic guest mode for unconfigured authentication
- Create new /auth-status endpoint for authentication status checking
- Modify frontend to auto-detect auth status and bypass login when appropriate
- Add guest mode indicator in site header for better UX

This change allows users to automatically access the system without manual
login when authentication is not configured, while maintaining secure
authentication when credentials are properly set up.
This commit is contained in:
yangdx
2025-03-18 02:56:02 +08:00
parent 056b58af75
commit f8440c8f80
11 changed files with 460 additions and 45 deletions

View File

@@ -6,8 +6,10 @@ from pydantic import BaseModel
class TokenPayload(BaseModel):
sub: str
exp: datetime
sub: str # Username
exp: datetime # Expiration time
role: str = "user" # User role, default is regular user
metadata: dict = {} # Additional metadata
class AuthHandler:
@@ -15,13 +17,55 @@ class AuthHandler:
self.secret = os.getenv("TOKEN_SECRET", "4f85ds4f56dsf46")
self.algorithm = "HS256"
self.expire_hours = int(os.getenv("TOKEN_EXPIRE_HOURS", 4))
self.guest_expire_hours = int(os.getenv("GUEST_TOKEN_EXPIRE_HOURS", 2)) # Guest token default expiration time
def create_token(self, username: str) -> str:
expire = datetime.utcnow() + timedelta(hours=self.expire_hours)
payload = TokenPayload(sub=username, exp=expire)
def create_token(self, username: str, role: str = "user", custom_expire_hours: int = None, metadata: dict = None) -> str:
"""
Create JWT token
Args:
username: Username
role: User role, default is "user", guest is "guest"
custom_expire_hours: Custom expiration time (hours), if None use default value
metadata: Additional metadata
Returns:
str: Encoded JWT token
"""
# Choose default expiration time based on role
if custom_expire_hours is None:
if role == "guest":
expire_hours = self.guest_expire_hours
else:
expire_hours = self.expire_hours
else:
expire_hours = custom_expire_hours
expire = datetime.utcnow() + timedelta(hours=expire_hours)
# Create payload
payload = TokenPayload(
sub=username,
exp=expire,
role=role,
metadata=metadata or {}
)
return jwt.encode(payload.dict(), self.secret, algorithm=self.algorithm)
def validate_token(self, token: str) -> str:
def validate_token(self, token: str) -> dict:
"""
Validate JWT token
Args:
token: JWT token
Returns:
dict: Dictionary containing user information
Raises:
HTTPException: If token is invalid or expired
"""
try:
payload = jwt.decode(token, self.secret, algorithms=[self.algorithm])
expire_timestamp = payload["exp"]
@@ -31,7 +75,14 @@ class AuthHandler:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED, detail="Token expired"
)
return payload["sub"]
# Return complete payload instead of just username
return {
"username": payload["sub"],
"role": payload.get("role", "user"),
"metadata": payload.get("metadata", {}),
"exp": expire_time
}
except jwt.PyJWTError:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token"