I'm using GoogleAppEngine to try to make a simple app that requires logging in with Twitter. My problem is that when I redirect the user to some type of "confirmation" page- /profile in my case- I'm getting a badkey error because I saved the users authentication data into my db.Model.
import logging
import webapp2
from google.appengine.ext import db
from google.appengine.ext.webapp import template
import urlparse
import oauth2 as oauth
consumer_key='MY_CONSUMER_KEY'
consumer_secret='SECRET_KEY'
request_token_url='https://api.twitter.com/oauth/request_token'
access_token_url='https://api.twitter.com/oauth/access_token'
authorize_url='https://api.twitter.com/oauth/authorize'
consumer=oauth.Consumer(consumer_key,consumer_secret)
client = oauth.Client(consumer)
screenname = ''
class Profile(db.Model):
twitter_id = db.StringProperty()
access_token = db.StringProperty()
access_token_secret = db.StringProperty()
twitter_user_name = db.StringProperty()
class MainHandler(webapp2.RequestHandler):
def get(self):
self.response.out.write(template.render("login.html", {}))
class SignInWithTwitter(webapp2.RequestHandler):
def get(self):
resp, content = client.request(request_token_url, "GET")
self.request_token = dict(urlparse.parse_qsl(content))
self.redirect((authorize_url +'?oauth_token='+ self.request_token['oauth_token']))
class ProfilePage(webapp2.RequestHandler):
def get(self):
logging.info("tst" + screenname)
self.profile = Profile.get(screenname)
self.response.out.write("<h1> Hello " + self.profile.screenname +"<h1>")
class AuthorizeTwitter(webapp2.RequestHandler):
def get(self):
oauth_verifier = self.request.get("oauth_verifier")
token = oauth.Token(self.request.get('oauth_token'), self.request.get('oauth_token_secret'))
token.set_verifier(oauth_verifier)
client = oauth.Client(consumer, token)
resp, content = client.request(access_token_url, "POST")
access_token = dict(urlparse.parse_qsl(content))
oauth_token = access_token['oauth_token']
oauth_token_secret = access_token['oauth_token_secret']
userid = access_token['user_id']
global screenname
screenname = access_token['screen_name']
logging.info(screenname)
profile = Profile.get_by_key_name(screenname)
if profile is None:
profile = Profile(key_name = screenname)
profile.twitter_id = userid
profile.access_token = oauth_token
profile.access_token_secret = oauth_token_secret
profile.twitter_user_name = screenname
profile.save()
self.redirect("/profile")
application = webapp2.WSGIApplication([
('/', MainHandler),
('/signin', SignInWithTwitter),
('/services/twitter/authorized', AuthorizeTwitter),
('/profile', ProfilePage),
], debug=True)
login.html is simply a button that redirects you to /signin
The error I'm getting is this:
BadKeyError: Invalid string key TwitterUserNameHere===. Details: Incorrect padding
Also is there a way I can get the current profile that is logged in once I redirect my user to /profile? Or will I need to keep accessing my database using my global screenname variable
EDIT
Traceback (most recent call last):
File "/base/data/home/runtimes/python27/python27_lib/versions/third_party/webapp2-2.5.2/webapp2.py", line 1535, in __call__
rv = self.handle_exception(request, response, e)
File "/base/data/home/runtimes/python27/python27_lib/versions/third_party/webapp2-2.5.2/webapp2.py", line 1529, in __call__
rv = self.router.dispatch(request, response)
File "/base/data/home/runtimes/python27/python27_lib/versions/third_party/webapp2-2.5.2/webapp2.py", line 1278, in default_dispatcher
return route.handler_adapter(request, response)
File "/base/data/home/runtimes/python27/python27_lib/versions/third_party/webapp2-2.5.2/webapp2.py", line 1102, in __call__
return handler.dispatch()
File "/base/data/home/runtimes/python27/python27_lib/versions/third_party/webapp2-2.5.2/webapp2.py", line 572, in dispatch
return self.handle_exception(e, self.app.debug)
File "/base/data/home/runtimes/python27/python27_lib/versions/third_party/webapp2-2.5.2/webapp2.py", line 570, in dispatch
return method(*args, **kwargs)
File "/base/data/home/apps/s~howaggieru/1.371718316886323623/main.py", line 56, in get
self.profile = Profile.get(screenname)
File "/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/ext/db/__init__.py", line 1238, in get
results = get(keys, **kwargs)
File "/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/ext/db/__init__.py", line 1533, in get
return get_async(keys, **kwargs).get_result()
File "/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/ext/db/__init__.py", line 1492, in get_async
keys, multiple = datastore.NormalizeAndTypeCheckKeys(keys)
File "/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/api/datastore.py", line 178, in NormalizeAndTypeCheckKeys
keys = [_GetCompleteKeyOrError(key) for key in keys]
File "/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/api/datastore.py", line 2782, in _GetCompleteKeyOrError
key = Key(arg)
File "/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/api/datastore_types.py", line 371, in __init__
'Invalid string key %s. Details: %s' % (encoded, e))
BadKeyError: Invalid string key TwitterUsername===. Details: Incorrect padding
The traceback shows that your error is happening in ProfilePage. Now, in AuthorizeTwitter you are correctly doing profile = Profile.get_by_key_name(screenname) - but in ProfilePage you do profile = Profile.get(screenname). That assumes that "screenname" is the entire string key, which it isn't, hence the error. Use get_by_keyname there too.
Saving the screenname as a module-level global will lead you into all sorts of problems once you have more than one user at a time. Instead you should pass it around as a URL parameter: you're redirecting from the authorize handler to the profile one, so you should pass the twitter handle as a URL parameter to the profile function. The webapp2 docs show how to do that.
Related
EDIT Found my error! Leaving problem description as is, but appending answer bellow.
In my registration function, I want to create a new User object.
I've defined a User Table like this:
class User(_USERDB.Model, UserMixin):
"""
User defining Data
"""
__tablename__ = "users"
__table_args__ = {'extend_existing': True}
id = Column(Integer, primary_key=True)
mail = Column(Text, unique=True, nullable=False)
pw = Column(Text, nullable=False)
date_of_creation = Column(DateTime(timezone=True), default=datetime.now) # the date the user is created
settings = relationship("UserSettingProfile", back_populates="user", passive_deletes=True)
admin = Column(Boolean, default=False, nullable=False)
world_id = Column(Integer, nullable=True)
def __dict__(self):
return {
"id": self.id,
"mail": self.mail,
"date_of_creation": self.date_of_creation,
"admin": self.admin,
"world_id": self.world_id
}
If I now use the constructor as in other tutorials (TechWithTim - Flask Bog tutorial)
new_user = User(mail=mail, pw=pw_hash, admin=admin)
I get the error from the Title
"AttributeError: 'function' object has no attribute 'get'"
I've already tried stepping through the debugger to spot where this comes from, but it's not much more helpful than the stack trace. All I did was validate that the stack trace, is the stack trace (not very helpful indeed)
Traceback (most recent call last):
File "E:\project\venv\Lib\site-packages\flask\app.py", line 2091, in __call__
return self.wsgi_app(environ, start_response)
File "E:\project\venv\Lib\site-packages\flask\app.py", line 2076, in wsgi_app
response = self.handle_exception(e)
File "E:\project\venv\Lib\site-packages\flask\app.py", line 2073, in wsgi_app
response = self.full_dispatch_request()
File "E:\project\venv\Lib\site-packages\flask\app.py", line 1518, in full_dispatch_request
rv = self.handle_user_exception(e)
File "E:\project\venv\Lib\site-packages\flask\app.py", line 1516, in full_dispatch_request
rv = self.dispatch_request()
File "E:\project\venv\Lib\site-packages\flask\app.py", line 1502, in dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)
File "E:\project\web_interface\routes\api_routing.py", line 135, in register
new_user = User(mail=mail, pw=pw_hash, admin=admin)
File "<string>", line 4, in __init__
File "E:\project\venv\Lib\site-packages\sqlalchemy\orm\state.py", line 479, in _initialize_instance
with util.safe_reraise():
File "E:\project\venv\Lib\site-packages\sqlalchemy\util\langhelpers.py", line 70, in __exit__
compat.raise_(
File "E:\project\venv\Lib\site-packages\sqlalchemy\util\compat.py", line 207, in raise_
raise exception
File "E:\project\venv\Lib\site-packages\sqlalchemy\orm\state.py", line 477, in _initialize_instance
return manager.original_init(*mixed[1:], **kwargs)
File "E:\project\venv\Lib\site-packages\sqlalchemy\orm\decl_base.py", line 1157, in _declarative_constructor
setattr(self, k, kwargs[k])
File "E:\project\venv\Lib\site-packages\sqlalchemy\orm\attributes.py", line 459, in __set__
self.impl.set(
File "E:\project\venv\Lib\site-packages\sqlalchemy\orm\attributes.py", line 1094, in set
old = dict_.get(self.key, NO_VALUE)
AttributeError: 'function' object has no attribute 'get'
For completion's sake, here is my api_routing.py file:
from flask import Blueprint, request, jsonify
from database import User, UserSettingProfile
#api_routes.route("/register", methods=["POST"])
def register():
response = {"message": ""}
try:
mail = request.values["mail"]
pw1 = request.values["pw1"]
pw2 = request.values["pw2"]
except KeyError as e:
response["message"] = f"{e=} | Missing argument. Expected: mail, password1, password2"
return jsonify(response), 400
admin = False
pw_hash = hash_pw(pw1)
print(f"{pw_hash=}\n{mail=}\n{admin=}")
new_user = User(mail=mail, pw=pw_hash, admin=admin)
print(new_user)
new_user_settings = UserSettingProfile(user_id=new_user.id)
_USERDB.session.add(new_user)
_USERDB.session.add(new_user_settings)
_USERDB.session.commit()
login_user(new_user, remember=True)
response["message"] = f"{mail=} registered and logged in successfully"
return jsonify(response), 200
All the parameters that I pass on into the User() constructor are valid and as expected:
pw_hash='$2b$14$6UpznQzJgw/zLZLGmjBkfOpm.D8iGXf/OsfqRkAVyzcZFM88kdos2'
mail='test_mail'
admin=False
After looking at other posts, I double-checked:
The name "User" in the namespace indeed maps to the model-class I defined.
Answer
The reason it fails is thanks to the __dict__ method. Since the removal of it, everything works fine.
Of course this leads to the next question: How to define custom dict functions for those classes
I couldn't find an answer to this but still want to offer a solution:
Define a custom function that takes the required obj as a parameter and then puts the wanted fields into a dict. Not the most elegant solution IMO but it works.
I'm trying to use Authlib library to access new eBay REST API (as Authorization code grant)
Here is my code;
import json
import os
import webbrowser
from time import time
from authlib.integrations.requests_client import OAuth2Session
from rpi_order_data_sync import settings
def auth(seller):
def token_updater(token, seller=seller):
if not os.path.exists(seller):
open(seller, "w").close()
with open(seller, "w") as token_file:
json.dump(token, token_file)
scope = ["https://api.ebay.com/oauth/api_scope/sell.fulfillment.readonly"]
if not os.path.exists(seller):
ebay = OAuth2Session(
settings.E_APP_ID,
settings.E_CERT_ID,
redirect_uri=settings.E_RU_NAME,
scope=scope,
)
uri, state = ebay.create_authorization_url(
"https://auth.sandbox.ebay.com/oauth2/authorize",
)
print("Please go to {} and authorize access.".format(uri))
try:
webbrowser.open_new_tab(uri)
except webbrowser.Error:
pass
authorization_response = input("Please enter callback URL: ") # nosec
token = ebay.fetch_token(
"https://api.sandbox.ebay.com/identity/v1/oauth2/token",
authorization_response=authorization_response,
)
print(token)
token_updater(token)
return ebay
The problem is eBay's token response has an unconventional token type named "User Access Token" instead of "Bearer". Therefore I get this error;
Traceback (most recent call last):
File "/home/thiras/.local/share/virtualenvs/rpi-order-data-sync-tA0i1rrc/lib/python3.8/site-packages/authlib/integrations/requests_client/oauth2_session.py", line 37, in __call__
req.url, req.headers, req.body = self.prepare(
File "/home/thiras/.local/share/virtualenvs/rpi-order-data-sync-tA0i1rrc/lib/python3.8/site-packages/authlib/oauth2/auth.py", line 91, in prepare
sign = self.SIGN_METHODS[token_type.lower()]
KeyError: 'user access token'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/thiras/.local/share/virtualenvs/rpi-order-data-sync-tA0i1rrc/bin/rods", line 11, in <module>
load_entry_point('rpi-order-data-sync', 'console_scripts', 'rods')()
File "/home/thiras/.local/share/virtualenvs/rpi-order-data-sync-tA0i1rrc/lib/python3.8/site-packages/click/core.py", line 829, in __call__
return self.main(*args, **kwargs)
File "/home/thiras/.local/share/virtualenvs/rpi-order-data-sync-tA0i1rrc/lib/python3.8/site-packages/click/core.py", line 782, in main
rv = self.invoke(ctx)
File "/home/thiras/.local/share/virtualenvs/rpi-order-data-sync-tA0i1rrc/lib/python3.8/site-packages/click/core.py", line 1259, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
File "/home/thiras/.local/share/virtualenvs/rpi-order-data-sync-tA0i1rrc/lib/python3.8/site-packages/click/core.py", line 1066, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/home/thiras/.local/share/virtualenvs/rpi-order-data-sync-tA0i1rrc/lib/python3.8/site-packages/click/core.py", line 610, in invoke
return callback(*args, **kwargs)
File "/home/thiras/HDD/freelancer/contentassasin/rpi-order-data-sync/rpi_order_data_sync/main.py", line 132, in sync_ebay_orders
orders = ebay.get(
File "/home/thiras/.local/share/virtualenvs/rpi-order-data-sync-tA0i1rrc/lib/python3.8/site-packages/requests/sessions.py", line 543, in get
return self.request('GET', url, **kwargs)
File "/home/thiras/.local/share/virtualenvs/rpi-order-data-sync-tA0i1rrc/lib/python3.8/site-packages/authlib/integrations/requests_client/oauth2_session.py", line 113, in request
return super(OAuth2Session, self).request(
File "/home/thiras/.local/share/virtualenvs/rpi-order-data-sync-tA0i1rrc/lib/python3.8/site-packages/requests/sessions.py", line 516, in request
prep = self.prepare_request(req)
File "/home/thiras/.local/share/virtualenvs/rpi-order-data-sync-tA0i1rrc/lib/python3.8/site-packages/requests/sessions.py", line 449, in prepare_request
p.prepare(
File "/home/thiras/.local/share/virtualenvs/rpi-order-data-sync-tA0i1rrc/lib/python3.8/site-packages/requests/models.py", line 318, in prepare
self.prepare_auth(auth, url)
File "/home/thiras/.local/share/virtualenvs/rpi-order-data-sync-tA0i1rrc/lib/python3.8/site-packages/requests/models.py", line 549, in prepare_auth
r = auth(self)
File "/home/thiras/.local/share/virtualenvs/rpi-order-data-sync-tA0i1rrc/lib/python3.8/site-packages/authlib/integrations/requests_client/oauth2_session.py", line 41, in __call__
raise UnsupportedTokenTypeError(description=description)
authlib.integrations.base_client.errors.UnsupportedTokenTypeError: unsupported_token_type: Unsupported token_type: 'user access token'
I've noticed Compliance fix for non-standard section at Authlib documentation but couldn't figure out how to do this fix or even possible in this way.
I've found a solution and it also works with requests-oauthlib package. It seems working flawlessly so far. The main struggle was to create a fake request.Response model since request.Response has no setter for .text or .content attributes so modifying them was impossible.
So I've created a FakeResponse class that only mimics .json() method since it was the only method used by Authlib.
class FakeResponse:
""" Fake Class for Request Response class. """
def __init__(self, data):
self.data = data
def json(self):
""" Mocks requests.Response.json(). """
return self.data
After that I've created an access_token_response hook;
def non_compliant_token_type(resp):
data = resp.json()
data["token_type"] = "Bearer"
fake_resp = FakeResponse(data=data)
return fake_resp
Please let me know if you have a better answer or any recommendations to improve it.
This question already has answers here:
How to get POSTed JSON in Flask?
(13 answers)
Closed 6 years ago.
I am creating an ios app that uses a server written in flask + python, and when I make a connection to the server to register a user I keep getting a 'NoneType' object is not subscriptable error in my server.py file. Basically my question is what is causing this error and how am I able to fix this. Also if anyone can point me in the right direction of different or easier ways to do this I would appreciate it thanks!
Here is the server.py file:
import bcrypt
from flask import Flask, request, make_response,jsonify
from flask_restful import Resource, Api
from pymongo import MongoClient
from json import JSONEncoder
from bson.objectid import ObjectId
from functools import wraps
app = Flask(__name__)
mongo = MongoClient('localhost', 27017)
app.db = mongo.eventure_db
app.bcrypt_rounds = 12
api = Api(app)
# Authentication code.
def check_auth(username, password):
# check_auth should access the database and check if the username + password are correct.
# create a collection to hold the users.
user_collection = app.db.users
user = user_collection.find_one({'username': username})
if user is None:
return False
else:
# check if hash generated matches stored hash
encodedPassword = password.encode('utf-8')
if bcrypt.hashpw(encodedPassword, user['password']) == user['password']:
return True
else:
return False
# User resource
class User(Resource):
def post(self):
if (request.json['username'] == None
or request.json['password'] == None):
return ({'error': 'Request requires username and password'},
400,
None)
user_collection = app.db.users
user = user_collection.find_one({'username': request.json['username']})
if user is not None:
return ({'error': 'Username already in use'}, 400, None)
else:
encodedPassword = request.json['password'].encode('utf-8')
hashed = bcrypt.hashpw(
encodedPassword, bcrypt.gensalt(app.bcrypt_rounds))
request.json['password'] = hashed
user_collection.insert_one(request.json)
#requires_auth
def get(self):
return (None, 200, None)
api.add_resource(User, '/eventure/api/v1.1/user/')
# Must define a custom JSON Serializer for flask_restful
# this is because ObjectId is not a string, and therefore,
# Flask's default serializer cannot serialize it.
#api.representation('application/json')
def output_json(data, code, headers=None):
resp = make_response(JSONEncoder().encode(data), code)
resp.headers.extend(headers or {})
return resp
if __name__ == '__main__':
app.config['TRAP_BAD_REQUEST_ERRORS'] = True
app.run(host='localhost', port=8789, debug=True)
And this is my register function in swift:
#IBAction func register(_ sender: AnyObject) {
let url = URL(string: "http://localhost:8789/eventure/api/v1.1/user/")
var request = URLRequest(url: url!)
request.httpMethod = "POST"
request.setValue(generateBasicAuthHeader(username: username.text!, password: password.text!), forHTTPHeaderField: "Authorization")
let session = URLSession.shared
let task = session.dataTask(with: request) { data, response, error in
if let response = response, let data = data {
print(String(data: data, encoding: String.Encoding.utf8))
}
}
task.resume()
self.username.text = ""
self.password.text = ""
}
traceback:
[28/Oct/2016 19:22:33] "POST /eventure/api/v1.1/user/ HTTP/1.1" 500 -
Traceback (most recent call last):
File "/Users/Dynee/eventure-backend-api/development/lib/python3.5/site-packages/flask/app.py", line 1836, in __call__
return self.wsgi_app(environ, start_response)
File "/Users/Dynee/eventure-backend-api/development/lib/python3.5/site-packages/flask/app.py", line 1820, in wsgi_app
response = self.make_response(self.handle_exception(e))
File "/Users/Dynee/eventure-backend-api/development/lib/python3.5/site-packages/flask_restful/__init__.py", line 270, in error_router
return original_handler(e)
File "/Users/Dynee/eventure-backend-api/development/lib/python3.5/site-packages/flask/app.py", line 1403, in handle_exception
reraise(exc_type, exc_value, tb)
File "/Users/Dynee/eventure-backend-api/development/lib/python3.5/site-packages/flask/_compat.py", line 32, in reraise
raise value.with_traceback(tb)
File "/Users/Dynee/eventure-backend-api/development/lib/python3.5/site-packages/flask/app.py", line 1817, in wsgi_app
response = self.full_dispatch_request()
File "/Users/Dynee/eventure-backend-api/development/lib/python3.5/site-packages/flask/app.py", line 1477, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/Users/Dynee/eventure-backend-api/development/lib/python3.5/site-packages/flask_restful/__init__.py", line 270, in error_router
return original_handler(e)
File "/Users/Dynee/eventure-backend-api/development/lib/python3.5/site-packages/flask/app.py", line 1381, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/Users/Dynee/eventure-backend-api/development/lib/python3.5/site-packages/flask/_compat.py", line 32, in reraise
raise value.with_traceback(tb)
File "/Users/Dynee/eventure-backend-api/development/lib/python3.5/site-packages/flask/app.py", line 1475, in full_dispatch_request
rv = self.dispatch_request()
File "/Users/Dynee/eventure-backend-api/development/lib/python3.5/site-packages/flask/app.py", line 1461, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/Users/Dynee/eventure-backend-api/development/lib/python3.5/site-packages/flask_restful/__init__.py", line 471, in wrapper
resp = resource(*args, **kwargs)
File "/Users/Dynee/eventure-backend-api/development/lib/python3.5/site-packages/flask/views.py", line 84, in view
return self.dispatch_request(*args, **kwargs)
File "/Users/Dynee/eventure-backend-api/development/lib/python3.5/site-packages/flask_restful/__init__.py", line 581, in dispatch_request
resp = meth(*args, **kwargs)
File "/Users/Dynee/eventure-backend-api/server.py", line 128, in post
if (request.json['username'] == None
TypeError: 'NoneType' object is not subscriptable
Also here is the generateBasicAuthHeader function:
func generateBasicAuthHeader(username: String, password: String) -> String {
let loginString = String(format: "%#:%#", username, password)
let loginData = loginString.data(using: String.Encoding.utf8)!
let base64LoginString = loginData.base64EncodedString()
let basicAuthHeader = "Basic \(base64LoginString)"
return basicAuthHeader
}
You need to explicitly set the content-type to application/json for request.json to work properly in flask. If the header isn't set, request.json would return None.
But the recommended to get json data in flask from a post request is to use request.get_json()
I'll also urge you to test your api with the nifty requests module before using your ios application.
>>> import requests
>>> requests.post(url, json={'name': 'hello world'})
It already sets the appropriate headers required to make a json request
If it works with the requests module, then you can be sure that it's going to work with your ios application. you just need to make sure you're setting the correct content-type.
You can forcefully tell flask to ignore the content-type header with
request.get_json(force=True)
I don't know why my project show the next cookie error. Could someone help me?
PATH
->test
->lib
->public
->templates
- app.yaml
- main.py
- client_secrets.json
- session-secret (python -c "import os;print os.urandom(64)" > session.secret)
When I use my App Engine Launcher (release: "1.7.5") and check out my localhost web page
I chose my Google account to add permissions in accounts.google.com/AccountChooser?service....... (redirect) and then accept conditions of the scopes
The log console shows the next error:
Traceback (most recent call last):
File "C:\Program Files\Google\google_appengine\lib\webapp2-2.5.2\webapp2.py", line 1535, in __call__
rv = self.handle_exception(request, response, e)
File "C:\Program Files\Google\google_appengine\lib\webapp2-2.5.2\webapp2.py", line 1529, in __call__
rv = self.router.dispatch(request, response)
File "C:\Program Files\Google\google_appengine\lib\webapp2-2.5.2\webapp2.py", line 1278, in default_dispatcher
return route.handler_adapter(request, response)
File "C:\Program Files\Google\google_appengine\lib\webapp2-2.5.2\webapp2.py", line 1102, in __call__
return handler.dispatch()
File "C:\Program Files\Google\google_appengine\lib\webapp2-2.5.2\webapp2.py", line 572, in dispatch
return self.handle_exception(e, self.app.debug)
File "C:\Program Files\Google\google_appengine\lib\webapp2-2.5.2\webapp2.py", line 570, in dispatch
return method(*args, **kwargs)
File "C:\Program Files\Google\google_appengine\pruebasDocs\main.py", line 320, in get
creds = self.GetCodeCredentials()
File "C:\Program Files\Google\google_appengine\pruebasDocs\main.py", line 194, in GetCodeCredentials
session.set_secure_cookie(name='userid', value=userid)
File "lib\sessions.py", line 160, in set_secure_cookie
self.set_cookie(name, value, expires_days=expires_days, **kwargs)
File "lib\sessions.py", line 141, in set_cookie
self.response.headers._headers.append(('Set-Cookie', str(vals.OutputString(None))))
**AttributeError: ResponseHeaders instance has no attribute '_headers'**
lo.....t:8080/?code=4/00VfZ4DJ8d0P99v1kwn0yjBofcbq.gn6ceL8RBx0XYKs_1NgQtmXj_6WohwI
MAIN.PY
def GetCodeCredentials(self):
# Other frameworks use different API to get a query parameter.
code = self.request.get('code')
if not code:
# returns None to indicate that no code was passed from Google Drive.
return None
# Auth flow is a controller that is loaded with the client information,
# including client_id, client_secret, redirect_uri etc
oauth_flow = self.CreateOAuthFlow()
# Perform the exchange of the code. If there is a failure with exchanging
# the code, return None.
try:
creds = oauth_flow.step2_exchange(code)
except FlowExchangeError:
return None
# Create an API service that can use the userinfo API. Authorize it with our
# credentials that we gained from the code exchange.
users_service = CreateService('oauth2', 'v2', creds)
# Make a call against the userinfo service to retrieve the user's information.
# In this case we are interested in the user's "id" field.
userid = users_service.userinfo().get().execute().get('id')
# Store the user id in the user's cookie-based session.
session = sessions.LilCookies(self, SESSION_SECRET)
session.set_secure_cookie(name='userid', value=userid)
SESSIONS.PY
# output all their cookies to the headers at once before a response flush.
for vals in new_cookie.values():
self.response.headers._headers.append(('Set-Cookie', vals.OutputString(None)))
i am using custom user accounts for one of my projects and am using the User model and authentication provided by webapp2. Everything runs perfect but i am stuck at the part where authentication is not successful.
For Example:
#imports
from webapp2_extras.appengine.auth.models import User
class LoginHandler(SomeBaseRequestHandler):
def get(self):
'''self code goes in here'''
def post(self):
auth_id = 'authentication:id'
password = 'somepassword'
user = User.get_by_auth_password(authid, password)
if user:
# code to set a session and redirect to homepage
else:
# append error list and render a template
I am able to login the user however the problem arises if a user provides a wrong user name or password. if the user provides any of the wrong credentials it raises a server side error.
Traceback (most recent call last):
File "/opt/google_appengine_1.6.4/lib/webapp2/webapp2.py", line 1536, in __call__
rv = self.handle_exception(request, response, e)
File "/opt/google_appengine_1.6.4/lib/webapp2/webapp2.py", line 1530, in __call__
rv = self.router.dispatch(request, response)
File "/opt/google_appengine_1.6.4/lib/webapp2/webapp2.py", line 1278, in default_dispatcher
return route.handler_adapter(request, response)
File "/opt/google_appengine_1.6.4/lib/webapp2/webapp2.py", line 1102, in __call__
return handler.dispatch()
File "/home/tigerstyle/orbit/orbit/orbit/handlers.py", line 36, in dispatch
webapp2.RequestHandler.dispatch(self)
File "/opt/google_appengine_1.6.4/lib/webapp2/webapp2.py", line 572, in dispatch
return self.handle_exception(e, self.app.debug)
File "/opt/google_appengine_1.6.4/lib/webapp2/webapp2.py", line 570, in dispatch
return method(*args, **kwargs)
File "/home/tigerstyle/orbit/orbit/orbit/handlers.py", line 239, in post
user = User.get_by_auth_password(auth_id, password)
File "/opt/google_appengine_1.6.4/lib/webapp2/webapp2_extras/appengine/auth/models.py", line 301, in get_by_auth_password
raise auth.InvalidPasswordError()
InvalidPasswordError
You can use try / except to control your login flow:
def post(self):
"""
username: Get the username from POST dict
password: Get the password from POST dict
"""
username = self.request.POST.get('username')
password = self.request.POST.get('password')
# Try to login user with password
# Raises InvalidAuthIdError if user is not found
# Raises InvalidPasswordError if provided password doesn't match with specified user
try:
self.auth.get_user_by_password(username, password)
self.redirect('/secure')
except (InvalidAuthIdError, InvalidPasswordError), e:
# Returns error message to self.response.write in the BaseHandler.dispatcher
# Currently no message is attached to the exceptions
return e