I am trying to follow the WeChat Official Account tutorial to build an app.
In the step of
1.4 Basic Configuration for Developers
After the restart is successful (python main.py 80), click the Submit button. If the prompt "token verification failed" appears,
check the code or network link. If the token is successfully verified,
you will be redirected back to the Basic Configuration page. Click
Start.
However, based on the tutorial, there is no submit button related code. I cannot find the submit button.
When I open the pages through WeChat Official Account in the app WeChat, it just shows "hello, this is handle view".
Any guide? Thanks
main.py
import web
from handle import Handle
urls = (
'/wx', 'Handle',
)
if __name__ == '__main__':
app = web.application(urls, globals())
app.run()
handle.py
import hashlib
import web
class Handle(object):
def GET(self):
try:
data = web.input()
if len(data) == 0:
return "hello, this is handle view"
signature = data.signature
timestamp = data.timestamp
nonce = data.nonce
echostr = data.echostr
token = "xxxx" #Enter the value in **Basic Configuration ** at Official Accounts Platform.
list = [token, timestamp, nonce]
list.sort()
sha1 = hashlib.sha1()
map(sha1.update, list)
hashcode = sha1.hexdigest()
print "handle/GET func: hashcode, signature: ", hashcode, signature
if hashcode == signature:
return echostr
else:
return ""
except Exception, Argument:
return Argument
I figured out the submit button here in the tutorial is referring the submit button at
https://mp.weixin.qq.com/
开发 -> 基本配置 -> 服务器配置 -> 修改配置 -> URL
After you fill the URL, that submit (提交) button.
(Unfortunately, the WeChat Official Accounts settings panel only has Mandarin language not like the developer doc. But hopefully my screenshot will help locate it.)
Related
I am using Python Flask and Spotipy to create a web application that connects to the Spotify API.
When the user logs in with Spotify, I store the OAuth2 token as a cookie so that, if they refresh the tab or close it and reopen it later (but soon enough that the cookie doesn't expire), they will stay logged in.
The Issue: If the user logs in and then refreshes the tab, they will stay logged in for as long as the cookie is valid (no matter if they close the tab). However, if the user closes the tab (without first refreshing) and then reopens it, they will be logged out again and the cookie disappears. The same thing happens if the user opens a duplicate tab. As stated before, the user should stay logged in rather than getting logged back out.
Here is my Python Flask code:
#app.route('/')
def index():
access_token = ""
expire_at = 0
url = request.url
code = sp_oauth.parse_response_code(url)
if request.cookies.get('token') is not None:
access_token = request.cookies.get('token')
if code != url:
token_info = sp_oauth.get_access_token(code)
access_token = token_info['access_token']
expire_at += token_info['expires_at']
if access_token:
sp = spotipy.Spotify(access_token)
results = sp.currently_playing()
if results is not None:
resp = make_response(render_template("record.html", url=str(results['item']['album']['images'][1]['url']), title=str(results['item']['name']),artist=str(results['item']['artists'][0]['name'])))
else:
resp = make_response(render_template("record.html", title="Play A Song On Spotify", artist="To See It Appear Here!", url=str("http://www.clker.com/cliparts/m/I/n/1/T/P/orange-dot-hi.png")))
if request.cookies.get('token') is None:
resp.set_cookie('token', access_token, expires=expire_at)
return resp
else:
return render_template("home.html", button=getSPOauthURI())
If some other code is needed to find the issue, let me know.
Thanks in advance for the help!
I use flask-assistant on python 3 with dilaogflow as a webhook. I looked at the official documentation and I don't find how to get the user message ("queryText" on dialogflow json request).
I tried this with no success:
# -*- coding: utf-8 -*-
from flask import Flask
from flask_assistant import Assistant, ask, tell, context_manager, event
project_id='myproject_id'
app = Flask(__name__)
assist = Assistant(app, route='/', project_id = project_id)
#assist.action('Default Fallback Intent')
def manage_fallback(queryText):
print('*'*40,queryText)
speech='Running'
return tell(speech)
if __name__ == '__main__':
app.run(debug=True)
The print of queryText always return None, but when I inspect on the ngrok web interface (http://127.0.0.1:4040) , I can see the request.
And I want to know how canI get the user message from flask-assistant?
I also asked about this question on github and get the answer, so I will share for the others:
You can get the query text from the flask-assistant request object.
from flask_assistant import request
...
...
#assist.action('Default Fallback Intent')
def manage_fallback():
user_query = request['queryResult']['queryText']
speech = "You said " + user_query
return tell(speech)
The reason the value of queryText expected by your manage_fallback function is None is because the parameter name must match the entity type expected by the intent.
Parameters are used to receive parsed entities for an intent, not the full user query.
I am trying to create a quick web app that authenticates into a users Yahoo account, but I am having trouble getting 'user approval'.
Yahoo Auth Page
Personally, every time I go to external website and have to authenticate, I usually log into my account. This seems to be redirecting me to a page and asking for a code. I have 0 idea what code I would need to supply in order to authenticate. And if I dont know, my users certainly wont! I am building a flask app, and I have tried to model my code around this repo.
I have added some code specifically for Yahoo, but cant seem to connect the dots. New YahooSignIn subclass in the oauth.py file below:
class YahooSignIn(OAuthSignIn):
def __init__(self):
super(YahooSignIn, self).__init__('yahoo')
self.service = OAuth2Service(
name='yahoo',
consumer_id=self.consumer_id,
consumer_secret=self.consume_secret,
authorize_url='https://api.login.yahoo.com/oauth/v2/request_auth',
access_token_url='https://api.login.yahoo.com/oauth/v2/get_token',
base_url='http://fantasysports.yahooapis.com/'
)
def authorize(self):
return redirect(self.service.get_authorize_url(
scope='email',
response_type='code',
redirect_uri=self.get_callback_url())
)
def callback(self):
def decode_json(payload):
return json.loads(payload.decode('utf-8'))
if 'code' not in request.args:
return None, None, None
oauth_session = self.service.get_auth_session(
data={'code': request.args['code'],
'grant_type': 'authorization_code',
'redirect_uri': self.get_callback_url()},
decoder=decode_json
)
me = oauth_session.get('me?fields=id,email').json()
return (
'yahoo$' + me['id'],
me.get('email').split('#')[0],
me.get('email')
)
The only other change made was to the index.html page to add an additional link with a 'yahoo' parameter
<p>Login with Yahoo</p>
Any help would be greatly appreciated as this one has stumped me the last two nights and I would love to move past this!
Previous to this year (2018/19) I had been using Yahoo's Oauth 1.0 API. This year I ran into problems using it so I switched to using Oauth 2.0 via the yahoo-oauth library linked below. They have a nice page that describes how to use their library. Here is the code that I used.
from yahoo_oauth import OAuth2
class YahooFantasyAPI:
def fetchGameID(self):
session = self.getSession()
r = session.get(
'https://fantasysports.yahooapis.com/fantasy/v2/game/nfl'
)
print(r.text)
def getSession(self):
oauth = OAuth2(None, None, from_file='oauth2.json')
if not oauth.token_is_valid():
oauth.refresh_access_token()
return oauth.session
api = YahooFantasyAPI()
fetchGameID()
https://yahoo-oauth.readthedocs.io/en/latest/
How do I update FB Status using Python & GraphAPI? This question has been asked before, but many of the solutions have been deprecated and the requirement of GraphAPI seems to have rendered many solutions irrelevant.
I have fiddled around with the fbpy, Facebook, OAuth, and oauth2 packages, and have looked through their examples, but I still cannot figure out how to get them working. I have no trust in any of the code or the packages I have been using and am wondering if anyone has any definitive solutions that they know will work.
First you need to do is understand login flows. You should understand if you easily want to switch through the different Facebook libraries. Therefore it can have code that is very verbose to code that is very simple based on implementation.
The next thing is that there are different ways to implement handling OAuth and different ways to display and launch your web app in Python. There is no way to authorize without hitting a browser. Otherwise you would have to keep copy pasting the access_token to the code.
Let's say you chose web.py to handle your web app presentation and requests.py to handle the Graph API HTTP calls.
import web, requests
Then setup the URL we want all request to go through
url = (
'/', 'index'
)
Now get your application id, secret and post-login URL you would like to use
app_id = "YOUR_APP_ID"
app_secret = "APP_SECRET"
post_login_url = "http://0.0.0.0:8080/"
This code will have one class index to handle the logic. In this class we want to deal with the authorization code Facebook will return after logging in
user_data = web.input(code=None)
code = user_data.code
From here setup a conditional to check the code
if not code:
# we are not authorized
# send to oauth dialog
else:
# authorized, get access_token
Within the "not authorized" branch, send the user to the dialog
dialog_url = ( "http://www.facebook.com/dialog/oauth?" +
"client_id=" + app_id +
"&redirect_uri=" + post_login_url +
"&scope=publish_stream" )
return "<script>top.location.href='" + dialog_url + "'</script>"
Else we can extract the access_token using the code received
token_url = ( "https://graph.facebook.com/oauth/access_token?" +
"client_id=" + app_id +
"&redirect_uri=" + post_login_url +
"&client_secret=" + app_secret +
"&code=" + code )
response = requests.get(token_url).content
params = {}
result = response.split("&", 1)
for p in result:
(k,v) = p.split("=")
params[k] = v
access_token = params['access_token']
From here you can choose how you want to deal with the call to update the status, for example a form,
graph_url = ( "https://graph.facebook.com/me/feed?" +
"access_token=" + access_token )
return ( '<html><body>' + '\n' +
'<form enctype="multipart/form-data" action="' +
graph_url + ' "method="POST">' + '\n' +
'Say something: ' + '\n' +
'<input name="message" type="text" value=""><br/><br/>' + '\n' +
'<input type="submit" value="Send"/><br/>' + '\n' +
'</form>' + '\n' +
'</body></html>' )
Or using face.py
from facepy import GraphAPI
graph = GraphAPI(access_token)
try:
graph.post(
path = 'me/feed',
message = 'Your message here'
)
except GraphAPI.OAuthError, e:
print e.message
So in the end you can get a slimmed down version like
import web
from facepy import GraphAPI
from urlparse import parse_qs
url = ('/', 'index')
app_id = "YOUR_APP_ID"
app_secret = "APP_SECRET"
post_login_url = "http://0.0.0.0:8080/"
user_data = web.input(code=None)
if not user_data.code:
dialog_url = ( "http://www.facebook.com/dialog/oauth?" +
"client_id=" + app_id +
"&redirect_uri=" + post_login_url +
"&scope=publish_stream" )
return "<script>top.location.href='" + dialog_url + "'</script>"
else:
graph = GraphAPI()
response = graph.get(
path='oauth/access_token',
client_id=app_id,
client_secret=app_secret,
redirect_uri=post_login_url,
code=code
)
data = parse_qs(response)
graph = GraphAPI(data['access_token'][0])
graph.post(path = 'me/feed', message = 'Your message here')
For more info see
* Facebook API - User Feed: http://developers.facebook.com/docs/reference/api/user/#feed
* Publish a Facebook Photo in Python – The Basic Sauce: http://philippeharewood.com/facebook/publish-a-facebook-photo-in-python-the-basic-sauce/
* Facebook and Python – The Basic Sauce: http://philippeharewood.com/facebook/facebook-and-python-the-basic-sauce/
One possible (tested!) solution using facepy:
Create a new application or use an existing one previously created.
Generate a user access token using the Graph API explorer with the status_update extended permission for the application.
Use the user access token created in the previous step with facepy:
from facepy import GraphAPI
ACCESS_TOKEN = 'access-token-copied-from-graph-api-explorer-on-web-browser'
graph = GraphAPI(ACCESS_TOKEN)
graph.post('me/feed', message='Hello World!')
You can try this blog too. It's using fbconsole app.
The code from the blog:
from urllib import urlretrieve
import imp
urlretrieve('https://raw.github.com/gist/1194123/fbconsole.py', '.fbconsole.py')
fb = imp.load_source('fb', '.fbconsole.py')
fb.AUTH_SCOPE = ['publish_stream']
fb.authenticate()
status = fb.graph_post("/me/feed", {"message":"Your message here"})
This is how I got it to work. You absolutely don't need to create any app for this. I'll describe how to post status updates to your profile and to a facebook page of yours.
First, to post a status update to your profile:
Go to https://developers.facebook.com/tools/explorer.
You'll see a textbox with Access Token written before it. Click on the button 'Get Access Token' beside this textbox. It will open a pop up asking you for various permissions for the access token. Basically these permissions define what all you can do through the Graph API using this token. Check the tick boxes beside all the permissions you need one of which will be updating your status.
Now go ahead and install the facepy module. Best way would be to use pip install.
After this pase the following code snippet in any .py file:
from facepy import GraphAPI
access_token = 'YOUR_GENERATED_ACCESS_TOKEN'
apiConnection = GraphAPI(access_token)
apiConnection.post(path='me/feed',
message='YOUR_DESIRED_STATUS_UPDATE_HERE')
Now execute this .py file the standard python way and check your facebook. You should see YOUR_DESIRED_STATUS_UPDATE_HERE posted to your facebook profile.
Next, to do the same thing with a facebook page of yours:
The procedure is almost exactly the same except for generating your access token.
Now you can't use the same access token to post to your facebook page. You need to generate a new one, which might be a little tricky for someone new to the Graph API. Here's what you need to do:
Go to the same developers.facebook.com/tools/explorer page.
Find a dropdown showing 'Graph API Explorer' and click on it. From the dropdown, select your page you want to post updates from. Generate a new access token for this page. The process is described here: . Do not forget to check the manage_pages permission in the extended permissions tab.
Now use this token in the same code as you used earlier and run it.
Go to your facebook page. You should YOUR_DESIRED_STATUS_UPDATE posted to your page.
Hope this helps!
I would like to enable the visitors of my website to login using their Google Accounts instead of having to sign up and create a new one.
A few things:
I am NOT using the Django authentication framework, instead, I do my own authentication and keep information about users in my own set of tables
consequently, various django-openid libs are not applicable since they all assume that the standard Django auth framework is used.
I tried to study the python-openid library + the google federated login API but I am lost. I get as close as to understand the instantiating the Consumer class but do not understand the session and store params required. I cannot fathom something that seems so easy can be so complicated. Is there really no step by step tutorial of how to do this in pure python or django?
I tried to look at the examples/consumer.py within the python-openid but it's 500lines of code again that I do not understand.
I also don't understand how verification of the user against google accounts is done on every request to my website. Google API only explains initial login steps. What happens on every request to my website where authentication must be verified against a google server?
I think your problem stems from a basic misunderstanding of how OpenID and/or OAuth work.
It looks like you just want authentication, so let's stick to OpenID for now. You are correct to look at existing libraries. python-openid is the one to use if you only need OpenID and not OAuth, and you are not using Django's built-in auth framework.
The full documentation for Federated Login with OpenID and OAuth is here: http://code.google.com/apis/accounts/docs/OpenID.html . In particular, look at the diagram under "Interaction sequence".
First, here is a very good working example from Facebook's Tornado web server's auth module:
https://github.com/facebook/tornado/blob/master/tornado/auth.py
(grep that for "GoogleHandler". I've used it with great success.)
This is independent of Django and Django auth, and should give you a good example of how to implement what you want. If that's still not enough, read on...
You said django-openid is irrelevant, but in fact it demonstrates an implementation of exactly what you want, but for Django's auth system instead of yours. Actually, you should look at the similar plugin, Django-SocialAuth, which implements OpenID + OAuth for a few different providers (Google, Facebook, Twitter, etc.). In particular, look at:
https://github.com/agiliq/Django-Socialauth/blob/master/socialauth/lib/oauthgoogle.py
and
https://github.com/agiliq/Django-Socialauth/tree/master/openid_consumer
and
https://github.com/agiliq/Django-Socialauth/tree/master/example_project
...for a full working example using django's auth framework, and can be adapted to your custom auth framework.
Best of luck. I encourage you to document whatever ends up working for you and build a step-by-step guide for others like you.
Federated Login for Google Account Users
django-openid
django-socialauth
I have managed to demistify the problem so here is the solution and I hope someone else can benefit from it:
1) Google Account verification is not done against the google accounts server on every request to your application. For example:
1.1 a user logs into your app using their gmail account
1.2 the user also navigates to gmail.com where they check their email
1.3 they log out of gmail
1.4 they remain logged into your application and can use it fully
This means you have to take care of session expiry on your end, Google account does not take care of it.
2) The core Python code I used is the following:
from openid.consumer.consumer import Consumer, \
SUCCESS, CANCEL, FAILURE, SETUP_NEEDED
from openid.consumer.discover import DiscoveryFailure
from django.utils.encoding import smart_unicode
from myapp.common.util.openid import DjangoOpenIDStore
def google_signin(request):
""" This is the view where the Google account login icon on your site points to, e.g. http://www.yourdomain.com/google-signin """
consumer = Consumer(request.session, DjangoOpenIDStore())
# catch Google Apps domain that is referring, if any
_domain = None
if 'domain' in request.POST:
_domain = request.POST['domain']
elif 'domain' in request.GET:
_domain = request.GET['domain']
try:
# two different endpoints depending on whether the using is using Google Account or Google Apps Account
if _domain:
auth_request = consumer.begin('https://www.google.com/accounts/o8/site-xrds?hd=%s' % _domain)
else:
auth_request = consumer.begin('https://www.google.com/accounts/o8/id')
except DiscoveryFailure as e:
return CustomError(request, "Google Accounts Error", "Google's OpenID endpoint is not available.")
# add requests for additional account information required, in my case: email, first name & last name
auth_request.addExtensionArg('http://openid.net/srv/ax/1.0', 'mode', 'fetch_request')
auth_request.addExtensionArg('http://openid.net/srv/ax/1.0', 'required', 'email,firstname,lastname')
auth_request.addExtensionArg('http://openid.net/srv/ax/1.0', 'type.email', 'http://schema.openid.net/contact/email')
auth_request.addExtensionArg('http://openid.net/srv/ax/1.0', 'type.firstname', 'http://axschema.org/namePerson/first')
auth_request.addExtensionArg('http://openid.net/srv/ax/1.0', 'type.lastname', 'http://axschema.org/namePerson/last')
return redirect(auth_request.redirectURL('http://www.yourdomain.com', 'http://www.yourdomain.com/google-signin-response')))
#transaction.commit_manually
def google_signin_response(request):
""" Callback from Google Account service with login the status. Your url could be http://www.yourdomain.com/google-signin-response """
transaction.rollback() # required due to Django's transaction inconsistency between calls
oidconsumer = Consumer(request.session, DjangoOpenIDStore())
# parse GET parameters submit them with the full url to consumer.complete
_params = dict((k,smart_unicode(v)) for k, v in request.GET.items())
info = oidconsumer.complete(_params, request.build_absolute_uri().split('?')[0])
display_identifier = info.getDisplayIdentifier()
if info.status == FAILURE and display_identifier:
return CustomError(request, _("Google Login Error"), _("Verification of %(user)s failed: %(error_message)s") % {'user' : display_identifier, 'error_message' : info.message})
elif info.status == SUCCESS:
try:
_email = info.message.args[('http://openid.net/srv/ax/1.0', 'value.email')]
_first_name = info.message.args[('http://openid.net/srv/ax/1.0', 'value.firstname')]
_last_name = info.message.args[('http://openid.net/srv/ax/1.0', 'value.lastname')]
try:
_user = User.objects.get(email__iexact=_email)
except ObjectDoesNotExist:
# create a new account if one does not exist with the authorized email yet and log that user in
_new_user = _new_account(_email, _first_name + ' ' + _last_name, _first_name, _last_name, p_account_status=1)
_login(request, _new_user, info.message.args[('http://specs.openid.net/auth/2.0', 'response_nonce')])
transaction.commit()
return redirect('home')
else:
# login existing user
_login(request, _user, info.message.args[('http://specs.openid.net/auth/2.0', 'response_nonce')])
transaction.commit()
return redirect('home')
except Exception as e:
transaction.rollback()
system_log_entry(e, request=request)
return CustomError(request, _("Login Unsuccessful"), "%s" % e)
elif info.status == CANCEL:
return CustomError(request, _("Google Login Error"), _('Google account verification cancelled.'))
elif info.status == SETUP_NEEDED:
if info.setup_url:
return CustomError(request, _("Google Login Setup Needed"), _('Setup needed') % { 'url' : info.setup_url })
else:
# This means auth didn't succeed, but you're welcome to try
# non-immediate mode.
return CustomError(request, _("Google Login Setup Needed"), _('Setup needed'))
else:
# Either we don't understand the code or there is no
# openid_url included with the error. Give a generic
# failure message. The library should supply debug
# information in a log.
return CustomError(request, _("Google Login Error"), _('Google account verification failed for an unknown reason. Please try to create a manual account on Acquee.'))
def get_url_host(request):
if request.is_secure():
protocol = 'https'
else:
protocol = 'http'
host = escape(get_host(request))
return '%s://%s' % (protocol, host)
3) an additional lib I created and imported above (myapp.common.util.openid) is a merge of a few existing Django openID libs so kudos to those guys:
from django.db import models
from django.conf import settings
from django.utils.hashcompat import md5_constructor
from openid.store.interface import OpenIDStore
import openid.store
from openid.association import Association as OIDAssociation
import time, base64
from myapp.common.db.accounts.models import Association, Nonce
class DjangoOpenIDStore(OpenIDStore):
"""
The Python openid library needs an OpenIDStore subclass to persist data
related to OpenID authentications. This one uses our Django models.
"""
def storeAssociation(self, server_url, association):
assoc = Association(
server_url = server_url,
handle = association.handle,
secret = base64.encodestring(association.secret),
issued = association.issued,
lifetime = association.issued,
assoc_type = association.assoc_type
)
assoc.save()
def getAssociation(self, server_url, handle=None):
assocs = []
if handle is not None:
assocs = Association.objects.filter(
server_url = server_url, handle = handle
)
else:
assocs = Association.objects.filter(
server_url = server_url
)
if not assocs:
return None
associations = []
for assoc in assocs:
association = OIDAssociation(
assoc.handle, base64.decodestring(assoc.secret), assoc.issued,
assoc.lifetime, assoc.assoc_type
)
if association.getExpiresIn() == 0:
self.removeAssociation(server_url, assoc.handle)
else:
associations.append((association.issued, association))
if not associations:
return None
return associations[-1][1]
def removeAssociation(self, server_url, handle):
assocs = list(Association.objects.filter(
server_url = server_url, handle = handle
))
assocs_exist = len(assocs) > 0
for assoc in assocs:
assoc.delete()
return assocs_exist
def useNonce(self, server_url, timestamp, salt):
# Has nonce expired?
if abs(timestamp - time.time()) > openid.store.nonce.SKEW:
return False
try:
nonce = Nonce.objects.get(
server_url__exact = server_url,
timestamp__exact = timestamp,
salt__exact = salt
)
except Nonce.DoesNotExist:
nonce = Nonce.objects.create(
server_url = server_url,
timestamp = timestamp,
salt = salt
)
return True
nonce.delete()
return False
def cleanupNonce(self):
Nonce.objects.filter(
timestamp__lt = (int(time.time()) - nonce.SKEW)
).delete()
def cleaupAssociations(self):
Association.objects.extra(
where=['issued + lifetimeint < (%s)' % time.time()]
).delete()
def getAuthKey(self):
# Use first AUTH_KEY_LEN characters of md5 hash of SECRET_KEY
return md5_constructor.new(settings.SECRET_KEY).hexdigest()[:self.AUTH_KEY_LEN]
def isDumb(self):
return False
4) and the model that is required in order to hold google account session identifiers and verified endpoints:
class Nonce(models.Model):
""" Required for OpenID functionality """
server_url = models.CharField(max_length=255)
timestamp = models.IntegerField()
salt = models.CharField(max_length=40)
def __unicode__(self):
return u"Nonce: %s for %s" % (self.salt, self.server_url)
class Association(models.Model):
""" Required for OpenID functionality """
server_url = models.TextField(max_length=2047)
handle = models.CharField(max_length=255)
secret = models.TextField(max_length=255) # Stored base64 encoded
issued = models.IntegerField()
lifetime = models.IntegerField()
assoc_type = models.TextField(max_length=64)
def __unicode__(self):
return u"Association: %s, %s" % (self.server_url, self.handle)
Good luck!
Rok