我已成功地使这里demistify问题的解决方案,我希望别人能够从中受益: 1)谷歌帐户验证没有针对您的应用程序的每个请求针对Google帐户服务器完成。例如: 1.1用户使用他们的gmail帐户登录到您的应用程序 1.2用户还导航到gmail.com,在那里他们检查他们的电子邮件 1.3他们注销gmail 1.4他们仍然登录到您的应用程序并可以充分使用它 这意味着您必须在会议结束时处理会话过期,Google帐户不会处理它。
2)I中所用的核心Python代码如下:
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"), _('<a href="%(url)s">Setup needed</a>') % { '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)I创建和上述(myapp.common.util.openid进口)的附加LIB是从现有的几个的Django的合并OpenID的库这样的荣誉给那些家伙:
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),并且是为了保持谷歌帐户会话标识符需要和验证端点模式:
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)
祝你好运! Rok
修复了链接,对于SO障碍感到抱歉。 – Tobu 2010-12-05 01:47:51