Closed GGross5213 closed 9 years ago
I'm not sure exactly what you're doing, but here's an example of how it works:
from parse_rest.connection import SessionToken, register
from parse_rest.user import User
# First, get a session token. This is probably the easiest way:
register(APPLICATION_ID, REST_API_KEY)
token = User.login(USERNAME, PASSWORD).sessionToken
# Then, you can either use that token in a block, like so:
with SessionToken(token):
me = User.current_user()
# or use it globally, like so:
register(APPLICATION_ID, REST_API_KEY, session_token=token)
me = User.current_user()
Feel free to reopen if this doesn't work for you.
This should still work when the session token is saved into our own local session, correct?
I do the following:
class LoginPage(BaseHandler):
def get(self):
self.render_template("login.html")
@uses_parse_master
def post(self):
email = self.request.get('email')
password = self.request.get('password')
u = User.login(email, password)
logging.info("session: " + str(self.session))
logging.info("parse session: " + str(u.sessionToken))
# To set a value into our session:
self.session[SESSION_TOKEN_KEY] = u.sessionToken
logging.info("sessionToken put into session dict: " + str(u.sessionToken))
self.display_message("You are logged in..." + str(u.sessionToken) +"<br><br>" + "<a href='/thing'>go to thing</a>")
def user_required(handler):
"""
Decorator that checks if there's a user associated with the current session.
Will also fail if there's no session present.
"""
#user_required registers the parse app itself so it doesn't need to
#decorate wth uses_parse_master. Think of it as a superset.
def check_login(self, *args, **kwargs):
logging.exception("checking login... to login with session key")
if not SESSION_TOKEN_KEY in self.session or not self.session[SESSION_TOKEN_KEY]:
self.redirect(self.uri_for('login'), abort=True)
else:
logging.info("sending parse session key: " + str(self.session[SESSION_TOKEN_KEY]))
register(APPLICATION_ID, REST_API_KEY, master_key=MASTER_KEY, session_token=self.session[SESSION_TOKEN_KEY])
return handler(self, *args, **kwargs)
return check_login
I've verified that the parse session key is printing when we register, matches what was saved, and matches the session token in Parse that is still not expired.
But, after the decorator executes, we still get the 101 invalid session error when trying to grab the user.
class UsefulThing(BaseHandler):
@user_required
def get(self):
self.display_message("this is useful thing...." + str(User.current_user()))
Actually, let's simply that all a bit :)
I get an invalid key even when trying to pull the session directly after login. (The decorator uses_parse_master does our register call without a session key.)
class LoginPage(BaseHandler):
def get(self):
self.render_template("login.html")
@uses_parse_master
def post(self):
email = self.request.get('email')
password = self.request.get('password')
u = User.login(email, password)
logging.info("session: " + str(self.session))
logging.info("parse session: " + str(u.sessionToken))
logging.info("parse session type: " + type(u.sessionToken).__name__)
# To set a value into our session:
#self.session[SESSION_TOKEN_KEY] = u.sessionToken
#logging.info("sessionToken put into session dict: " + str(u.sessionToken))
with SessionToken(u.sessionToken):
me = User.current_user()
logging.info("current user is...." + str(me))
self.display_message("You are logged in..." + str(u.sessionToken) +"<br><br>" + "<a href='/thing'>go to thing</a>")
the User.current_user()
throws the ResourceRequestNotFound: {"code":101,"error":"invalid session"}
error.
File "/Users/snip/Documents/Projects/guestbook/guestbook.py", line 162, in post
me = User.current_user()
File "/Users/snip/Documents/Projects/guestbook/lib/parse_rest/user.py", line 97, in current_user
return cls(**User.GET(user_url))
File "/Users/snip/Documents/Projects/guestbook/lib/parse_rest/connection.py", line 133, in GET
return cls.execute(uri, 'GET', **kw)
File "/Users/snip/Documents/Projects/guestbook/lib/parse_rest/connection.py", line 127, in execute
raise exc(e.read())
ResourceRequestNotFound: {"code":101,"error":"invalid session"}
This is in a Google App Engine project, should that prove to be a useful bit of information!
The code in your simplified example seems to be not valid. At the very least, there's some indentation issues. In any case, I simplified it down, and removed App Engine specific code, and ended up with this example, which works for me:
from parse_rest.connection import SessionToken, register
from parse_rest.user import User
register(APPLICATION_ID, REST_API_KEY)
u = User.login(USERNAME, PASSWORD)
print("parse session: " + str(u.sessionToken))
print("parse session type: " + type(u.sessionToken).__name__)
with SessionToken(u.sessionToken):
me = User.current_user()
print("current user is...." + str(me))
print("You are logged in..." + str(u.sessionToken))
In this case, the with SessionToken
block is actually redundant. Calling User.login
will update the current user.
A good use case for the with SessionToken
syntax is storing Parse session tokens between requests.
For example, a user logs in to your app, which initiates a login with their user to Parse. Your app now has a Parse session token for that user. Your app stores that session token in it's own datastore. The next time the user requests a page from your own app, you simply wrap the requests to Parse in a with SessionToken
block, and supply the stored token.
You could also do other things with it, such as have some app logged in as two users simultaneously, and operate on one user at a time within these blocks.
Agreed that the with SessionToken
in this case is redundant, but I was just trying to nail down an example that was shorter and not working. We're trying to store the session token and use it on another request, but we get the invalid session error then as well.
I will explore some possible GAE library conflicts and report back if that was the cause.
I never figured out what my problem was. I ended up just using the python requests library and calling the parse REST API directly.
Tracked it down, here are the layers:
connection.py
has the following code to add the session token and master key headers depending on what should go in the request: if ACCESS_KEYS.get('session_token'):
request.add_header('X-Parse-Session-Token', ACCESS_KEYS.get('session_token'))
if master_key and 'X-Parse-Session-Token' not in headers.keys():
request.add_header('X-Parse-Master-Key', master_key)
X-parse-session-token
(different capitalization) so the master key gets added to the request.I changed that snippet of code in connection.py
, around line 111 to:
if ACCESS_KEYS.get('session_token'):
request.add_header('X-Parse-Session-Token', ACCESS_KEYS.get('session_token'))
elif master_key:
request.add_header('X-Parse-Master-Key', master_key)
And all is working now.
(Apologies for any indentation issues, I'm working on this code via screensharing, and I think some of the indentation gets mucked up in the various passing around. The change should be obvious despite any copy/paste problems.)
That's a great fix @codegoddesskh- I've tried it in 70d5343. I'll hold off closing the issue until I've confirmed it works in other scenarios (I've been bit by this behavior a few times recently, actually)
Thanks for the quick response and confirmation. I'll keep an eye out for anything wacky happening too.
Maybe I'm missing something but even after using the fix in commit 70d5343 I still can't get User.current_user()
or any authenticated call such as user = User.Query.get(objectId=userId)
to work for me. I have the user log in client side via the Parse.FacebookUtils.logIn()
Javascript method. Within the success block of that function I store the user's session token using the Django database-backed sessions.
Then later on, possibly after the user has navigated to a few different pages, I call:
token = request.session['session_token']
with SessionToken(token):
user = User.current_user()
With this code, I get a ResourceRequestLoginRequired: {"error":"unauthorized"}
error.
I never log the user in server-side with a call to User.login()
, but if I had them login client side and I am using the valid Parse Session Token for that login, I should not be running into this problem. Correct?
Asking this just in case: Did you remember to call register with your application ID and API key?
Yeah, same as above I even tried changing it to the redundant:
register(...., session_token = token)
with SessionToken(token):
user = User.current_user()
And I still get the same error.
Everything you're describing sounds reasonable and like it should work.
I did a little digging on {"error":"unauthorized"}
which should be error information bubbled up directly from the Parse REST API.
Results point to possibly a wrong or changed API key. https://www.parse.com/questions/i-receive-errorunauthorized-for-rest-api-login https://www.parse.com/questions/getting-errorunauthorizederrorunauthorizederrorunauthorized https://www.parse.com/questions/401-unauthorized-error-with-parse-rest-api
Thank you! That's exactly what it was!
My REST API key was changed. I saw those posts about a wrong app ID, and after verifying my app ID was correct I didn't even check the the REST API key. Thanks again!
Yay! :) Glad I could help.
To prevent this tread from ending up a mile long, I'm locking the issue. Please open a new issue if you have any other trouble with User.current_user() as it's not likely to be directly related to the discussion here.
Traceback (most recent call last): File "app-test.py", line 152, in test_session_token me = User.current_user() File "/usr/local/lib/python2.7/dist-packages/parse_rest/user.p current_user return cls(**User.GET(user_url)) File "/usr/local/lib/python2.7/dist-packages/parse_rest/connec 30, in GET return cls.execute(uri, 'GET', **kw) File "/usr/local/lib/python2.7/dist-packages/parse_rest/connec 24, in execute raise exc(e.read()) ResourceRequestNotFound: {"code":101,"error":"invalid session"}
This is the error I keep getting. I have tried doing the login and then immediately using the Session Token to get the current user and it never works. Can someone please help?