Prevent Flask from ever sending Set-Cookie? - python

Can I prevent Flask framework from ever sending a Set-Cookie header?
I'm using a variety of blueprints that use the session cookie. I'm wondering if there is a way to tell the framework to simply never try to set cookies. I'd like to not have to prepare each individual response using suggestions like this or using app.after_request.

You can create custom session interface and override should_set_cookie method
from flask import Flask
from flask.sessions import SecureCookieSessionInterface, SessionMixin
class CustomSessionInterface(SecureCookieSessionInterface):
def should_set_cookie(self, app: "Flask", session: SessionMixin) -> bool:
return False
app = Flask(__name__)
app.session_interface = CustomSessionInterface()

Related

Flask session don't persist data

I have a Javascript application and a Flask application. When the user send data from Js to Flask, I store it on session and it works fine at a specific route:
#app.route(...)
def user(...):
session['name'] = name
print(session['name']) # Works !
But when I tr to get the values on session from another method / route the session is empty:
#app.route(...)
def current():
print(session.keys(), session.values) # Empty !
I have installed Flask Session and set the config to:
'SECRET_KEY': b'...',
'SESSION_TYPE': 'filesystem', # Memcache, null and redis
'SESSION_PERMANENT': False, # True
And then started the Flask application and it not work. I have also try to set session.modified = True after I add some new value to session and still not work.
I have read lots of threads on Stack Over Flow, Reddit, etc; and nothing worked. Tips please ?
TL;DR, enable CORS and credentials support on the back end, and use credentials in the front end code when issuing requests.
I recently ran into a similar issue where I was developing a front end and a back end in separate apps. I noticed that each time I issued a request from the front end client, it would create a new session for each request, which would rapidly bloat the session storage on the back end and made user tracking difficult if not impossible.
I'm assuming that you're Javascript app and Flask app are running separately (i.e., the javascript is not on a template being served by the Flask app and hence the js requests are coming from a different origin).
Suppose we have a simple app with Flask-Session enabled running on port 5000:
from flask import Flask, session
from flask_session import Session
app = Flask(__name__)
SECRET_KEY = "changeme"
SESSION_TYPE = 'filesystem'
app.config.from_object(__name__)
Session(app)
#app.route('/foo')
def foo():
return session.sid
#app.route('/bar')
def bar():
return session.sid
Now if we run the app if we navigate to either route on a browser(e.g., http://localhost:5000/foo), we would get the same session id. If you open another tab, open the developer tools and issue the following command in the console, you'd get a cors error:
// Using fetch, you can use jquery or axios
fetch("http://localhost:5000/foo").then(response => {
return response.text()
}).then(data => {
console.log(data)
})
You can fix this easily by installing Flask-CORS and wrapping your app in the CORS class:
from flask import Flask, session
from flask_session import Session
from flask_cors import CORS
app = Flask(__name__)
SECRET_KEY = "changeme"
SESSION_TYPE = 'filesystem'
app.config.from_object(__name__)
Session(app)
CORS(app)
#app.route('/foo')
def foo():
return session.sid
#app.route('/bar')
def bar():
return session.sid
Now if you run the javascript fetch function above, it prints out a different session id each time the request is invoked, even for the same route. That's because Flask can't track the session unless you're issuing the requests from the same origin or unless you provide some way for flask to identify the session. You can do this from your JS by allowing credentials to be passed:
fetch("http://localhost:5000/foo",
{ credentials: 'include' }).then(response => {
return response.text()
}).then(data => {
console.log(data)
})
However, you will get another CORS error regarding Access-Control-Allow-Credentials. You can fix this in you're Flask app by import the cross_origin decorator, wrapping your routes in the decorator and passing supports_credentials=True to the decorator. The flask code would look something like this:
from flask import Flask, session
from flask_session import Session
from flask_cors import CORS, cross_origin
app = Flask(__name__)
SECRET_KEY = "changeme"
SESSION_TYPE = 'filesystem'
app.config.from_object(__name__)
Session(app)
CORS(app)
#app.route('/foo')
#cross_origin(supports_credentials=True)
def foo():
return session.sid
#app.route('/bar')
#cross_origin(supports_credentials=True)
def bar():
return session.sid
Now flask can track the session by the requester (in this case, the browser running the Javascript app).
I had the same problem using classic post request in html. The session, which was still storing values in previous route, would empty itself after my post request.
I solved this using:
app.config.update(SESSION_COOKIE_SAMESITE="None", SESSION_COOKIE_SECURE=True)
I am sharing this in case others are facing the same issue.

Example of RESTful API in Flask Python

Can someone show me examples of making a RESTful API which uses database information in Flask? I have no idea how to implement POST, PUT and DELETE and I always get the 405 error where I can't use the method in url.
Have you add request method in your routing? you can following reference from: flask-restful
from flask import Flask, request
from flask_restful import Resource, Api
app = Flask(__name__)
api = Api(app)
class TodoSimple(Resource):
def get(self):
# do get something
def put(self):
# do put something
def delete(self):
# do delete something
def post(self):
# do post something
api.add_resource(TodoSimple, '/api/todo')
if __name__ == '__main__':
app.run(debug=True)
in flask-restful the HTTP actions (GET, PUT, POST, DELETE) have their corresponding method in the resource class, so is just a matter of defining those method in the resource (with the corresponding parameter defined in the routing)
I've also built a lightweight framework for building restful apis that makes it super easy to build apis. You can take a look at the code to have an idea of how an API can be built, configured and run, and of course, build on top of it
here's the code: https://github.com/sebastiandev/peach

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',
}

