Combining Flask-restless, Flask-security and regular Python requests
I finally went to Flask-JWT (https://pypi.python.org/pypi/Flask-JWT/0.1.0)
Here is my modified minimal example:
from flask import Flask, render_template, request, url_for, redirectfrom flask.ext.sqlalchemy import SQLAlchemyfrom flask.ext.security import Security, SQLAlchemyUserDatastore, \ UserMixin, RoleMixin, login_required, current_user, logout_userfrom flask.ext.restless import APIManagerfrom flask.ext.restless import ProcessingExceptionfrom flask.ext.login import user_logged_in# JWT importsfrom datetime import timedeltafrom flask_jwt import JWT, jwt_required# Create appapp = Flask(__name__)app.config['DEBUG'] = Trueapp.config['SECRET_KEY'] = 'super-secret'app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite://'# expiration delay for tokens (here is one minute)app.config['JWT_EXPIRATION_DELTA'] = timedelta(seconds=60)# Create database connection objectdb = SQLAlchemy(app)# creates the JWT Token authentication ======================================jwt = JWT(app)@jwt.authentication_handlerdef authenticate(username, password): user = user_datastore.find_user(email=username) print '%s vs. %s' % (username, user.email) if username == user.email and password == user.password: return user return None@jwt.user_handlerdef load_user(payload): user = user_datastore.find_user(id=payload['user_id']) return user# Define Flask-security models ===============================================roles_users = db.Table('roles_users', db.Column('user_id', db.Integer(), db.ForeignKey('user.id')), db.Column('role_id', db.Integer(), db.ForeignKey('role.id')))class Role(db.Model, RoleMixin): id = db.Column(db.Integer(), primary_key=True) name = db.Column(db.String(80), unique=True) description = db.Column(db.String(255))class User(db.Model, UserMixin): id = db.Column(db.Integer, primary_key=True) email = db.Column(db.String(255), unique=True) password = db.Column(db.String(255)) active = db.Column(db.Boolean()) confirmed_at = db.Column(db.DateTime()) roles = db.relationship('Role', secondary=roles_users, backref=db.backref('users', lazy='dynamic'))#Some additional stuff to query over...class SomeStuff(db.Model): __tablename__ = 'somestuff' id = db.Column(db.Integer, primary_key=True) data1 = db.Column(db.Integer) data2 = db.Column(db.String(10)) user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=True) user = db.relationship(User, lazy='joined', join_depth=1, viewonly=True)# Setup Flask-Securityuser_datastore = SQLAlchemyUserDatastore(db, User, Role)security = Security(app, user_datastore)# Flask-Restless API ==========================================================@jwt_required()def auth_func(**kw): return Trueapimanager = APIManager(app, flask_sqlalchemy_db=db)apimanager.create_api(SomeStuff, methods=['GET', 'POST', 'DELETE', 'PUT'], url_prefix='/api/v1', collection_name='free_stuff', include_columns=['data1', 'data2', 'user_id'])apimanager.create_api(SomeStuff, methods=['GET', 'POST', 'DELETE', 'PUT'], url_prefix='/api/v1', preprocessors=dict(GET_SINGLE=[auth_func], GET_MANY=[auth_func]), collection_name='protected_stuff', include_columns=['data1', 'data2', 'user_id'])# Create some users to test with@app.before_first_requestdef create_user(): db.create_all() user_datastore.create_user(email='test', password='test') user_datastore.create_user(email='test2', password='test2') ### stuff = SomeStuff(data1=2, data2='toto', user_id=1) db.session.add(stuff) stuff = SomeStuff(data1=5, data2='titi', user_id=1) db.session.add(stuff) db.session.commit()# Views@app.route('/')@login_requireddef home(): print(request.headers) return render_template('index.html')@app.route('/logout/')def log_out(): logout_user() return redirect(request.args.get('next') or '/')if __name__ == '__main__': app.run()
Then, to interact with it via requests
:
>>> import requests, json >>> r=requests.get('http://127.0.0.1:5000/api/v1/free_stuff') # this is OK >>> print 'status:', r.status_codestatus: 200 >>> r=requests.get('http://127.0.0.1:5000/api/v1/protected_stuff') # this should fail >>> print 'status:', r.status_codestatus: 401 >>> print r.json(){u'status_code': 401, u'description': u'Authorization header was missing', u'error': u'Authorization Required'} >>> # Authenticate and retrieve Token >>> r = requests.post('http://127.0.0.1:5000/auth', ...: data=json.dumps({'username': 'test', 'password': 'test'}),...: headers={'content-type': 'application/json'}...: ) >>> print 'status:', r.status_codestatus: 200 >>> token = r.json()['token'] >>> # now we have the token, we can navigate to restricted area: >>> r = requests.get('http://127.0.0.1:5000/api/v1/protected_stuff', ...: headers={'Authorization': 'Bearer %s' % token}) >>> print 'status:', r.status_codestatus: 200
Your original query (of using python requests module) helped me get unstuck :)I did not do anything different.
I am not using Flask-Restless (yet)
FWIW - I was able to get the auth token using "just" Flask-Security (i.e. without having to use Flask-jwt)
See here for details