Custom requests bypassing token auth in EVE - python

I'm new to EVE framework, but already have some experience with flask and mongodb. I want to build a web app based on eve rest with token auth. So for example I have the case: I want to check if email exists in realtime when user filled out the form. The user info is in users collection, but I want to put users collection under token auth. So how should I handle custom request without token? Should it be handled through flask?
Maybe something like this:
#app.route('/_check_email', methods=['GET'])
def check_email():
print request
email = request.args.get('email', 0, type=str)
accounts = app.data.driver.db['users']
lookup = {'email': email}
account = accounts.find_one(lookup)
if not account:
return jsonify(valid=True)
else:
return jsonify(valid=False)
Thanks!

You might want to wrap it all in a Flask Blueprint. See what's been done with Eve-Docs extension. Other than that, Eve is just a Flask subclass so you are free to play with it as you would do with Flask itself.

Related

flask-login without flask-sqlalchemy or ORM

I am currently using flask-login in my application for user login session management. I am using flask-sqlalchemy, so all working ok.
Because of my previous sql experience, I am not fan of ORM. I like to use SQL directly. May be it is because of my not sound knowledge in ORM. Anyways, my question is- is there any way I can use flask-login without ORM/flask-sqlalchemy, where I am getting user data by pymysql or MySQL-connector?
I know I can create sessions myself and pop when I logout, but I want to know if there is any way to use flask-login or any other session management library with pymysql?
I went with the following solution. It allows to redefine getting user from request Authorization header and use in stateless application.
from flask_login import login_required, LoginManager
login_manager = LoginManager()
login_manager.init_app(app)
#login_manager.request_loader
def load_user_from_request(request):
api_key: str = request.headers.get('Authorization')
if api_key:
token_type, token = api_key.split()
print("token_type:" + token_type)
if token_type == "JWT" and token:
decoded_token: dict = decode_token(token)
username = decoded_token['identity']
user: User = get_user(username)
return user
return None
So if your endpoint is allowed to be used only by authorized users, #jwt_required or #login_required annotations can be used with method.
Be sure that route annotation is the first among others to guarantee correct work of other annotations; your endpoint can be look like:
#app.route('/api/users', methods=['GET'])
#login_required
#roles_required(['Admin']) # optional
def list_users():
return list[] # your code here
Here is another one annotation mentioned, #roles_required, it is not obligatory of course. Since Flask user management requires you to use ORM, you can overcome that by defining your own #roles_required annotation, see example here.

How to get oauth2 client app from Django request

I'm using oauth2_provider + rest_framework. I have configured several client applications, and they successfully authenticate and receive access tokens.
I would like to have the client app in the request (Eg. request.client). Perhaps I should create some kind of middleware, which sets it, but I'm not sure what is the proper way to do it. Or maybe this functionality is already provided by the oauth2_provider/oauthlib, and I have overlooked it?
The client should be set when:
a valid access token is provided
valid app credentials are provided (like when requesting access token)
Python v3.5.3, Django v1.10.6
oauth2_provider AccessToken has a foreign key
to the application issued that token
You can get the application form the access token like this: application = request.auth.application
AbstractApplication class has foreign key to settings.AUTH_USER_MODEL https://github.com/evonove/django-oauth-toolkit/blob/0.12.0/oauth2_provider/models.py#L62
So if you are using default Application class you could get the clients by request.user.oauth2_providers_applications

Different login views for different flask blueprints

