本文介绍了如何添加OAuth 2.0提供程序?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我可以使用servuth OAuth2.0重现我的错误,所以它不是javascript,问题是我必须重新加载,以使登录/注销生效,我希望它工作没有javascript。我有一个想法,注销两次使注销有效,所以我可以使用自定义请求处理程序/ login和/或/ logour或只是/ sessionchange将做一个self.redirect,但它不是干净的解决方案。也许你可以看看代码,看看为什么我必须注销两次,即我必须重新加载,我可以解决这个使用一个 self.redirect ?我使用正确的方式使用Cookie,新的cookie,还是让它混合?我正在为和。如果能够提出任何建议,我会很高兴。在我删除Javascript之前,有两个相关问题的背景。而BTW我应该使用Facebook或Facebook.py类吗?我想我已经评论了旧的cookie的设置,一旦OAuth 2.0处理我的认证服务器端,这将是正确的。你可以评论还是回答?如果您可以查看和评论,请提前感谢。







  {%load i18n%} 

<?xml version =1.0encoding =utf-8?>

<!DOCTYPE html PUBLIC - // W3C // DTD XHTML 1.0 Strict // ENhttp://www.w3.org/TR/xhtml1/DTD/xhtml1-strict。 DTD>

< html xmlns =http://www.w3.org/1999/xhtml>

< head> < title> {%trans登录%}< / title>

< script type =text / javascript>

var _gaq = _gaq || [];

_gaq.push(['_ setAccount','{{analytics}}']);

_gaq.push(['_ trackPageview']);



(function(){

var ga = document.createElement('script'); ga.type ='text / javascript' ; ga.async = true;

ga.src =('https:'== document.location.protocol?'https:// ssl':'http:// www')+' .google-analytics.com / ga.js';

var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga,s);

})();

< / script>

< / head>

< body>

< div id =fb-root>< / div>

< script>

window.fbAsyncInit = function(){

FB.init({

appId:'164355773607006',// App ID

channelURL:'//WWW.KOOLBUSINESS.COM/static/channel.html',//通道文件

状态:true,//检查登录状态

cookie:true,//启用Cookie以允许服务器访问会话

oauth:true,//启用OAuth 2.0

xfbml:true //解析XFBML

});



//其他初始化代码在这里

};

//异步加载SDK

(function(d){

var js,id ='facebook-jssdk'; if(d .getElementById(id)){return;}

js = d.createElement('script'); js.id = id; js.async = true;

js .src =//connect.facebook.net/en_US/all.js;

d.getElementsByTagName('head')[0] .appendChild(js);

}(文件));

< / script>

< a href =https://www.facebook.com/dialog/oauth?client_id=164355773607006&redirect_uri=http://{{host}}>< img src = / _ / IMG / loginwithfacebook.png >< / A>

< a href =/_ah/login_redir?claimid=google.com/accounts/o8/id&continue=http://{{host}}>< img src = /_/img/loginwithgoogle.png\"></a><br>{%如果用户%}< a href ={{logout_url}}class =logout>注销Google< /一个> {%endif%}

{%if current_user%}< a href =https://www.facebook.com/logout.php?next=http://{{host }}& access_token = {{current_user.access_token}}onclick =FB.logout()>注销Facebook< / a> {%endif%}

{%if current_user%}< a href =/ logoutonclick =FB.logout();>注销Facebook JS< / a> {%endif%}

< / body>

< / html>


class BaseHandler(webapp.RequestHandler):
facebook = None
user = None
csrf_protect = True

@属性
def current_user(self):
如果没有hasattr(self,_current_user):
self._current_user = None
cookie = facebook.get_user_from_cookie(
self .request.cookies,facebookconf.FACEBOOK_APP_ID,facebookconf.FACEBOOK_APP_SECRET)
logging.debug(logging cookie+ str(cookie))
如果cookie:
#存储用户的本地实例数据,所以我们不需要
#每次请求到Facebook的往返
user = FBUser.get_by_key_name(cookie [uid])
logging.debug(user+ str(user))
logging.debug(username+ str(user.name))

如果不是用户:
graph = facebook.GraphAPI(cookie [access_token ])
profile = graph.get_object(me)
user = FBUser(key_name = str(profile [id]),
id = str(profile [id]),
name = profile [name],
profile_url = profile [link],
access_token = cookie [access_token])
user.put()
elif用户.access_token!= cookie [access_token]:
user.access_token = cookie [access_token]
user.put()
self._current_user = user
return self。 $ _ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $$$$$$$$$$ b
try:
self.init_facebook()
self.init_csrf()
self.response.headers [u'P3P'] = u'CP = HONK '#iframe cookies in IE
except Exception,ex:
self.log_exception(ex)
raise

def handle_exception(self,ex,debug_mode):
由webapp调用未处理的异常
self.log_exception(ex)
self.render(u'error',
trace = traceback.format_exc(),debug_mode = debug_mode)

def log_exception(self,ex):
内部日志处理程序以减少一些App Engine的错误噪声
msg =((str( ex)或ex .__ class __.__ name__)+
u':\\\
'+ traceback.format_exc())
如果isinstance(ex,urlfetch.DownloadError)或\
isinstance(例如,DeadlineExceededError)或\
isinstance(ex,CsrfException)或\
isinstance(ex,taskqueue.TransientError):
logging.warn(msg)
else:
logging.error(msg)

def set_co

如果值为None:
value ='deleted'
expires = datetime.timedelta(minutes = -50000)
jar = Cookie.SimpleCookie()
jar [name] = value
jar [name] ['path'] = u'/'
如果过期:
如果isinstance(expires,datetime.timedelta):
expires = datetime.datetime.now()+ expires
如果isinstance(expires,datetime.datetime):
expires = expires.strftime(' %a,%d%b%Y%H:%M:%S')
jar [name] ['expires'] = expires
self.response.headers.add_header(* jar.output ().split(u':',1))

