Quickstart¶
Requirements¶
- Python 3.5
Note on Requirements¶
I do not currently plan to support older versions of python. Python 2 support is very unlikely to arrive as the original author is a die-hard believer in python 3. As for older versions of python 3, my test harnesses depend on some features only available in python 3.5.
Installation¶
Note
flask-praetorian does not support distutils or setuptools because the author has very strong feelings about python packaging and the role pip plays in taking us into a bright new future of standardized and usable python packaging
Install from pypi¶
This will install the latest release of flask-praetorian from pypi via pip:
$ pip install flask-praetorian
Install latest version from github¶
If you would like a version other than the latest published on pypi, you may do so by cloning the git repostiory:
$ git clone https://github.com/dusktreader/flask-praetorian.git
Next, checkout the branch or tag that you wish to use:
$ cd flask-praetorian
$ git checkout integration
Finally, use pip to install from the local directory:
$ pip install .
Example¶
This is a minimal example of how to use the flask-praetorian decorators:
import flask
import tempfile
import flask_sqlalchemy
import flask_praetorian
db = flask_sqlalchemy.SQLAlchemy()
guard = flask_praetorian.Praetorian()
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.Text, unique=True)
password = db.Column(db.Text)
roles = db.Column(db.Text)
@property
def rolenames(self):
try:
return self.roles.split(',')
except:
return []
@classmethod
def lookup(cls, username):
return cls.query.filter_by(username=username).one_or_none()
@classmethod
def identify(cls, id):
return cls.query.get(id)
app = flask.Flask(__name__)
app.debug = True
app.config['SECRET_KEY'] = 'top secret'
guard.init_app(app, User)
local_database = tempfile.NamedTemporaryFile(prefix='local', suffix='.db')
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///{}'.format(local_database)
db.init_app(app)
with app.app_context():
db.create_all()
db.session.add(User(
username='TheDude',
password=guard.encrypt_password('abides'),
))
db.session.add(User(
username='Walter',
password=guard.encrypt_password('calmerthanyouare'),
roles='admin'
))
db.session.add(User(
username='Donnie',
password=guard.encrypt_password('iamthewalrus'),
roles='operator'
))
db.session.add(User(
username='Maude',
password=guard.encrypt_password('andthorough'),
roles='operator,admin'
))
db.session.commit()
@app.route('/')
def root():
return 'root endpoint'
@app.route('/protected')
@flask_praetorian.auth_required()
def protected():
return 'protected endpoint'
@app.route('/protected_admin_required')
@flask_praetorian.auth_required()
@flask_praetorian.roles_required('admin')
def protected_admin_required():
return 'protected_admin_required endpoint'
@app.route('/protected_admin_accepted')
@flask_praetorian.auth_required()
@flask_praetorian.roles_accepted('admin', 'operator')
def protected_admin_and_operator_accepted():
return 'protected_admin_accepted endpoint'
if __name__ == '__main__':
app.run()
The above code can be found example/basic.py
. The server can be started by
calling:
$ python example/basic.py
Once the server is up and running, you can login and get an auth token by POSTing to the ‘/auth’ endpoint with a body containing your username and password:
POST /auth HTTP/1.1
Host: localhost:5000
Content-Type: application/json
{
"username": "TheDude",
"password": "abides"
}
The response will have a json body containing the token:
HTTP/1.1 200 OK
Content-Type: application/json
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZGVudGl0eSI6MSwiaWF0IjoxNDQ0OTE3NjQwLCJuYmYiOjE0NDQ5MTc2NDAsImV4cCI6MTQ0NDkxNzk0MH0.KPmI6WSjRjlpzecPvs3q_T3cJQvAgJvaQAPtk1abC_E"
}
This token can then be used to make requests against protected endpoints:: Once you have provisioned a token, you can try out the various endpoints that were created above by include the token in the request header like soo:
GET /protected HTTP/1.1
Authorization: JWT eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZGVudGl0eSI6MSwiaWF0IjoxNDQ0OTE3NjQwLCJuYmYiOjE0NDQ5MTc2NDAsImV4cCI6MTQ0NDkxNzk0MH0.KPmI6WSjRjlpzecPvs3q_T3cJQvAgJvaQAPtk1abC_E
You can try out the different endpoints with different users provisioned above to see how the role constraining decorators from flask-praetorian work.