I have a flask web application and it has multiple blueprints:
restserver
webserver
Most of the endpoints in both webserver and restserver require the user to be logged-in. I use flask-login extension, which provides #login_required decorator.
Is it possible to have different login_view for different blueprints?
# for web blueprint
login_mananger.login_view = '/web/login'
.. so on
One of the most important specialities of RESTful is statelessness, it means the server won't "remember" any information from clients, the requests from clients should have contained all the needed informations, including auth informations.
Back to your question, you don't have to use Flask-Login for RESTful service authentication, and you should not use cookies or sessions because of the diversity of the clients. You can DIY the HTTP authentication of course, but Flask-HTTPAuth is what you really need.
Here is a simplest example of Flask-HTTPAuth:
from flask.ext.httpauth import HTTPBasicAuth
auth = HTTPBasicAuth()
#auth.verify_password
def verify_password(username, password):
user = User.query.filter_by(username=username).first()
if not user:
return False
g.current_user = user
# You should accomplish the verify_password function by yourself in the User model.
return user.verify_password(password)
According to the doc of Flask-HTTPAuth:
The callback function takes two arguments, the username and the
password and must return True or False.
You should notice that the initialization of the Flask-HTTPAuth just in the blueprint rather than the whole application since this authentication just used in your restserver blueprint.
Then there is a function just like Flask-login's #login_required which provided by Flask-HTTPAuth:
#app.route('/private')
#auth.login_required
def private_page():
return "Only for authorized people!"
This "login_required" callback function will be called when authentication is succesful. Since all of your restserver's route should be protected, you can use a "before_request" handler for applying the protection to the whole blueprint. Assuming that your restserver blueprint's name is "rest" and you have saved the user object in "g" just like what we do before:
from flask import jsonify
#rest.before_request
#auth.login_required
def before_request():
if not g.current_user:
return jsonify({'error':'Unauthorized.'})
I think this will do the trick. What I wrote above is just the simplest example and you can do much better in many ways, such as replacing the user credentials with token after first request. I believe that you will figure it out.
If my answer is helpful, it will be my great honour if you can "upvote" for this answer, thanks.
In your case, you need to place the login manager declaration in the same file as the flask app instance. This is commonly an __init__.py file with the app = Flask(__name__).
At the top, import LoginManager class
from flask_login import LoginManager
Then tie it to the app instance.
login_manager = LoginManager()
login_manager.init_app(app)
(This was not asked but just incase someone needs it) Lets say you have admins and normal users and you are authenticating from different tables:
#login_manager.user_loader
def load_user(user_id):
x = Users.query.get(str(user_id))
if x == None:
x = Admins.query.get(str(user_id))
return x
Finally after importing blueprints you can define the login views for each in a dictionary
login_manager.blueprint_login_views = {
'admin': '/admin/login',
'site': '/login',
}

Passing values from HTML to python using EVE rest framework

I am creating a website using html as a frontend and python as a backend using EVE framework. I have enabled token authentication for my usersRESTful Account Management. But when I pass the values to the EVE framework it gives me a 401.
var login = function (loginData) {
var deferred = $q.defer();
$http.post(appConfig.serviceUrl + 'user',{data:loginData})
here the loginData holds the username and password of my user from the html page this piece of code is inside a .js file.
My api.py holds the following authentication code.
class RolesAuth(TokenAuth):
def check_auth(self, token, allowed_roles, resource, method):
# use Eve's own db driver; no additional connections/resources are used
accounts = app.data.driver.db['user']
lookup = {'token': token}
if allowed_roles:
lookup['roles'] = {'$in': allowed_roles}
account = accounts.find_one(lookup)
return account
def add_token(documents):
# Don't use this in production:
# You should at least make sure that the token is unique.
for document in documents:
document["token"] = (''.join(random.choice(string.ascii_uppercase)
for x in range(10)))
My problem is as soon as the api.py is run it asks to provide proper credentials. How can i send the token directly to the auth mechanism so that it lets me access the db.
How will you suggest me to get rid of the authentication alert box.
I want the token to be automatically sent to the api.
If suppose I use basic authentication how can I send the username and password values directly and validate it? Without having the browser pop-up box asking for username and password
Thanks in advance.
Does it work with curl ? Refer to this question
Also, refer to this and this thread on the mailing list.

python-social-auth + mobile app

I have a django app and I create API for mobile app. When it comes to user authentication I simple gets login + pass and do standard django login stuff. When user is logged in I generate a token, save it and provide to the mobile app.
Now it comes to Facebook and I would like to implement python-social-auth library. I do know how to implement it for standard web, it's really trivial. But I have no idea, how to implement it into my mobile API and how to incorporate there my token stuff.
Just thinking...
Is there a possibility to do programatical auth so I would be able to create API method and call the social auth stuff from there? But how about the "Allow access to XY app to your profile" page on facebook side?
Any advice helps. Thank you in advance.
The documentation describes how you can simply provide the access_token to authenticate/create a user.
from django.contrib.auth import login
from social.apps.django_app.utils import psa
# Define an URL entry to point to this view, call it passing the
# access_token parameter like ?access_token=<token>. The URL entry must
# contain the backend, like this:
#
# url(r'^register-by-token/(?P<backend>[^/]+)/$',
# 'register_by_access_token')
#psa('social:complete')
def register_by_access_token(request, backend):
# This view expects an access_token GET parameter, if it's needed,
# request.backend and request.strategy will be loaded with the current
# backend and strategy.
token = request.GET.get('access_token')
user = request.backend.do_auth(request.GET.get('access_token'))
if user:
login(request, user)
return 'OK'
else:
return 'ERROR'

Categories