Accessing Flask Session From Different Files - python

I'm trying to neatly compartmentalize my code by separating flask app, service component and a decoupled key/value pair store.
My web app looks like this:
import flask
import os
import service_component as service
app = flask.Flask(__name__)
#app.route("/", methods=["POST"])
def event():
service.dostuff()
return "ok", 200
if __name__ == "__main__":
app.run(port=5000, debug=True)
# for test purposes
app.secret_key = os.urandom(24)
My service_component is:
import key_value_store
def dostuff():
val_i_want = key_value_store.provider["key"]
...and key_value_store looks like:
from flask import session
class SessionProvider:
def __getitem__(self, key):
return session.get(key)
def __setitem__(self, key, value):
session[key] = value
provider = SessionProvider()
The problem is that when I run the program, I get the error:
RuntimeError: The session is unavailable because no secret key was set. Set the secret_key on the application to something unique and secret.
Is there some requirement to keep the usage of "session" in my web app file? Are there recommended ways around this that still let me maintain loose coupling of components/abstraction of the key/value pair store?

Don't set the secret key here:
if __name__ == "__main__":
app.secret_key = os.urandom(24)
app.run(port=5000, debug=True)
return "ok", 200 # Also this does nothing here
The above will only apply when running with python app.py not with flask run or a WSGI server.
Also this would change the secret key on each launch, which you want to avoid. You should really be loading a pre-defined key in via your config, so user cookies aren't invalidated on each app restart. This sounds like it could lead to some weird session persistance behaviour.
If you don't have a config loader (yet), you can just hard-code the value right after you define the app:
app = Flask(__name__)
app.config['SECRET_KEY'] = 'super_secure'
Of course set that key to something sensible. If you want to generate this with Python, use the secrets module rather than os.urandom. However, again, you should passing the key as an actual string, rather than generating it dynamically on each app launch, for the reason mentioned above.

Related

Cannot create secret key in flask; returns “name 'session' is not defined”

Im attempting to create a website in flask. To do that, I need use sessions and therefore I am required to use a secret key. I did all of that, and yet it still returns a long error log with
nameerror: name ‘session’ is not defined at then end
I tried everything and moved the thing that sets the secret key everywhere, but it always had the same issue. Here is my code currently:
from flask import Flask
import os
app = Flask(__name__)
app.secret_key = os.urandom(24)
usernumber = 0
#app.route('/')
def homepage():
global usernumber
session['usernumber'] = usernumber
usernumber = usernumber + 1
Usernumberstring = session['usernumber']
return f"Welcome {Usernumberstring}"
if __name__ == '__main__':
app.run(use_reloader=True, debug=False, host="0.0.0.0")
You are not importing session;
from flask import Flask, session
Check more details about flask session here;
https://pythonbasics.org/flask-sessions/#:~:text=Unlike%20cookies%2C%20Session%20(session),temporary%20directory%20on%20the%20server.

RuntimeError: The session is unavailable because no secret key was set. Set the secret_key on the application to something unique and secret

