mirror of
https://github.com/langgenius/dify.git
synced 2026-05-09 04:36:31 +08:00
feat(openapi): cookie auth for device-flow approval routes
Adds the openapi blueprint branch in load_user_from_request so that account-branch device-flow approval routes (approve / deny / approval-context) can authenticate via the console session cookie under @login_required. Splits extract_access_token into two helpers: - extract_console_cookie_token (cookie-only) — used by openapi approval routes that must not fall through to the Authorization header, where dfoa_/dfoe_ bearers live (those aren't JWTs and PassportService.verify would crash on them). - extract_access_token retains both code paths for legacy callers.
This commit is contained in:
parent
cf5ebe9430
commit
9b2a37ceff
@ -12,7 +12,7 @@ from constants import HEADER_NAME_APP_CODE
|
||||
from dify_app import DifyApp
|
||||
from extensions.ext_database import db
|
||||
from libs.passport import PassportService
|
||||
from libs.token import extract_access_token, extract_webapp_passport
|
||||
from libs.token import extract_access_token, extract_console_cookie_token, extract_webapp_passport
|
||||
from models import Account, Tenant, TenantAccountJoin
|
||||
from models.model import AppMCPServer, EndUser
|
||||
from services.account_service import AccountService
|
||||
@ -84,6 +84,24 @@ def load_user_from_request(request_from_flask_login: Request) -> LoginUser | Non
|
||||
|
||||
logged_in_account = AccountService.load_logged_in_account(account_id=user_id)
|
||||
return logged_in_account
|
||||
elif request.blueprint == "openapi":
|
||||
# Account-branch device-flow approval routes (approve / deny /
|
||||
# approval-context) sit under @login_required and authenticate via
|
||||
# the console session cookie. Cookie-only on purpose — bearer
|
||||
# tokens (dfoa_/dfoe_) live on the Authorization header and are
|
||||
# validated by AppPipeline, not flask-login.
|
||||
cookie_token = extract_console_cookie_token(request)
|
||||
if not cookie_token:
|
||||
return None
|
||||
try:
|
||||
decoded = PassportService().verify(cookie_token)
|
||||
except Exception:
|
||||
return None
|
||||
user_id = decoded.get("user_id")
|
||||
source = decoded.get("token_source")
|
||||
if source or not user_id:
|
||||
return None
|
||||
return AccountService.load_logged_in_account(account_id=user_id)
|
||||
elif request.blueprint == "web":
|
||||
app_code = request.headers.get(HEADER_NAME_APP_CODE)
|
||||
webapp_token = extract_webapp_passport(app_code, request) if app_code else None
|
||||
|
||||
@ -72,11 +72,15 @@ def extract_csrf_token_from_cookie(request: Request) -> str | None:
|
||||
return request.cookies.get(_real_cookie_name(COOKIE_NAME_CSRF_TOKEN))
|
||||
|
||||
|
||||
def extract_access_token(request: Request) -> str | None:
|
||||
def _try_extract_from_cookie(request: Request) -> str | None:
|
||||
return request.cookies.get(_real_cookie_name(COOKIE_NAME_ACCESS_TOKEN))
|
||||
def extract_console_cookie_token(request: Request) -> str | None:
|
||||
"""Cookie-only console session token. Used by /openapi/v1/oauth/device/*
|
||||
approval routes, which must not fall through to the Authorization header
|
||||
(that's where dfoa_/dfoe_ bearers live — they aren't JWTs)."""
|
||||
return request.cookies.get(_real_cookie_name(COOKIE_NAME_ACCESS_TOKEN))
|
||||
|
||||
return _try_extract_from_cookie(request) or _try_extract_from_header(request)
|
||||
|
||||
def extract_access_token(request: Request) -> str | None:
|
||||
return extract_console_cookie_token(request) or _try_extract_from_header(request)
|
||||
|
||||
|
||||
def extract_webapp_access_token(request: Request) -> str | None:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user