def render(self,name,** data):
渲染模板
如果不是数据:
data = {}
data [u'js_conf'] = json.dumps({
u'appId':facebookconf.FACEBOOK_APP_ID,
u'canvasName' : F acebookconf.FACEBOOK_CANVAS_NAME,
u'userIdOnServer':self.user.id if self.user else None,
})
data [u'logged_in_user'] = self.user
data [u'message'] = self.get_message()
data [u'csrf_token'] = self.csrf_token
data [u'canvas_name'] = facebookconf.FACEBOOK_CANVAS_NAME
data [u 'current_user'] = self.current_user
data [u'user'] = users.get_current_user()
data [u'facebook_app_id'] = facebookconf.FACEBOOK_APP_ID
user = users.get_current_user )
data [u'logout_url'] = users.create_logout_url(self.request.uri)if users.get_current_user()else'https://www.facebook.com/dialog/oauth?client_id=164355773607006&redirect_uri ='+ self.request.uri
host = os.environ.get('HTTP_HOST',os.environ ['SERVER_NAME'])
data [u'host'] =主机
如果host.find('。br')> 0:
logo ='Montao.com.br'
logo_url ='/_/img/montao_small.gif'
analytics ='UA-637933-12'
domain =无
else:
logo ='Koolbusiness.com'
logo_url ='/_/img/kool_business.png'
analytics ='UA-3492973-18'
domain ='koolbusiness'

data [u'domain'] = domain
data [u'analytics'] = analytics
data [u'logo'] = logo
data [u'logo_url'] = logo_url
data [u'admin'] = users.is_current_user_admin()
如果用户:
data [u'greeting'] =(欢迎,%s!(< a href = \%s\>注销< / a>)%
(user.nickname(),users.create_logout_url(/)) )


