You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

login.py 4.3KB

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