Reputation: 553
I am using Flask-Restless to make a super simple REST API. I would like to add authentication, but just for put/post/delete calls, while I want to leave get calls public.
So far, I put in my views.py file this:
manager = flask.ext.restless.APIManager(app, flask_sqlalchemy_db=db)
manager.create_api(models.mymodel, methods=['GET', 'POST', 'DELETE'])
I had a look on different solutions for authentication, but they all look too "big". I'll have just one user that should be able to make PUT/POST/DELETE calls, and then "public" users will just use GET.
I think that a simple way should be something like this:
The "check" shouldn't be something like storing a secret-key in my config.py
file and then comparing it to an attribute of the header of the api call? I think that creating an entire table for users, as I saw in some tutorials, and then having usernames+password
that generates API tokens is too "big" and not necessary here.. Since I will be the only user that can be authenticated, I know what the key is and I can just put some 'secret-key' : mysecretkey
in the header. Am I missing something?
Thanks!
Upvotes: 1
Views: 1772
Reputation: 31870
No need to reinvent authentication when HTTP Basic Auth exists:
Upvotes: 0
Reputation: 976
This can be done using preprocessors argument of create_api
. For example:
# replace the next line with your favorite way or reading config files
access_password = 'mysecretkey'
def check_credentials(**kwargs):
if flask.request.headers.get('X-Secret-Key','') != access_password:
raise flask_restless.ProcessingException(code=401) # Unauthorized
# create API
manager = flask_restless.APIManager(app, flask_sqlalchemy_db=db)
manager.create_api(models.mymodel, methods=['GET', 'POST', 'DELETE'],
collection_name='myobjects',
preprocessors={
'POST': [check_credentials],
'DELETE_SINGLE': [check_credentials],
})
Tested with Python 3.4, Flask 0.11.1, Flask-Restless 0.17.0. Older versions for Flask-Restless may require DELETE
instead of DELETE_SINGLE
, and a different package name.
An example how to access the password-protected part of the API using cURL:
curl -X POST -d '{"data":"my JSON data, etc."}' \
-H "Content-Type: application/json" \
-H "X-Secret-Key: mysecretkey" \
http://localhost:5000/api/myobjects
This is a simple scheme, but if there is any chance you app may grow bigger in the future, I would recommend going with Flask-JWT. It doesn't have to be big and complicated with a database back-end. Here is your starting case (one used with a hardcoded password) in a minimalist implementation:
# Anonymous object is sufficient here, a full-blown solution would define a class User
admin_user = type('', (object,), {"id": 1, "username": "admin", "password": "mysecret"})()
def authenticate(username, password):
if username == admin_user.username and password == admin_user.password:
return admin_user
def identity(payload):
id = payload['identity']
if id == admin_user.id:
return admin_user
jwt = JWT(app, authenticate, identity)
@jwt_required()
def check_credentials(**kwargs):
pass
# create API as in the first example
Tested with Python 3.4, Flask 0.11.1, Flask-Restless 0.17.0, Flask-JWT 0.3.2.
Upvotes: 2