Skip to content

Commit

Permalink
Support an optional=True argument in login_required decorator
Browse files Browse the repository at this point in the history
  • Loading branch information
miguelgrinberg committed Apr 26, 2020
1 parent 75d3fef commit 8ecbb11
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 4 deletions.
8 changes: 8 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,14 @@ API Documentation
def private_page():
return "Only for admins!"

An optional ``optional`` argument can be set to ``True`` to allow the route to execute also when authentication is not included with the request, in which case ``auth.current_user()`` will be set to ``None``. Example::

@app.route('/private')
@auth.login_required(optional=True)
def private_page():
user = auth.current_user()
return "Hello {}!".format(user.name if user is not None else 'anonymous')

.. method:: current_user()

The user object returned by the ``verify_password`` callback on successful authentication. If no user is returned by the callback, this is set to the username passed by the client. Example::
Expand Down
10 changes: 6 additions & 4 deletions flask_httpauth.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,11 @@ def authorize(self, role, user, auth):
elif role in user_roles:
return True

def login_required(self, f=None, role=None):
if f is not None and role is not None: # pragma: no cover
raise ValueError('role is the only supported argument')
def login_required(self, f=None, role=None, optional=None):
if f is not None and \
(role is not None or optional is not None): # pragma: no cover
raise ValueError(
'role and optional are the only supported arguments')

def login_required_internal(f):
@wraps(f)
Expand All @@ -147,7 +149,7 @@ def decorated(*args, **kwargs):
status = 401
elif not self.authorize(role, user, auth):
status = 403
if status:
if not optional and status:
# Clear TCP receive buffer of any pending data
request.data
try:
Expand Down
9 changes: 9 additions & 0 deletions tests/test_token.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ def index():
def token_auth_route():
return 'token_auth:' + token_auth.current_user()

@app.route('/protected-optional')
@token_auth.login_required(optional=True)
def token_auth_optional_route():
return 'token_auth:' + str(token_auth.current_user())

@app.route('/protected2')
@token_auth2.login_required
def token_auth_route2():
Expand Down Expand Up @@ -74,6 +79,10 @@ def test_token_auth_login_valid_different_case(self):
'mytoken this-is-the-token!'})
self.assertEqual(response.data.decode('utf-8'), 'token_auth:user')

def test_token_auth_login_optional(self):
response = self.client.get('/protected-optional')
self.assertEqual(response.data.decode('utf-8'), 'token_auth:None')

def test_token_auth_login_invalid_token(self):
response = self.client.get(
'/protected', headers={'Authorization':
Expand Down

0 comments on commit 8ecbb11

Please sign in to comment.