Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

login.py 4.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. from functools import wraps
  2. from typing import Any
  3. from flask import current_app, g, has_request_context, request
  4. from flask_login import user_logged_in # type: ignore
  5. from flask_login.config import EXEMPT_METHODS # type: ignore
  6. from werkzeug.exceptions import Unauthorized
  7. from werkzeug.local import LocalProxy
  8. from configs import dify_config
  9. from extensions.ext_database import db
  10. from models.account import Account, Tenant, TenantAccountJoin
  11. from models.model import EndUser
  12. #: A proxy for the current user. If no user is logged in, this will be an
  13. #: anonymous user
  14. current_user: Any = LocalProxy(lambda: _get_user())
  15. def login_required(func):
  16. """
  17. If you decorate a view with this, it will ensure that the current user is
  18. logged in and authenticated before calling the actual view. (If they are
  19. not, it calls the :attr:`LoginManager.unauthorized` callback.) For
  20. example::
  21. @app.route('/post')
  22. @login_required
  23. def post():
  24. pass
  25. If there are only certain times you need to require that your user is
  26. logged in, you can do so with::
  27. if not current_user.is_authenticated:
  28. return current_app.login_manager.unauthorized()
  29. ...which is essentially the code that this function adds to your views.
  30. It can be convenient to globally turn off authentication when unit testing.
  31. To enable this, if the application configuration variable `LOGIN_DISABLED`
  32. is set to `True`, this decorator will be ignored.
  33. .. Note ::
  34. Per `W3 guidelines for CORS preflight requests
  35. <http://www.w3.org/TR/cors/#cross-origin-request-with-preflight-0>`_,
  36. HTTP ``OPTIONS`` requests are exempt from login checks.
  37. :param func: The view function to decorate.
  38. :type func: function
  39. """
  40. @wraps(func)
  41. def decorated_view(*args, **kwargs):
  42. auth_header = request.headers.get("Authorization")
  43. if dify_config.ADMIN_API_KEY_ENABLE:
  44. if auth_header:
  45. if " " not in auth_header:
  46. raise Unauthorized("Invalid Authorization header format. Expected 'Bearer <api-key>' format.")
  47. auth_scheme, auth_token = auth_header.split(None, 1)
  48. auth_scheme = auth_scheme.lower()
  49. if auth_scheme != "bearer":
  50. raise Unauthorized("Invalid Authorization header format. Expected 'Bearer <api-key>' format.")
  51. admin_api_key = dify_config.ADMIN_API_KEY
  52. if admin_api_key:
  53. if admin_api_key == auth_token:
  54. workspace_id = request.headers.get("X-WORKSPACE-ID")
  55. if workspace_id:
  56. tenant_account_join = (
  57. db.session.query(Tenant, TenantAccountJoin)
  58. .filter(Tenant.id == workspace_id)
  59. .filter(TenantAccountJoin.tenant_id == Tenant.id)
  60. .filter(TenantAccountJoin.role == "owner")
  61. .one_or_none()
  62. )
  63. if tenant_account_join:
  64. tenant, ta = tenant_account_join
  65. account = db.session.query(Account).filter_by(id=ta.account_id).first()
  66. # Login admin
  67. if account:
  68. account.current_tenant = tenant
  69. current_app.login_manager._update_request_context_with_user(account) # type: ignore
  70. user_logged_in.send(current_app._get_current_object(), user=_get_user()) # type: ignore
  71. if request.method in EXEMPT_METHODS or dify_config.LOGIN_DISABLED:
  72. pass
  73. elif not current_user.is_authenticated:
  74. return current_app.login_manager.unauthorized() # type: ignore
  75. # flask 1.x compatibility
  76. # current_app.ensure_sync is only available in Flask >= 2.0
  77. if callable(getattr(current_app, "ensure_sync", None)):
  78. return current_app.ensure_sync(func)(*args, **kwargs)
  79. return func(*args, **kwargs)
  80. return decorated_view
  81. def _get_user() -> EndUser | Account | None:
  82. if has_request_context():
  83. if "_login_user" not in g:
  84. current_app.login_manager._load_user() # type: ignore
  85. return g._login_user # type: ignore
  86. return None