I am making Flask app.
I wrote this code:
from flask import Flask, session
from flask_caching import Cache
app = Flask(__name__)
cache = Cache(app, config={'CACHE_TYPE': 'simple'})
#app.route('/my-route')
#cache.cached(timeout=50)
def my_route():
id = request.args.get('id')
schema = Schema({
Required('id'): All(Coerce(str))
})
try:
schema({'id': id})
except MultipleInvalid as e:
str(e)
ans=test(session[‘id’])
return ans
if __name__ == '__main__':
app.run(debug=True)
When I run the append access localhost:8000/my-route?id=aDj1948, I get:
RuntimeError: The session is unavailable because no secret key was set. Set the secret_key on the application to something unique and secret. error.
I rewrote #cache.cached(timeout=50, key_prefix=make_cache_key), but same error happens. I do not think I have to set secret key somewhere in the codes, so I really cannot understand what is wrong.
How should I fix this?
What is wrong in my codes?
It has nothing to do with cache. In order to use sessions you have to set a secret key: http://flask.pocoo.org/docs/1.0/quickstart/#sessions
Add the following (obviously don't use my example and change the secret key) after initialising your app:
app = Flask(__name__)
# Set the secret key to some random bytes. Keep this really secret!
app.secret_key = b'_5#y2L"F4Q8z\n\xec]/'
You can generate secrets on the fly:
import secrets
secret = secrets.token_urlsafe(32)
app.secret_key = secret
I don't think there is anything related to cache as I tried to clear mine and recheck multiple times.
You just have to just simply add
app.secret_key = 'dd hh' #the secret_key can be anything

Difficulty implementing server side session storage using redis and flask

I have a setup where a node.js app is making ajax requests to a flask based python server. Since ajax requests lack cookie data, I can't use the simple flask session object to persist data across requests. To remedy this, I'd like to implement a redis based server side implementation of a session storage system, but the solutions I've found so far do not work.
One solution I've tried is the following this snippet.
But this doesn't work. Is there more setup I need to do to configure redis beyond what is mentioned in the quickstart guide? Here is my attempt:
...
from flask import session
# Snippet code is copy pasted here verbatum
import session_interface
...
app = Flask(__name__)
app.session_interface = session_interface.RedisSessionInterface()
...
# Can't access this as session['key'] across requests
session['key'] = value
...
if __name__ == '__main__':
app.secret_key = '123456789012345678901234'
app.run(debug=True)
Another solution I've tried is importing the Flask-Session extention.
However, I can't get this to work either. The section I'm confused about is the following:
"We are not supplying something like SESSION_REDIS_HOST and SESSION_REDIS_PORT, if you want to use the RedisSessionInterface, you should configure SESSION_REDIS to your own redis.Redis instance. This gives you more flexibility, like maybe you want to use the same redis.Redis instance for cache purpose too, then you do not need to keep two redis.Redis instance in the same process."
What is meant by this section and how would I have figured this out? Here is my attempt to make this extension work:
...
from flask import session
from flask_session import Session
import redis
...
app = Flask(__name__)
SESSION_TYPE = 'redis'
app.config.from_object(__name__)
Session(app)
...
# Can't access this as session['key'] across requests
session['key'] = value
...
if __name__ == '__main__':
app.secret_key = '123456789012345678901234'
app.run(debug=True)
Has anyone successfully implemented manual session storage on a server running flask? Are there other options for getting this functionality?
Thanks for your input.
I think that's because you missed the URL configuration for your storage Redis, to check that, you can use Redis-CLI to see if there is anything being inserted into Redis.
I use this code and it worked:
from flask import Flask
from flask_session import Session
import redis
……
app = Flask(__name__)
app.config['SESSION_TYPE'] = 'redis'
app.config['SESSION_REDIS'] = redis.from_url('127.0.0.1:6379')
sess = Session()
sess.init_app(app)
def getSession():
return session.get('key', 'not set')
def setSession():
session.set('key')=123
return 'ok'
……
The following works for me:
...
from flask_session import Session
import redis
...
app = Flask(__name__)
SECRET_KEY = '123456789012345678901234'
SESSION_TYPE = 'redis'
SESSION_REDIS = redis.from_url('localhost:6379')
app.config.from_object(__name__)
sess = Session()
sess.init_app(app)
...
# Should be available accross requests now
session['key'] = value
...
if __name__ == '__main__':
app.run(debug=True)
Using sess.init_app(app) instead of Session(app) did the trick.

Trying to flash a message raises an exception

I want to use flash to show a message, but doing so raises an exception. The code below demonstrates the error, and works fine if the call to flash is removed. How do I fix this error?
from flask import Flask, flash
app = Flask(__name__)
#app.route('/')
def index():
flash('Entered')
return 'Completed'
app.run(debug=True)
RuntimeError: the session is unavailable because no secret key was set. Set the secret_key on the application to something unique and secret.
As the error says, you have not set a secret key, so the session is unavailable. The session relies on a secret key to sign the cookie prevent tampering. Message flashing relies on the session.
Set the SECRET_KEY config item to fix this error.
# set as part of the config
SECRET_KEY = 'many random bytes'
# or set directly on the app
app.secret_key = 'many random bytes'
In your run.py file
from tc import app
app.secret_key='12345'
app.run(debug=True)

Using pytest with gaesessions session middleware in appengine

When I run py.test --with-gae, I get the following error (I have pytest_gae plugin installed):
def get_current_session():
"""Returns the session associated with the current request."""
> return _tls.current_session
E AttributeError: 'thread._local' object has no attribute 'current_session'
gaesessions/__init__.py:50: AttributeError
I'm using pytest to test my google appengine application. The application runs fine when run in the localhost SDK or when deployed to GAE servers. I just can't figure out how to make pytest work with gaesessions.
My code is below:
test_handlers.py
from webtest import TestApp
import appengine_config
def pytest_funcarg__anon_user(request):
from main import app
app = appengine_config.webapp_add_wsgi_middleware(app)
return TestApp(app)
def test_session(anon_user):
from gaesessions import get_current_session
assert get_current_session()
appengine_config.py
from gaesessions import SessionMiddleware
def webapp_add_wsgi_middleware(app):
from google.appengine.ext.appstats import recording
app = recording.appstats_wsgi_middleware(app)
app = SessionMiddleware(app, cookie_key="replaced-with-this-boring-text")
return app
Relevant code from gaesessions:
# ... more code are not show here ...
_tls = threading.local()
def get_current_session():
"""Returns the session associated with the current request."""
return _tls.current_session
# ... more code are not show here ...
class SessionMiddleware(object):
"""WSGI middleware that adds session support.
``cookie_key`` - A key used to secure cookies so users cannot modify their
content. Keys should be at least 32 bytes (RFC2104). Tip: generate your
key using ``os.urandom(64)`` but do this OFFLINE and copy/paste the output
into a string which you pass in as ``cookie_key``. If you use ``os.urandom()``
to dynamically generate your key at runtime then any existing sessions will
become junk every time your app starts up!
``lifetime`` - ``datetime.timedelta`` that specifies how long a session may last. Defaults to 7 days.
``no_datastore`` - By default all writes also go to the datastore in case
memcache is lost. Set to True to never use the datastore. This improves
write performance but sessions may be occassionally lost.
``cookie_only_threshold`` - A size in bytes. If session data is less than this
threshold, then session data is kept only in a secure cookie. This avoids
memcache/datastore latency which is critical for small sessions. Larger
sessions are kept in memcache+datastore instead. Defaults to 10KB.
"""
def __init__(self, app, cookie_key, lifetime=DEFAULT_LIFETIME, no_datastore=False, cookie_only_threshold=DEFAULT_COOKIE_ONLY_THRESH):
self.app = app
self.lifetime = lifetime
self.no_datastore = no_datastore
self.cookie_only_thresh = cookie_only_threshold
self.cookie_key = cookie_key
if not self.cookie_key:
raise ValueError("cookie_key MUST be specified")
if len(self.cookie_key) < 32:
raise ValueError("RFC2104 recommends you use at least a 32 character key. Try os.urandom(64) to make a key.")
def __call__(self, environ, start_response):
# initialize a session for the current user
_tls.current_session = Session(lifetime=self.lifetime, no_datastore=self.no_datastore, cookie_only_threshold=self.cookie_only_thresh, cookie_key=self.cookie_key)
# create a hook for us to insert a cookie into the response headers
def my_start_response(status, headers, exc_info=None):
_tls.current_session.save() # store the session if it was changed
for ch in _tls.current_session.make_cookie_headers():
headers.append(('Set-Cookie', ch))
return start_response(status, headers, exc_info)
# let the app do its thing
return self.app(environ, my_start_response)
The problem is that your gae sessions is not yet called until the app is also called. The app is only called when you make a request to it. Try inserting a request call before you check for the session value. Check out the revised test_handlers.py code below.
def test_session(anon_user):
anon_user.get("/") # get any url to call the app to create a session.
from gaesessions import get_current_session
assert get_current_session()

Categories