-
-
Notifications
You must be signed in to change notification settings - Fork 239
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #173 from luord/json-lookup
Added a fourth lookup within the json body
- Loading branch information
Showing
10 changed files
with
249 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
JWT in JSON Body | ||
================ | ||
|
||
You can also pass the token as an attribute in the body of an `application/json` request. | ||
However, since the body is meaningless in a `GET` request, this is mostly useful for | ||
protecting routes that only accept `POST`, `PATCH`, or `DELETE` methods. | ||
|
||
That is to say, the `GET` method will become essentially unauthorized in any protected route | ||
if you only use this lookup method. | ||
|
||
If you decide to use JWTs in the request body, here is an example of how it might look: | ||
|
||
.. literalinclude:: ../examples/jwt_in_json.py |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
from flask import Flask, jsonify, request | ||
|
||
from flask_jwt_extended import ( | ||
JWTManager, jwt_required, create_access_token, | ||
) | ||
|
||
app = Flask(__name__) | ||
|
||
# IMPORTANT: Body is meaningless in GET requests, so using json | ||
# as the only lookup method means that the GET method will become | ||
# unauthorized in any protected route, as there's no body to look for. | ||
|
||
app.config['JWT_TOKEN_LOCATION'] = ['json'] | ||
app.config['JWT_SECRET_KEY'] = 'super-secret' # Change this! | ||
|
||
jwt = JWTManager(app) | ||
|
||
|
||
@app.route('/login', methods=['POST']) | ||
def login(): | ||
username = request.json.get('username', None) | ||
password = request.json.get('password', None) | ||
if username != 'test' or password != 'test': | ||
return jsonify({"msg": "Bad username or password"}), 401 | ||
|
||
access_token = create_access_token(identity=username) | ||
return jsonify(access_token=access_token) | ||
|
||
|
||
# The default attribute name where the JWT is looked for is `access_token`, | ||
# and can be changed with the JWT_JSON_KEY option. | ||
# Notice how the route is unreachable with GET requests. | ||
@app.route('/protected', methods=['GET', 'POST']) | ||
@jwt_required | ||
def protected(): | ||
return jsonify(foo='bar') | ||
|
||
if __name__ == '__main__': | ||
app.run() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
import pytest | ||
from flask import Flask, jsonify | ||
|
||
from flask_jwt_extended import JWTManager, jwt_required, jwt_refresh_token_required, create_access_token, create_refresh_token | ||
from tests.utils import get_jwt_manager | ||
|
||
|
||
@pytest.fixture(scope='function') | ||
def app(): | ||
app = Flask(__name__) | ||
app.config['JWT_SECRET_KEY'] = 'foobarbaz' | ||
app.config['JWT_TOKEN_LOCATION'] = 'json' | ||
JWTManager(app) | ||
|
||
@app.route('/protected', methods=['POST']) | ||
@jwt_required | ||
def access_protected(): | ||
return jsonify(foo='bar') | ||
|
||
@app.route('/refresh', methods=['POST']) | ||
@jwt_refresh_token_required | ||
def refresh_protected(): | ||
return jsonify(foo='bar') | ||
|
||
return app | ||
|
||
|
||
def test_content_type(app): | ||
test_client = app.test_client() | ||
|
||
with app.test_request_context(): | ||
access_token = create_access_token('username') | ||
refresh_token = create_refresh_token('username') | ||
|
||
data = {'access_token': access_token} | ||
response = test_client.post('/protected', data=data) | ||
|
||
assert response.status_code == 401 | ||
assert response.get_json() == {'msg': 'Invalid content-type. Must be application/json.'} | ||
|
||
data = {'refresh_token': refresh_token} | ||
response = test_client.post('/refresh', data=data) | ||
|
||
assert response.status_code == 401 | ||
assert response.get_json() == {'msg': 'Invalid content-type. Must be application/json.'} | ||
|
||
|
||
def test_custom_body_key(app): | ||
app.config['JWT_JSON_KEY'] = 'Foo' | ||
app.config['JWT_REFRESH_JSON_KEY'] = 'Bar' | ||
test_client = app.test_client() | ||
|
||
with app.test_request_context(): | ||
access_token = create_access_token('username') | ||
refresh_token = create_refresh_token('username') | ||
|
||
# Ensure 'default' keys no longer work | ||
data = {'access_token': access_token} | ||
response = test_client.post('/protected', json=data) | ||
assert response.status_code == 401 | ||
assert response.get_json() == {'msg': 'Missing "Foo" key in json data.'} | ||
|
||
|
||
data = {'refresh_token': refresh_token} | ||
response = test_client.post('/refresh', json=data) | ||
assert response.status_code == 401 | ||
assert response.get_json() == {'msg': 'Missing "Bar" key in json data.'} | ||
|
||
# Ensure new keys do work | ||
data = {'Foo': access_token} | ||
response = test_client.post('/protected', json=data) | ||
assert response.status_code == 200 | ||
assert response.get_json() == {'foo': 'bar'} | ||
|
||
data = {'Bar': refresh_token} | ||
response = test_client.post('/refresh', json=data) | ||
assert response.status_code == 200 | ||
assert response.get_json() == {'foo': 'bar'} | ||
|
||
|
||
def test_missing_keys(app): | ||
test_client = app.test_client() | ||
jwtM = get_jwt_manager(app) | ||
headers = {'content-type': 'application/json'} | ||
|
||
# Ensure 'default' no json response | ||
response = test_client.post('/protected', headers=headers) | ||
assert response.status_code == 401 | ||
assert response.get_json() == {'msg': 'Missing "access_token" key in json data.'} | ||
|
||
# Test custom no json response | ||
@jwtM.unauthorized_loader | ||
def custom_response(err_str): | ||
return jsonify(foo='bar'), 201 | ||
|
||
response = test_client.post('/protected', headers=headers) | ||
assert response.status_code == 201 | ||
assert response.get_json() == {'foo': "bar"} | ||
|
||
def test_defaults(app): | ||
test_client = app.test_client() | ||
|
||
with app.test_request_context(): | ||
access_token = create_access_token('username') | ||
refresh_token = create_refresh_token('username') | ||
|
||
data = {'access_token': access_token} | ||
response = test_client.post('/protected', json=data) | ||
assert response.status_code == 200 | ||
assert response.get_json() == {'foo': 'bar'} | ||
|
||
data = {'refresh_token': refresh_token} | ||
response = test_client.post('/refresh', json=data) | ||
assert response.status_code == 200 | ||
assert response.get_json() == {'foo': 'bar'} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters