I have been developing a web app using web.py. It uses a session like below:
store = web.session.DBStore(db.sess, "sessions")
session = web.session.Session(
app,
store,
initializer={
"auth": False,
"username": "anonymous",
"preferences": db.data.select('preferences', where="username='anonymous'", limit=1)[0]
}
)
web.config._session = session
I decided, it could be useful to have a desktop application as well. A problem I am running into though, is I cannot get a session to work properly outside of a web browser. I believe it's just another object that holds specific data, but I am not entirely sure.
What I need is some way to either use web.py to create a session so I can use all of my functions with it (many check for a session to see who is logged in) or I need some way to create a "fake" session containing essentially the same data as before so I could still use the functions.
My whole goal in this is to keep using the same model, since then I wouldn't have to rewrite many functions that just duplicate functionality.
I found out what I was doing wrong. Turns out web.input needs context, which is not available outside of the browser as far as I could see.
What I ended up doing was changing my login(...) method from login(input) to login(username, password). Now, from the interactive shell, I can get a session. I believe this will carry over into a desktop application as the interactive shell is not a browser.
Related
I'm building a flask server in python with Cloud Run, for a chatbot to call.
Sometimes if user wants to do something with the chatbot, the bot need ask the user to login to a 3rd party server before doing the things.
I have two routes:
Route 1 is "/login", it returns a simple iframe which will open a login page in a 3rd party server, generate a "session_id", and save some info I already get to a global variable dict called "runtimes" with the "session_id" as key, so that I can use it later when visitor successfully logged in.
Route 2 is "/callback/<session_id>". After user successfully login to its account, the 3rd party server will call this route with a token in url parameters. Then I will use the "session_id" to read the saved info from "runtimes", and do later things.
It works well in my local machine. But in Google Cloud Run, because it support multiple instances, sometimes it will trigger a new instance when server calls "callback", so it cannot get the "runtime" because they are in different instances.
I know that I can save the runtimes dict to a database to solve this problem, but it looks too overkill...Just not seem right.
Is there any easy way that I can make the "runtimes" be shared between instances?
The solution here is to use a central point of storage: database, memorystore, firestore,... something out of Cloud Run itself.
You can also try the Cloud Run execution runtime v2 that allow you to mount a network disk, such as Cloud Storage or Filestore. You can imagine to store the session data in a file which has the name of the session ID.
Note: On Cloud Run side, something is cooking, but it's not 100% safe, it will be a best effort. A database backup will be required even with that new feature
I am new to Flask.
I have a public api, call it api.example.com.
#app.route('/api')
def api():
name = request.args.get('name')
...
return jsonify({'address':'100 Main'})
I am building an app on top of my public api (call it www.coolapp.com), so in another app I have:
#app.route('/make_request')
def index():
params = {'name':'Fred'}
r = requests.get('http://api.example.com', params=params)
return render_template('really_cool.jinja2',address=r.text)
Both api.example.com and www.coolapp.com are hosted on the same server. It seems inefficient the way I have it (hitting the http server when I could access the api directly). Is there a more efficient way for coolapp to access the api and still be able to pass in the params that api needs?
Ultimately, with an API powered system, it's best to hit the API because:
It's user testing the API (even though you're the user, it's what others still access);
You can then scale easily - put a pool of API boxes behind a load balancer if you get big.
However, if you're developing on the same box you could make a virtual server that listens on localhost on a random port (1982) and then forwards all traffic to your api code.
To make this easier I'd abstract the API_URL into a setting in your settings.py (or whatever you are loading in to Flask) and use:
r = requests.get(app.config['API_URL'], params=params)
This will allow you to make a single change if you find using this localhost method isn't for you or you have to move off one box.
Edit
Looking at your comments you are hoping to hit the Python function directly. I don't recommend doing this (for the reasons above - using the API itself is better). I can also see an issue if you did want to do this.
First of all we have to make sure the api package is in your PYTHONPATH. Easy to do, especially if you're using virtualenvs.
We from api import views and replace our code to have r = views.api() so that it calls our api() function.
Our api() function will fail for a couple of reasons:
It uses the flask.request to extract the GET arg 'name'. Because we haven't made a request with the flask WSGI we will not have a request to use.
Even if we did manage to pass the request from the front end through to the API the second problem we have is using the jsonify({'address':'100 Main'}). This returns a Response object with an application type set for JSON (not just the JSON itself).
You would have to completely rewrite your function to take into account the Response object and handle it correctly. A real pain if you do decide to go back to an API system again...
Depending on how you structure your code, your database access, and your functions, you can simply turn the other app into package, import the relevant modules and call the functions directly.
You can find more information on modules and packages here.
Please note that, as Ewan mentioned, there's some advantages to using the API. I would advise you to use requests until you actually need faster requests (this is probably premature optimization).
Another idea that might be worth considering, depending on your particular code, is creating a library that is used by both applications.
I have been debugging this half a day now... anybody have ideas?
I wrote a python script to monitor active sessions, found this:
sessions = Session.objects.filter(expire_date__gte=datetime.now())
for session in sessions:
data = session.get_decoded()
id = data.get('_auth_user_id', None)
ses = session.session_key
if id:
name = User.objects.get(id=id)
gives nice list... ok. But -- if user logs out or in, the above code does not reflect the change. It just keeps repeating the original, outdated list.
Is there a caching issue? Think not -- disabled memcached, and no change.
Tried file and memcache based session storage -- strange result: the code above seems to read db-based session storage.
So, I suspect the initialization is not correct for the 1.4.3 -- as there seem to have been various ways to initialize environment. I believe 1.4. does not require anything but the environment variable DJANGO_SETTINGS_MODULE to be set to the app.
Next, if this does not resolve.. must use file based session storage and poll the directory.. that seems to be alive and kicking in realtime :)
Your problem is caused by transaction isolation. By default, each connection to the db runs inside a transaction. Usually, that equates to a view, and the transaction middleware takes care of opening and closing the transaction. In a standalone script, you'll need to manage that yourself.
I am working on a python web application based on the pyramid framework. I am trying to add session authentication to it. By that I understand that:
users can log in/out (security is desirable); user data are kept in a database
authentication is handled via the session (request.session)
First off: Is session authentication a good option or are there better ones?
Secondly: I can't really make heads or tails of the documentation and examples.
So far, I've followed http://docs.pylonsproject.org/projects/pyramid/en/1.3-branch/tutorials/wiki2/authorization.html#adding-login-and-logout-views so far that I have a login/logout form. However, my authn_policy is a http://docs.pylonsproject.org/projects/pyramid/en/latest/api/authentication.html#pyramid.authentication.SessionAuthenticationPolicy
As the session factory in pyramid is insecure (see http://docs.pylonsproject.org/projects/pyramid/en/1.3-branch/narr/sessions.html), I use *pyramid_beaker* instead.
The configuration is:
in __init__.py: session_factory = session_factory_from_settings(settings)
in the .ini file:
beaker.session.lock_dir = %(here)s/data/sessions/lock
beaker.session.type = ext:database
beaker.session.sa.url = mysql://user:pass#localhost:3306/db
beaker.session.table_name = user_session
I hope I was able to make my problem clear.
I'd say it depends on what you want to do. Session authentication works fine if you use Beaker, but I like using AuthTktAuthenticationPolicy for the additional timeout and reissue options, and the fact that your authentication doesn't disappear even if you clear the session.
I recently began a project to migrate our web app from apache + Mod_python to just cherry-py.
There is still a good deal of stuff I still need to do, but for now, it is CherryPy's sessions that are giving me a bit of a headache.
My first question is how do they work?
In Mod_python, we do something like this:
...
from mod_python import Session
sess = Session.Session(req, timeout = 60*60, lock=0)
#req is the request page object.
Judging from the CherryPy documentation, all I need to do to start a session is modify the config by adding something like the following:
cherrypy.config.update({
'tools.sessions.on': True,
'tools.sessions.storage_type': 'ram'})
The above defaults to a time of 60 minutes (though you can manually set your own), but what if I want to destroy that session and make a new one? Do, I call cherrypy.lib.sessions.expire() in any arbitrary file and then do the cherrypy.config.update thing again? Or, will CherryPy make a new session by itself? What if I want to make a new session with a different expiry time?
Note: When I say arbitrary file, I mean a file that is not running CherryPy (My "config" file imports and gets html back from our other pages much like the standard Publisher that comes with Mod_Python).
I tried making a quick little test file:
import cherrypy
from cherrypy.lib import sessions
def index(sid=0, secret=None, timeout=30, lock=1):
cherrypy.session['test'] = 'test'
cherrypy.lib.sessions.expire()
return cherrypy.session.get('test','None')
The end result is that 'test' is still displayed on the screen. Is this happening because the client side session is expired, but the local one still has data? In that case, how can I check if a session expired or not?
Sorry for the confusing question, but I am confused.
Thanks for all your help!
Try this to end a session.
sess = cherrypy.session
sess['_cp_username'] = None
and try this to create a session...
cherrypy.session.regenerate()
cherrypy.session['_cp_username'] = cherrypy.request.login
I used this example to handle most of my session activity.
http://tools.cherrypy.org/wiki/AuthenticationAndAccessRestrictions
Hope this helps,
Andrew