|
| 1 | +from datetime import timedelta |
| 2 | + |
| 3 | +import simplekv |
| 4 | +import simplekv.memory |
| 5 | +from flask import Flask, request, jsonify |
| 6 | + |
| 7 | +from flask_jwt_extended import JWTManager, jwt_required, \ |
| 8 | + get_jwt_identity, revoke_token, unrevoke_token, \ |
| 9 | + get_stored_tokens, get_all_stored_tokens, create_access_token, \ |
| 10 | + create_refresh_token, jwt_refresh_token_required, get_stored_token |
| 11 | + |
| 12 | +# Setup flask |
| 13 | +app = Flask(__name__) |
| 14 | +app.secret_key = 'super-secret' |
| 15 | + |
| 16 | +# Configure access token expires time |
| 17 | +app.config['JWT_ACCESS_TOKEN_EXPIRES'] = timedelta(minutes=5) |
| 18 | + |
| 19 | +# Enable and configure the JWT blacklist / token revoke. We are using an in |
| 20 | +# memory store for this example. In production, you should use something |
| 21 | +# persistant (such as redis, memcached, sqlalchemy). See here for options: |
| 22 | +# http://pythonhosted.org/simplekv/ |
| 23 | +app.config['JWT_BLACKLIST_ENABLED'] = True |
| 24 | +app.config['JWT_BLACKLIST_STORE'] = simplekv.memory.DictStore() |
| 25 | +app.config['JWT_BLACKLIST_TOKEN_CHECKS'] = 'refresh' |
| 26 | + |
| 27 | +jwt = JWTManager(app) |
| 28 | + |
| 29 | + |
| 30 | +@app.route('/login', methods=['POST']) |
| 31 | +def login(): |
| 32 | + username = request.json.get('username', None) |
| 33 | + password = request.json.get('password', None) |
| 34 | + if username != 'test' and password != 'test': |
| 35 | + return jsonify({"msg": "Bad username or password"}), 401 |
| 36 | + |
| 37 | + ret = { |
| 38 | + 'access_token': create_access_token(identity=username), |
| 39 | + 'refresh_token': create_refresh_token(identity=username) |
| 40 | + } |
| 41 | + return jsonify(ret), 200 |
| 42 | + |
| 43 | + |
| 44 | +@app.route('/refresh', methods=['POST']) |
| 45 | +@jwt_refresh_token_required |
| 46 | +def refresh(): |
| 47 | + current_user = get_jwt_identity() |
| 48 | + ret = { |
| 49 | + 'access_token': create_access_token(identity=current_user) |
| 50 | + } |
| 51 | + return jsonify(ret), 200 |
| 52 | + |
| 53 | + |
| 54 | +# Endpoint for listing tokens that have the same identity as you |
| 55 | +@app.route('/auth/tokens', methods=['GET']) |
| 56 | +@jwt_required |
| 57 | +def list_identity_tokens(): |
| 58 | + username = get_jwt_identity() |
| 59 | + return jsonify(get_stored_tokens(username)), 200 |
| 60 | + |
| 61 | + |
| 62 | +# Endpoint for listing all tokens. In your app, you should either not expose |
| 63 | +# this endpoint, or put some addition security on top of it so only trusted users, |
| 64 | +# (administrators, etc) can access it |
| 65 | +@app.route('/auth/all-tokens') |
| 66 | +def list_all_tokens(): |
| 67 | + return jsonify(get_all_stored_tokens()), 200 |
| 68 | + |
| 69 | + |
| 70 | +# Endpoint for allowing users to revoke their tokens |
| 71 | +@app.route('/auth/tokens/revoke/<string:jti>', methods=['PUT']) |
| 72 | +@jwt_required |
| 73 | +def change_jwt_revoke_state(jti): |
| 74 | + username = get_jwt_identity() |
| 75 | + try: |
| 76 | + token_data = get_stored_token(jti) |
| 77 | + if token_data['token']['identity'] != username: |
| 78 | + raise KeyError |
| 79 | + revoke_token(jti) |
| 80 | + return jsonify({"msg": "Token successfully revoked"}), 200 |
| 81 | + except KeyError: |
| 82 | + return jsonify({'msg': 'Token not found'}), 404 |
| 83 | + |
| 84 | + |
| 85 | +@app.route('/auth/tokens/unrevoke/<string:jti>', methods=['PUT']) |
| 86 | +@jwt_required |
| 87 | +def change_jwt_unrevoke_state(jti): |
| 88 | + username = get_jwt_identity() |
| 89 | + try: |
| 90 | + token_data = get_stored_token(jti) |
| 91 | + if token_data['token']['identity'] != username: |
| 92 | + raise KeyError |
| 93 | + unrevoke_token(jti) |
| 94 | + return jsonify({"msg": "Token successfully unrevoked"}), 200 |
| 95 | + except KeyError: |
| 96 | + return jsonify({'msg': 'Token not found'}), 404 |
| 97 | + |
| 98 | + |
| 99 | +@app.route('/protected', methods=['GET']) |
| 100 | +@jwt_required |
| 101 | +def protected(): |
| 102 | + return jsonify({'hello': 'world'}) |
| 103 | + |
| 104 | +if __name__ == '__main__': |
| 105 | + app.run() |
0 commit comments