self.response.out.write(template.render(
os.path.join(
os.path.dirname(__ file__),'templates ',name +' .html')

def init_facebook(self):

Facebook = Facebook()
user = None

#初始的Facebook请求作为一个POST签名与一个signed_request
如果u'signed_request'在self.request.POST:
facebook.load_signed_request(self.request.get('signed_request') )
#我们将方法重置为GET,因为Facebook的
#signed_request的请求是出于安全原因使用POST,尽管
#实际上是一个GET。在webapp中导致请求丢失.POST数据。
self.request.method = u'GET'
#self.set_cookie(
#'u',facebook.user_cookie,datetime.timedelta(minutes = 1440))
elif 'u'in self.request.cookies:
facebook.load_signed_request(self.request.cookies.get('u'))

#尝试加载或创建用户对象
如果facebook.user_id:
user = FBUser.get_by_key_name(facebook.user_id)
如果用户:
#更新存储access_token
如果facebook.access_token和\ $​​ b $ b facebook.access_token!= user.access_token:
user.access_token = facebook.access_token
user.put()
#刷新数据,如果我们在实时ping之后失败了
如果user.dirty:
user.refresh_data()
#如果需要,还原存储access_token
如果不是facebook.access_token:
facebook.access_token = user.access_token

如果不是用户和facebook.access_token:
我= facebook.api(你'我的' {u'fields':_USER_FIELDS})
try:
friends = [user [u'id'] for user in me [u'friends'] [u'data]]
user = FBUser(key_name = facebook.user_id,
id = facebook.user_id,friends = friends,
access_token = facebook.access_token,name = me [u'name'],
email = me.get(u'email'),picture = me [u'picture]]
user.put()
除了KeyError,ex:
pass#ignore如果不能得到最小字段

self.facebook = facebook
self.user = user

def init_csrf(self):
发出和处理CSRF令人信服的sary
self.csrf_token = self.request.cookies.get(u'c')
如果不是self.csrf_token:
self.csrf_token = str(uuid4())[ :8]
self.set_cookie('c',self.csrf_token)
如果self.request.method == u'POST'和self.csrf_protect和\ $​​ b $ b self.csrf_token! = self.request.POST.get(u'_csrf_token'):
raise CsrfException(u'Missing or invalid CSRF token。')

def set_message(self,** obj):
简单消息支持
self.set_cookie('m',base64.b64encode(json.dumps(obj))if obj else None)

def get_message(self):
获取并清除当前消息
message = self.request.cookies.get(u'm')
如果消息:
self.set_message()#清除当前cookie
return json.loads(base64.b64decode(message))



class Facebook(object):
包含Facebook特定逻辑
def __init __(self,app_id = facebookconf.FACEBOOK_APP_ID,
app_secret = facebookconf.FACEBOOK_APP_SECRET):
self.app_id = app_id
self.app_secret = app_secret
self.user_id =无
self.access_token =无
self.signed_request = {}

def api(self,path,params = None,method = u'GET',domain = u'graph'):
Make API call
如果不是params:
params = {}
params [u 'method'] = method
if u'access_token'not in params and self.access_token:
params [u'access_token'] = self.access_token
result = json.loads(urlfetch。 fetch(
url = u'https://'+ domain + u'.facebook.com'+ path,
payload = urllib.urlencode(params),
method = urlfetch.POST ,
headers = {
u'Content-Type':u应用程序/ x-www-form-urlencoded'})
.content)
如果isinstance(result,dict)和u'error'在结果中:
raise FacebookApiError(result)
返回结果

def load_signed_request(self,signed_request):
从signed_request值加载用户状态
try:
sig,payload = signed_request.split(u'。',1)
sig = self.base64_url_decode(sig)
data = json.loads(self.base64_url_decode(payload))

expected_sig = hmac.new(
self.app_secret,msg = payload,digestmod = hashlib.sha256).digest()

#允许signed_request最多工作1天
if sig == expected_sig和\ $​​ b $ b data [u'issued_at']> (time.time() - 86400):
self.signed_request = data
self.user_id = data.get(u'user_id')
self.access_token = data.get(u' oauth_token')
除了ValueError,例如:
pass#ignore如果不能分开点

@property
def user_cookie(self):
根据当前状态生成一个signed_request值
如果不是self.user_id:
return
payload = self.base64_url_encode(json.dumps({
u' user_id':self.user_id,
u'issued_at':str(int(time.time()))
sig = self.base64_url_encode(hmac.new(
self.app_secret,msg = payload,digestmod = hashlib.sha256).digest())
return sig +'。'+ payload

@staticmethod
def base64_url_decode (数据):
data = data.encode(u'ascii')
data + ='='*(4 - (len(数据) )%b $ b return base64.urlsafe_b64decode(data)

@staticmethod
def base64_url_encode(data):
return base64.urlsafe_b64encode(data).rstrip( '=')

facebook.py

 #!/ usr / bin / env python 

#版权所有2010 Facebook

#根据Apache许可证版本2.0 (许可证);您可以
#不使用此文件,除非符合许可证。您可以在

#http://www.apache.org/licenses/LICENSE-2.0

#获得
#的许可证副本根据适用法律要求或以书面形式同意,根据许可证分发的软件
#以按原样分发,不含任何明示或暗示的任何形式的担保或条件。请参阅
#许可证,用于管理许可证下的权限和限制
#的特定语言。

Facebook平台的Python客户端库

这个客户端库旨在支持Graph API和官方的
Facebook JavaScript SDK,实现
Facebook身份验证的规范方式阅读更多关于Graph API的信息,请访问
http://developers.facebook.com/docs/api。您可以在http下载Facebook
JavaScript SDK ://github.com/facebook/connect-js/

如果您的应用程序正在使用Google AppEngine的webapp框架,您的
使用该模块可能如下所示:

user = facebook.get_user_from_cookie(self.request.cookies,key,secret)
如果用户:
graph = facebook.GraphAPI(user [access_token])
profile = graph.get_object(me)
friends = graph.get_connections(me,friends)


from google.appengine.dist import use_library
use_library('django','1.2')
import cgi
import hashlib
import time
import u rllib
#from django.utils import translation,simplejson as json
#查找JSON解析器

try:
#对于Google AppEngine
from django。 utils import simplejson
_parse_json = lambda s:simplejson.loads(s)
除了ImportError:
try:
import simplejson
_parse_json = lambda s:simplejson.loads s)
除了ImportError:
import json
_parse_json = lambda s:json.loads(s)


class GraphAPI(object):
Facebook Graph API的客户端。

有关API的完整文档
,请参阅http://developers.facebook.com/docs/api。

Graph API由Facebook中的对象(例如,人物,页面,
事件,照片)以及它们之间的连接组成(例如,朋友
照片标签和事件RSVP)。该客户端以通用的方式提供对这些
原始类型的访问。例如,给定OAuth访问
令牌,这将获取用户的朋友的活动用户和列表
的配置文件:

graph = facebook.GraphAPI(access_token)
user = graph.get_object(me)
friends = graph.get_connections(user [id],friends)

您可以看到所有的对象和连接的支持
由API在http://developers.facebook.com/docs/reference/api/。

您可以通过OAuth或使用Facebook
JavaScript SDK获取访问令牌。有关详细信息,请参阅http://developers.facebook.com/docs/authentication/


如果您使用JavaScript SDK,可以使用下面的
get_user_from_cookie()方法从SDK保存的cookie中获取活动用户的OAuth访问令牌


def __init __(self,access_token = None):
self.access_token = access_token

def get_object(self,id,** args)
从图中获取给定的对象。
return self.request(id,args)

def get_objects(self,ids,** args) :
从图中获取所有给定的对象。

我们将地图从ID返回给对象。如果任何ID无效,
我们引发异常。

args [ids] =,。join(ids)
return self.request(,args)

def get_connections (self,id,connection_name,** args):
获取给定对象的连接。
return self.request(id +/+ connection_name,args)

def put_object(self,parent_object,connection_name,** data):
将给定对象写入连接到给定父项的图形。

例如

graph.put_object(me,feed,message =Hello,world)

写Hello ,世界到活跃的用户墙。同样地,这个
会对活跃用户的Feed的第一个帖子发表评论:

feed = graph.get_connections(me,feed)
post = feed [ data] [0]
graph.put_object(post [id],comments,message =First!)

请参阅http://developers.facebook。 com / docs / api#发布所有
支持的可写对象。

大多数写操作需要扩展权限。例如,
发布墙上的帖子需要publish_stream权限。有关
扩展权限的详细信息,请参阅
http://developers.facebook.com/docs/authentication/。

assert self.access_token,写操作需要访问令牌
return self.request(parent_object +/+ connection_name,post_args = data)

def put_wall_post(self,message,attachment = {},profile_id =me):
在给定的个人资料的墙上写一个墙贴。

如果没有指定
profile_id,我们默认写入经过身份验证的用户的墙。

附件将状态消息的结构附件添加到
发布到墙上。它应该是一个表单的字典:

{name:链接名称
link:http://www.example.com/,
caption:{* actor *}发表了新的评论,
description:这是附件的更长的描述,
picture:http:// www


return self.put_object(profile_id,feed,message = message,**附件)

def put_comment(self,object_id,message):
在给定的帖子中写入给定的注释。
return self.put_object(object_id,comments,message = message)

def put_like(self,object_id):
喜欢给定的帖子。
return self.put_object(object_id,likes)

def delete_object(self,id):
从图中删除给定ID的对象。
self.request(id,post_args = {method: delete})

def req uest(self,path,args = None,post_args = None):
获取Graph API中的给定路径。

我们将args转换为有效的查询字符串。如果给定了post_args,
我们使用给定的参数向给定的路径发送POST请求。

如果不是args:args = {}
如果self.access_token:
如果post_args不是None:
post_args [access_token] = self .access_token
else:
args [access_token] = self.access_token
post_data = None if post_args is None else urllib.urlencode(post_args)
file = urllib.urlopen( https://graph.facebook.com/+ path +?+
urllib.urlencode(args),post_data)
try:
response = _parse_json(file.read )
finally:
file.close()
如果response.get(error):
raise GraphAPIError(response [error] [type],
response [error] [message])
return response


class GraphAPIError(Exception):
def __init __(self,type ,message):
异常.__ init __(self,message)
self.typ e = type


##### NEXT两个函数从https://github.com/jgorset/facepy/blob/master/facepy/signed_request.py

import base64
import hmac


def urlsafe_b64decode(str):
对缺少填充的字符串执行Base 64解码。

l = len(str)
pl = l%4
返回base64.urlsafe_b64decode(str.ljust(l + pl,=))


def parse_signed_request(signed_request,secret):

通过Facebook给出的解析signed_request(通常通过POST),
使用应用程序秘密进行解密。

参数:
signed_request - 通过POST
提供的Facebook的签名请求秘密 - 应用程序的app_secret需要decrpyt signed_request


如果。在signed_request中:
esig,payload = signed_request.split(。)
else:
return {}

sig = urlsafe_b64decode (esig))
data = _parse_json(urlsafe_b64decode(str(payload)))

如果不是isinstance(data,dict):
raise SignedRequestError(Pyload不是json string)
return {}

如果data [algorithm]。upper()==HMAC-SHA256:
if hmac.new(secret,payload ,hashlib.sha256).digest()== sig:
返回数据

else:
raise SignedRequestError(不是HMAC-SHA256加密!)

return {}



def get_user_from_cookie(cookies,app_id,app_secret):
解析官方Facebook JavaS设置的cookie脚本SDK。

cookie应该是一个类似字典的对象,将cookie名称映射到
cookie值。

如果用户通过Facebook登录,我们返回带有
键uid和access_token的字典。前者是用户的Facebook ID,
,后者可用于对Graph API进行身份验证请求。
如果用户没有登录,我们返回None。

下载官方Facebook JavaScript SDK
http://github.com/facebook/connect-js/。阅读更多关于Facebook
身份验证在http://developers.facebook.com/docs/authentication/。


cookie = cookies.get(fbsr_+ app_id,)
如果没有cookie:
返回无

response = parse_signed_request(cookie,app_secret)
如果没有响应:
返回无

args = dict(
code = response ['code'],
client_id = app_id,
client_secret = app_secret,
redirect_uri ='',


file = urllib.urlopen(https:// graph。
尝试:
token_response = file.read()
finally:
file.close()

access_token = cgi.parse_qs(token_response)[access_token] [ - 1]

return dict(
uid = response [user_id],
access_token = access_token,

某些日志跟踪是

  2011-10-18 18:25:07.912 

记录cookie {'access_token':'AAACV ewZBArF4BACUDwnDap5OrQQ5dx0sHEKuPJkIJJ8GdXlYdni5K50xKw6s8BSIDZCpKBtVWF9maHMoJeF9ZCRRYM1zgZD,UID:u'32740016’ }

D 2011-10-18 18:25:07.925

用户LT; __在0x39d606ae980b528>主体__ FBUser对象;

D 2011-10-18 18:25:07.925

用户名Niklas R

现在看看这样做的代码,在我看来,我将模块Facebook与变量facebook混淆,其中一个是示例项目的类facebook,一个是新的推荐模块Facebook.py:

  class BaseHandler(webapp.RequestHandler):
facebook = None
user = None
csrf_protect = True

@property
def current_user(self):
如果不是hasattr(self,_current_user):
self._current_user =无
cookie = facebook.get_user_from_cookie(
self.request.cookies,facebookconf.FACEBOOK_APP_ID,facebookconf.FACEBOOK_APP_SECRET)
logging.debug(logging cookie+ str(cookie))
如果cookie:
#存储用户数据的本地实例,因此我们不需要
#往返Fac每个请求的电子书
user = FBUser.get_by_key_name(cookie [uid])
logging.debug(user+ str(user))
logging.debug(username+ str(user.name))

如果不是用户:
graph = facebook.GraphAPI(cookie [access_token])
profile = graph.get_object(me)
user = FBUser(key_name = str(profile [id]),
id = str(profile [id]),
name = profile [name],
profile_url = profile [link],
access_token = cookie [access_token])
user.put()
elif user.access_token!= cookie [access_token] :
user.access_token = cookie [access_token]
user.put()
self._current_user = user
return self._current_us呃$ er $ er's's's's's's's's's's's's's's's's's's's's's's>>>>>>>>>>>>>>'s's's's>'s's>'s's's's's's's> how I make \"Login with facebook\" for my website with OAuth instead of javascript / cookie this is python only for OAuth 2.0 with Facebook and as far as I can tell it's working:

class FBUser(db.Model): 
id = db.StringProperty(required=True)
created = db.DateTimeProperty(auto_now_add=True) $b$ b updated = db.DateTimeProperty(auto_now=True)
name = db.StringProperty(required=True)
profile_url = db.StringProperty()
access_token = db.StringProperty(required=True)
name = db.StringProperty(required=True)
picture = db.StringProperty()
email = db.StringProperty()
friends = db.StringListProperty() $b$ b
class I18NPage(I18NHandler):
def get(self):
if self.request.get('code'):
args = dict(
code = self.request. get(’code’),
client_id = facebookconf.FACEBOOK_APP_ID,
client_secret = facebookconf.FACEBOOK_APP_SECRET,
redirect_uri = ’http://www.koolbusiness.com/’,
)
logging.debug(\"client_id\"+str(args))
file = urllib.urlopen(\"https://graph.facebook.com/oauth/access_token?\" + urllib.urlencode(args))
try:
logging.debug(\"reading file\")
token_response = file.read()
logging.debug(\"read file\"+str(token_response))
finally:
file.close()
access_token = cgi.parse_qs(token_response)[\"access_token\"][-1]
graph = main.GraphAPI(access_token)
user = graph.get_object(\"me\") #write the access_token to the datastore
fbuser = main.FBUser.get_by_key_name(user[\"id\"])
logging.debug(\"fbuser \"+str(fbuser))

if not fbuser:
fbuser = main.FBUser(key_name=str(user[\"id\"]),
id=str(user[\"id\"]),
name=user[\"name\"],
profile_url=user[\"link\"],
access_token=access_token)
fbuser.put()
elif fbuser.access_token != access_token:
fbuser.access_token = access_token
fbuser.put()

The login link is



<a href=\"https://www.facebook.com/dialog/oauth?client_id=164355773607006&redirect_uri=http://{{host}}/\"><img src=\"/_/img/loginwithfacebook.png\"></a> that redirects and allows me to pick up the access_token in the method above and logout is straightforward:



<a href=\"https://www.facebook.com/logout.php?next=http://www.koolbusiness.com&access_token={{access_token}}\">{% trans \"Log out\" %}</a>

$ b$b

I could reproduce my bug using servside OAuth2.0 only so it's not javascript and the issue is that I must reload to make login / logout take effect and I want it to work without javascript. I have an idea that making logout twice makes logout effective so I could use a custom request handler for /login and/or /logour or just /sessionchange that will do a self.redirect but it's not the clean solution. Maybe you can take a look at the code and see why I must logout twice ie I must reload and can I workaround this using a self.redirect ? Am I using cookies the right way, the new cookie, or do I get it mixed up? I'm doing this both for the website and for the FB app. I'll be glad if you can come with any suggestion. There's a background of 2 related questions from before I removed the Javascript. And BTW should I use class Facebook or facebook.py? I think I commented out where the old cookie is set and that this will be correct once OAuth 2.0 handles my authentication serverside. Can you comment or answer? Thank you in advance if you can review and comment.

How to make my welcome text appear?

How to make this page reload on login / logout?

Why my strange results rendering the user object?

login.html

{% load i18n %}

<?xml version="1.0" encoding="utf-8"?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">

<head>  <title>{% trans "Log in" %}</title>

<script type="text/javascript">

  var _gaq = _gaq || [];

  _gaq.push(['_setAccount', '{{analytics}}']);

  _gaq.push(['_trackPageview']);



  (function() {

    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;

    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';

    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);

  })();

</script>

</head>

<body>

<div id="fb-root"></div>

<script>

  window.fbAsyncInit = function() {

    FB.init({

      appId      : '164355773607006', // App ID

      channelURL : '//WWW.KOOLBUSINESS.COM/static/channel.html', // Channel File

      status     : true, // check login status

      cookie     : true, // enable cookies to allow the server to access the session

      oauth      : true, // enable OAuth 2.0

      xfbml      : true  // parse XFBML

    });



    // Additional initialization code here

  };

  // Load the SDK Asynchronously

  (function(d){

     var js, id = 'facebook-jssdk'; if (d.getElementById(id)) {return;}

     js = d.createElement('script'); js.id = id; js.async = true;

     js.src = "//connect.facebook.net/en_US/all.js";

     d.getElementsByTagName('head')[0].appendChild(js);

   }(document));

</script>

<a href="https://www.facebook.com/dialog/oauth?client_id=164355773607006&redirect_uri=http://{{host}}"><img src="/_/img/loginwithfacebook.png"></a>

<a href="/_ah/login_redir?claimid=google.com/accounts/o8/id&continue=http://{{host}}"><img src="/_/img/loginwithgoogle.png"></a><br>{% if user %}<a href="{{ logout_url }}" class="logout">Logout Google</a>{% endif %}

{% if current_user %}<a href="https://www.facebook.com/logout.php?next=http://{{host}}&access_token={{current_user.access_token}}" onclick="FB.logout()">Logout Facebook</a> {% endif %}

{% if current_user %}<a href="/logout" onclick="FB.logout();">Logout Facebook JS</a> {% endif %}

</body>

</html>


class BaseHandler(webapp.RequestHandler):
    facebook = None
    user = None
    csrf_protect = True

    @property
    def current_user(self):
        if not hasattr(self, "_current_user"):
            self._current_user = None
            cookie = facebook.get_user_from_cookie(
                self.request.cookies, facebookconf.FACEBOOK_APP_ID, facebookconf.FACEBOOK_APP_SECRET)
        logging.debug("logging cookie"+str(cookie))
            if cookie:
                # Store a local instance of the user data so we don't need
                # a round-trip to Facebook on every request
                user = FBUser.get_by_key_name(cookie["uid"])
                logging.debug("user "+str(user))
                logging.debug("username "+str(user.name))

                if not user:
                    graph = facebook.GraphAPI(cookie["access_token"])
                    profile = graph.get_object("me")
                    user = FBUser(key_name=str(profile["id"]),
                                id=str(profile["id"]),
                                name=profile["name"],
                                profile_url=profile["link"],
                                access_token=cookie["access_token"])
                    user.put()
                elif user.access_token != cookie["access_token"]:
                    user.access_token = cookie["access_token"]
                    user.put()
                self._current_user = user
        return self._current_user
   def initialize(self, request, response):
        """General initialization for every request"""
        super(BaseHandler, self).initialize(request, response)

        try:
            self.init_facebook()
            self.init_csrf()
            self.response.headers[u'P3P'] = u'CP=HONK' # iframe cookies in IE
        except Exception, ex:
            self.log_exception(ex)
            raise

    def handle_exception(self, ex, debug_mode):
        """Invoked for unhandled exceptions by webapp"""
        self.log_exception(ex)
        self.render(u'error',
            trace=traceback.format_exc(), debug_mode=debug_mode)

    def log_exception(self, ex):
        """Internal logging handler to reduce some App Engine noise in errors"""
        msg = ((str(ex) or ex.__class__.__name__) +
                u': \n' + traceback.format_exc())
        if isinstance(ex, urlfetch.DownloadError) or \
           isinstance(ex, DeadlineExceededError) or \
           isinstance(ex, CsrfException) or \
           isinstance(ex, taskqueue.TransientError):
            logging.warn(msg)
        else:
            logging.error(msg)

    def set_cookie(self, name, value, expires=None):

        if value is None:
            value = 'deleted'
            expires = datetime.timedelta(minutes=-50000)
        jar = Cookie.SimpleCookie()
        jar[name] = value
        jar[name]['path'] = u'/'
        if expires:
            if isinstance(expires, datetime.timedelta):
                expires = datetime.datetime.now() + expires
            if isinstance(expires, datetime.datetime):
                expires = expires.strftime('%a, %d %b %Y %H:%M:%S')
            jar[name]['expires'] = expires
        self.response.headers.add_header(*jar.output().split(u': ', 1))

    def render(self, name, **data):
        """Render a template"""
        if not data:
            data = {}
        data[u'js_conf'] = json.dumps({
            u'appId': facebookconf.FACEBOOK_APP_ID,
            u'canvasName': facebookconf.FACEBOOK_CANVAS_NAME,
            u'userIdOnServer': self.user.id if self.user else None,
        })
        data[u'logged_in_user'] = self.user
        data[u'message'] = self.get_message()
        data[u'csrf_token'] = self.csrf_token
        data[u'canvas_name'] = facebookconf.FACEBOOK_CANVAS_NAME
        data[u'current_user']=self.current_user
        data[u'user']=users.get_current_user()
        data[u'facebook_app_id']=facebookconf.FACEBOOK_APP_ID
    user = users.get_current_user()
        data[u'logout_url']=users.create_logout_url(self.request.uri) if users.get_current_user() else 'https://www.facebook.com/dialog/oauth?client_id=164355773607006&redirect_uri='+self.request.uri
        host=os.environ.get('HTTP_HOST', os.environ['SERVER_NAME'])
        data[u'host']=host
        if host.find('.br') > 0:
        logo = 'Montao.com.br'
            logo_url = '/_/img/montao_small.gif'
            analytics = 'UA-637933-12'
        domain = None
    else:
        logo = 'Koolbusiness.com'
            logo_url = '/_/img/kool_business.png'
            analytics = 'UA-3492973-18'
        domain = 'koolbusiness'

        data[u'domain']=domain
        data[u'analytics']=analytics
        data[u'logo']=logo
        data[u'logo_url']=logo_url
        data[u'admin']=users.is_current_user_admin()
        if user:
            data[u'greeting'] = ("Welcome, %s! (<a href=\"%s\">sign out</a>)" %
                        (user.nickname(), users.create_logout_url("/")))


        self.response.out.write(template.render(
            os.path.join(
                os.path.dirname(__file__), 'templates', name + '.html'),
            data))

    def init_facebook(self):

        facebook = Facebook()
        user = None

        # initial facebook request comes in as a POST with a signed_request
        if u'signed_request' in self.request.POST:
            facebook.load_signed_request(self.request.get('signed_request'))
            # we reset the method to GET because a request from facebook with a
            # signed_request uses POST for security reasons, despite it
            # actually being a GET. in webapp causes loss of request.POST data.
            self.request.method = u'GET'
            #self.set_cookie(
                #'u', facebook.user_cookie, datetime.timedelta(minutes=1440))
        elif 'u' in self.request.cookies:
            facebook.load_signed_request(self.request.cookies.get('u'))

        # try to load or create a user object
        if facebook.user_id:
            user = FBUser.get_by_key_name(facebook.user_id)
            if user:
                # update stored access_token
                if facebook.access_token and \
                        facebook.access_token != user.access_token:
                    user.access_token = facebook.access_token
                    user.put()
                # refresh data if we failed in doing so after a realtime ping
                if user.dirty:
                    user.refresh_data()
                # restore stored access_token if necessary
                if not facebook.access_token:
                    facebook.access_token = user.access_token

            if not user and facebook.access_token:
                me = facebook.api(u'/me', {u'fields': _USER_FIELDS})
                try:
                    friends = [user[u'id'] for user in me[u'friends'][u'data']]
                    user = FBUser(key_name=facebook.user_id,
                        id=facebook.user_id, friends=friends,
                        access_token=facebook.access_token, name=me[u'name'],
                        email=me.get(u'email'), picture=me[u'picture'])
                    user.put()
                except KeyError, ex:
                    pass # ignore if can't get the minimum fields

        self.facebook = facebook
        self.user = user

    def init_csrf(self):
        """Issue and handle CSRF token as necessary"""
        self.csrf_token = self.request.cookies.get(u'c')
        if not self.csrf_token:
            self.csrf_token = str(uuid4())[:8]
            self.set_cookie('c', self.csrf_token)
        if self.request.method == u'POST' and self.csrf_protect and \
                self.csrf_token != self.request.POST.get(u'_csrf_token'):
            raise CsrfException(u'Missing or invalid CSRF token.')

    def set_message(self, **obj):
        """Simple message support"""
        self.set_cookie('m', base64.b64encode(json.dumps(obj)) if obj else None)

    def get_message(self):
        """Get and clear the current message"""
        message = self.request.cookies.get(u'm')
        if message:
            self.set_message() # clear the current cookie
            return json.loads(base64.b64decode(message))



class Facebook(object):
    """Wraps the Facebook specific logic"""
    def __init__(self, app_id=facebookconf.FACEBOOK_APP_ID,
            app_secret=facebookconf.FACEBOOK_APP_SECRET):
        self.app_id = app_id
        self.app_secret = app_secret
        self.user_id = None
        self.access_token = None
        self.signed_request = {}

    def api(self, path, params=None, method=u'GET', domain=u'graph'):
        """Make API calls"""
        if not params:
            params = {}
        params[u'method'] = method
        if u'access_token' not in params and self.access_token:
            params[u'access_token'] = self.access_token
        result = json.loads(urlfetch.fetch(
            url=u'https://' + domain + u'.facebook.com' + path,
            payload=urllib.urlencode(params),
            method=urlfetch.POST,
            headers={
                u'Content-Type': u'application/x-www-form-urlencoded'})
            .content)
        if isinstance(result, dict) and u'error' in result:
            raise FacebookApiError(result)
        return result

    def load_signed_request(self, signed_request):
        """Load the user state from a signed_request value"""
        try:
            sig, payload = signed_request.split(u'.', 1)
            sig = self.base64_url_decode(sig)
            data = json.loads(self.base64_url_decode(payload))

            expected_sig = hmac.new(
                self.app_secret, msg=payload, digestmod=hashlib.sha256).digest()

            # allow the signed_request to function for upto 1 day
            if sig == expected_sig and \
                    data[u'issued_at'] > (time.time() - 86400):
                self.signed_request = data
                self.user_id = data.get(u'user_id')
                self.access_token = data.get(u'oauth_token')
        except ValueError, ex:
            pass # ignore if can't split on dot

    @property
    def user_cookie(self):
        """Generate a signed_request value based on current state"""
        if not self.user_id:
            return
        payload = self.base64_url_encode(json.dumps({
            u'user_id': self.user_id,
            u'issued_at': str(int(time.time())),
        }))
        sig = self.base64_url_encode(hmac.new(
            self.app_secret, msg=payload, digestmod=hashlib.sha256).digest())
        return sig + '.' + payload

    @staticmethod
    def base64_url_decode(data):
        data = data.encode(u'ascii')
        data += '=' * (4 - (len(data) % 4))
        return base64.urlsafe_b64decode(data)

    @staticmethod
    def base64_url_encode(data):
        return base64.urlsafe_b64encode(data).rstrip('=')

facebook.py

#!/usr/bin/env python
#
# Copyright 2010 Facebook
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

"""Python client library for the Facebook Platform.

This client library is designed to support the Graph API and the official
Facebook JavaScript SDK, which is the canonical way to implement
Facebook authentication. Read more about the Graph API at
http://developers.facebook.com/docs/api. You can download the Facebook
JavaScript SDK at http://github.com/facebook/connect-js/.

If your application is using Google AppEngine's webapp framework, your
usage of this module might look like this:

    user = facebook.get_user_from_cookie(self.request.cookies, key, secret)
    if user:
        graph = facebook.GraphAPI(user["access_token"])
        profile = graph.get_object("me")
        friends = graph.get_connections("me", "friends")

"""
from google.appengine.dist import use_library
use_library('django', '1.2')
import cgi
import hashlib
import time
import urllib
#from django.utils import translation, simplejson as json
# Find a JSON parser

try:
    # For Google AppEngine
    from django.utils import simplejson
    _parse_json = lambda s: simplejson.loads(s)
except ImportError:
    try:
        import simplejson
        _parse_json = lambda s: simplejson.loads(s)
    except ImportError:
        import json
        _parse_json = lambda s: json.loads(s)


class GraphAPI(object):
    """A client for the Facebook Graph API.

    See http://developers.facebook.com/docs/api for complete documentation
    for the API.

    The Graph API is made up of the objects in Facebook (e.g., people, pages,
    events, photos) and the connections between them (e.g., friends,
    photo tags, and event RSVPs). This client provides access to those
    primitive types in a generic way. For example, given an OAuth access
    token, this will fetch the profile of the active user and the list
    of the user's friends:

       graph = facebook.GraphAPI(access_token)
       user = graph.get_object("me")
       friends = graph.get_connections(user["id"], "friends")

    You can see a list of all of the objects and connections supported
    by the API at http://developers.facebook.com/docs/reference/api/.

    You can obtain an access token via OAuth or by using the Facebook
    JavaScript SDK. See http://developers.facebook.com/docs/authentication/
    for details.

    If you are using the JavaScript SDK, you can use the
    get_user_from_cookie() method below to get the OAuth access token
    for the active user from the cookie saved by the SDK.
    """
    def __init__(self, access_token=None):
        self.access_token = access_token

    def get_object(self, id, **args):
        """Fetchs the given object from the graph."""
        return self.request(id, args)

    def get_objects(self, ids, **args):
        """Fetchs all of the given object from the graph.

        We return a map from ID to object. If any of the IDs are invalid,
        we raise an exception.
        """
        args["ids"] = ",".join(ids)
        return self.request("", args)

    def get_connections(self, id, connection_name, **args):
        """Fetchs the connections for given object."""
        return self.request(id + "/" + connection_name, args)

    def put_object(self, parent_object, connection_name, **data):
        """Writes the given object to the graph, connected to the given parent.

        For example,

            graph.put_object("me", "feed", message="Hello, world")

        writes "Hello, world" to the active user's wall. Likewise, this
        will comment on a the first post of the active user's feed:

            feed = graph.get_connections("me", "feed")
            post = feed["data"][0]
            graph.put_object(post["id"], "comments", message="First!")

        See http://developers.facebook.com/docs/api#publishing for all of
        the supported writeable objects.

        Most write operations require extended permissions. For example,
        publishing wall posts requires the "publish_stream" permission. See
        http://developers.facebook.com/docs/authentication/ for details about
        extended permissions.
        """
        assert self.access_token, "Write operations require an access token"
        return self.request(parent_object + "/" + connection_name, post_args=data)

    def put_wall_post(self, message, attachment={}, profile_id="me"):
        """Writes a wall post to the given profile's wall.

        We default to writing to the authenticated user's wall if no
        profile_id is specified.

        attachment adds a structured attachment to the status message being
        posted to the Wall. It should be a dictionary of the form:

            {"name": "Link name"
             "link": "http://www.example.com/",
             "caption": "{*actor*} posted a new review",
             "description": "This is a longer description of the attachment",
             "picture": "http://www.example.com/thumbnail.jpg"}

        """
        return self.put_object(profile_id, "feed", message=message, **attachment)

    def put_comment(self, object_id, message):
        """Writes the given comment on the given post."""
        return self.put_object(object_id, "comments", message=message)

    def put_like(self, object_id):
        """Likes the given post."""
        return self.put_object(object_id, "likes")

    def delete_object(self, id):
        """Deletes the object with the given ID from the graph."""
        self.request(id, post_args={"method": "delete"})

    def request(self, path, args=None, post_args=None):
        """Fetches the given path in the Graph API.

        We translate args to a valid query string. If post_args is given,
        we send a POST request to the given path with the given arguments.
        """
        if not args: args = {}
        if self.access_token:
            if post_args is not None:
                post_args["access_token"] = self.access_token
            else:
                args["access_token"] = self.access_token
        post_data = None if post_args is None else urllib.urlencode(post_args)
        file = urllib.urlopen("https://graph.facebook.com/" + path + "?" +
                              urllib.urlencode(args), post_data)
        try:
            response = _parse_json(file.read())
        finally:
            file.close()
        if response.get("error"):
            raise GraphAPIError(response["error"]["type"],
                                response["error"]["message"])
        return response


class GraphAPIError(Exception):
    def __init__(self, type, message):
        Exception.__init__(self, message)
        self.type = type


##### NEXT TWO FUNCTIONS PULLED FROM https://github.com/jgorset/facepy/blob/master/facepy/signed_request.py

import base64
import hmac


def urlsafe_b64decode(str):
    """Perform Base 64 decoding for strings with missing padding."""

    l = len(str)
    pl = l % 4
    return base64.urlsafe_b64decode(str.ljust(l+pl, "="))


def parse_signed_request(signed_request, secret):
    """
    Parse signed_request given by Facebook (usually via POST),
    decrypt with app secret.

    Arguments:
    signed_request -- Facebook's signed request given through POST
    secret -- Application's app_secret required to decrpyt signed_request
    """

    if "." in signed_request:
        esig, payload = signed_request.split(".")
    else:
        return {}

    sig = urlsafe_b64decode(str(esig))
    data = _parse_json(urlsafe_b64decode(str(payload)))

    if not isinstance(data, dict):
        raise SignedRequestError("Pyload is not a json string!")
        return {}

    if data["algorithm"].upper() == "HMAC-SHA256":
        if hmac.new(secret, payload, hashlib.sha256).digest() == sig:
            return data

    else:
        raise SignedRequestError("Not HMAC-SHA256 encrypted!")

    return {}



def get_user_from_cookie(cookies, app_id, app_secret):
    """Parses the cookie set by the official Facebook JavaScript SDK.

    cookies should be a dictionary-like object mapping cookie names to
    cookie values.

    If the user is logged in via Facebook, we return a dictionary with the
    keys "uid" and "access_token". The former is the user's Facebook ID,
    and the latter can be used to make authenticated requests to the Graph API.
    If the user is not logged in, we return None.

    Download the official Facebook JavaScript SDK at
    http://github.com/facebook/connect-js/. Read more about Facebook
    authentication at http://developers.facebook.com/docs/authentication/.
    """

    cookie = cookies.get("fbsr_" + app_id, "")
    if not cookie:
        return None

    response = parse_signed_request(cookie, app_secret)
    if not response:
        return None

    args = dict(
        code = response['code'],
        client_id = app_id,
        client_secret = app_secret,
        redirect_uri = '',
    )

    file = urllib.urlopen("https://graph.facebook.com/oauth/access_token?" + urllib.urlencode(args))
    try:
        token_response = file.read()
    finally:
        file.close()

    access_token = cgi.parse_qs(token_response)["access_token"][-1]

    return dict(
        uid = response["user_id"],
        access_token = access_token,
    )

Some log traces are

2011-10-18 18:25:07.912

logging cookie{'access_token': 'AAACVewZBArF4BACUDwnDap5OrQQ5dx0sHEKuPJkIJJ8GdXlYdni5K50xKw6s8BSIDZCpKBtVWF9maHMoJeF9ZCRRYM1zgZD', 'uid': u'32740016'}

D 2011-10-18 18:25:07.925

user <__main__.FBUser object at 0x39d606ae980b528>

D 2011-10-18 18:25:07.925

username Niklas R

Now looking at the code that does this it seems to me that I'm confusing the module facebook with the variable facebook where one is the class facebook from the example project and one is the new recommended module facebook.py:

class BaseHandler(webapp.RequestHandler):
    facebook = None
    user = None
    csrf_protect = True

    @property
    def current_user(self):
        if not hasattr(self, "_current_user"):
            self._current_user = None
            cookie = facebook.get_user_from_cookie(
                self.request.cookies, facebookconf.FACEBOOK_APP_ID, facebookconf.FACEBOOK_APP_SECRET)
        logging.debug("logging cookie"+str(cookie))
            if cookie:
                # Store a local instance of the user data so we don't need
                # a round-trip to Facebook on every request
                user = FBUser.get_by_key_name(cookie["uid"])
                logging.debug("user "+str(user))
                logging.debug("username "+str(user.name))

                if not user:
                    graph = facebook.GraphAPI(cookie["access_token"])
                    profile = graph.get_object("me")
                    user = FBUser(key_name=str(profile["id"]),
                                id=str(profile["id"]),
                                name=profile["name"],
                                profile_url=profile["link"],
                                access_token=cookie["access_token"])
                    user.put()
                elif user.access_token != cookie["access_token"]:
                    user.access_token = cookie["access_token"]
                    user.put()
                self._current_user = user
        return self._current_user
解决方案

How to add Facebook as OAuth 2.0 provider: Here's how I make "Login with facebook" for my website with OAuth instead of javascript / cookie this is python only for OAuth 2.0 with Facebook and as far as I can tell it's working:

class FBUser(db.Model):
    id = db.StringProperty(required=True)
    created = db.DateTimeProperty(auto_now_add=True)
    updated = db.DateTimeProperty(auto_now=True)
    name = db.StringProperty(required=True)
    profile_url = db.StringProperty()
    access_token = db.StringProperty(required=True)
    name = db.StringProperty(required=True)
    picture = db.StringProperty()
    email = db.StringProperty()
    friends = db.StringListProperty()

class I18NPage(I18NHandler):
    def get(self):
    if self.request.get('code'):
          args = dict(
            code = self.request.get('code'),
            client_id = facebookconf.FACEBOOK_APP_ID,
            client_secret = facebookconf.FACEBOOK_APP_SECRET,
            redirect_uri = 'http://www.koolbusiness.com/',
          )
      logging.debug("client_id"+str(args))
          file = urllib.urlopen("https://graph.facebook.com/oauth/access_token?" + urllib.urlencode(args))
          try:
        logging.debug("reading file")
            token_response = file.read()
        logging.debug("read file"+str(token_response))
          finally:
            file.close()
          access_token = cgi.parse_qs(token_response)["access_token"][-1]
          graph = main.GraphAPI(access_token)
          user = graph.get_object("me")   #write the access_token to the datastore
      fbuser = main.FBUser.get_by_key_name(user["id"])
          logging.debug("fbuser "+str(fbuser))

          if not fbuser:
            fbuser = main.FBUser(key_name=str(user["id"]),
                                id=str(user["id"]),
                                name=user["name"],
                                profile_url=user["link"],
                                access_token=access_token)
            fbuser.put()
          elif fbuser.access_token != access_token:
            fbuser.access_token = access_token
            fbuser.put()

The login link is

<a href="https://www.facebook.com/dialog/oauth?client_id=164355773607006&redirect_uri=http://{{host}}/"><img src="/_/img/loginwithfacebook.png"></a> that redirects and allows me to pick up the access_token in the method above and logout is straightforward:

<a href="https://www.facebook.com/logout.php?next=http://www.koolbusiness.com&access_token={{access_token}}">{% trans "Log out" %}</a>

这篇关于如何添加OAuth 2.0提供程序?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-05 00:57