How to create dynamic subdomains in a Flask application

I am trying to setup variable route handling in a Flask application such as described in this answer: Dynamic Subdomain Handling in a Web App (Flask)
However, I want to be able to recognize certain subdomains BEFORE they are caught by the variable route so I can use the flask-restful api extension (Routing with RESTful).
For example, I have tried the following:
#app.route('/', subdomain="<user>", defaults={'path':''})
#app.route('/<path:path>', subdomain="<user>")
def user_profile(user,path):
pass
class Api(restful.Resource):
def get(self):
#Do Api things.
api.add_resource(Api, '/v1', subdomain="api")
When I test this, all of URLs go to the variable route handler and call user_prof(). I tried putting the api route first and the standard #app.route rule second and vice versa but there was no change.
Am I missing some other parameter or need to go deeper in Flask to make this happen?
Update:
The URL patterns I am trying to match are like this:
user1.mysite.com -> handled by user_profile()
user2.mysite.com -> handled by user_profile()
any_future_string.mysite.com -> handled by user_profile()
api.mysite.com/v1 -> handled by Api class
Other cases include:
www.mysite.com -> handled by index_display()
mysite.com -> handled by index_display()
#app.before_request
def before_request():
if 'api' == request.host[:-len(app.config['SERVER_NAME'])].rstrip('.'):
redirect(url_for('api'))
#app.route('/', defaults={'path': ''}, subdomain='api')
#app.route('/<path:path>', subdomain='api')
def api(path):
return "hello"
This should work. Add your api version to the path if needed or that could be processed by your API class.
To keep it simple, I redesigned the logic of my application into two distinct parts.
This way the Flask application only handles the API endpoint logic. The user profile logic is handled by another application. I can now add multiple Resources to the API application without worry about breaking the routing.

How can I create a session-local cookie-aware HTTP client in Django?

I'm using a web service backend to provide authentication to Django, and the get_user method must retain a cookie provided by the web service in order to associate with a session. Right now, I make my remote calls just by calling urllib2.urlopen(myTargetService) but this doesn't pass the cookie for the current session along.
I have created a session access middleware to store the session in the settings:
class SessionAccessMiddleware:
def process_request(self, request):
settings.current_session = request.session
So, I can access the request session in get_request and post_request, but I don't know how to have urllib2 remember my cookies in a session-specific way.
How do I do this?
Here: http://docs.python.org/library/cookielib.html#examples are examples of doing exactly what you try to do with urllib2 and cookielib. So according to docs you need to create cookielib.CookieJar, set cookie with correct data (from session), build an opener that uses your CookieJar and use it to fetch yourTargetService.
If settings in your middleware code means from django.conf import settings it's not good idea. Look at http://github.com/svetlyak40wt/django-globals/ for a place where you can safely store request-wide data for access from somewhere where request object is unaccessible. Also, it would be probably good idea to write custom authentication backend and use it with django.contrib.auth - instead of rolling your own auth system from scratch - which is covered here: http://docs.djangoproject.com/en/dev/topics/auth/#writing-an-authentication-backend .

Categories