浏览代码

enh: cookie auth

Timothy J. Baek 10 月之前
父节点
当前提交
b36c525ebc

+ 18 - 1
backend/apps/webui/routers/auths.py

@@ -2,6 +2,7 @@ import logging
 
 from fastapi import Request, UploadFile, File
 from fastapi import Depends, HTTPException, status
+from fastapi.responses import Response
 
 from fastapi import APIRouter
 from pydantic import BaseModel
@@ -47,7 +48,23 @@ router = APIRouter()
 
 
 @router.get("/", response_model=UserResponse)
-async def get_session_user(user=Depends(get_current_user)):
+async def get_session_user(
+    request: Request, response: Response, user=Depends(get_current_user)
+):
+    token = create_token(
+        data={"id": user.id},
+        expires_delta=parse_duration(request.app.state.config.JWT_EXPIRES_IN),
+    )
+
+    # Set the cookie token
+    response.set_cookie(
+        key="token",
+        value=token,
+        httponly=True,  # Ensures the cookie is not accessible via JavaScript
+        secure=True,  # Ensures the cookie is sent over https
+        samesite="lax",
+    )
+
     return {
         "id": user.id,
         "email": user.email,

+ 17 - 5
backend/utils/utils.py

@@ -1,5 +1,5 @@
 from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
-from fastapi import HTTPException, status, Depends
+from fastapi import HTTPException, status, Depends, Request
 
 from apps.webui.models.users import Users
 
@@ -24,7 +24,8 @@ ALGORITHM = "HS256"
 # Auth Utils
 ##############
 
-bearer_security = HTTPBearer()
+bearer_security = HTTPBearer(auto_error=False)
+
 pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
 
 
@@ -75,13 +76,24 @@ def get_http_authorization_cred(auth_header: str):
 
 
 def get_current_user(
+    request: Request,
     auth_token: HTTPAuthorizationCredentials = Depends(bearer_security),
 ):
+    # get token from cookie
+    token = request.cookies.get("token")
+
+    if auth_token is None and token is None:
+        raise HTTPException(status_code=403, detail="Not authenticated")
+
+    if auth_token is not None:
+        token = auth_token.credentials
+
     # auth by api key
-    if auth_token.credentials.startswith("sk-"):
-        return get_current_user_by_api_key(auth_token.credentials)
+    if token.startswith("sk-"):
+        return get_current_user_by_api_key(token)
+
     # auth by jwt token
-    data = decode_token(auth_token.credentials)
+    data = decode_token(token)
     if data != None and "id" in data:
         user = Users.get_user_by_id(data["id"])
         if user is None:

+ 2 - 1
src/lib/apis/auths/index.ts

@@ -90,7 +90,8 @@ export const getSessionUser = async (token: string) => {
 		headers: {
 			'Content-Type': 'application/json',
 			Authorization: `Bearer ${token}`
-		}
+		},
+		credentials: 'include'
 	})
 		.then(async (res) => {
 			if (!res.ok) throw await res.json();

+ 4 - 4
src/lib/apis/files/index.ts

@@ -92,15 +92,15 @@ export const getFileById = async (token: string, id: string) => {
 	return res;
 };
 
-export const getFileContentById = async (token: string, id: string) => {
+export const getFileContentById = async (id: string) => {
 	let error = null;
 
 	const res = await fetch(`${WEBUI_API_BASE_URL}/files/${id}/content`, {
 		method: 'GET',
 		headers: {
-			Accept: 'application/json',
-			authorization: `Bearer ${token}`
-		}
+			Accept: 'application/json'
+		},
+		credentials: 'include'
 	})
 		.then(async (res) => {
 			if (!res.ok) throw await res.json();

+ 1 - 1
src/lib/components/chat/Messages/UserMessage.svelte

@@ -104,7 +104,7 @@
 									type="button"
 									on:click={async () => {
 										if (file?.url) {
-											getFileContentById(localStorage.token, file.id).then((blob) => {
+											getFileContentById(file.id).then((blob) => {
 												if (blob) {
 													const url = URL.createObjectURL(blob);
 													window.open(url, '_blank').focus();