Jun 10 2010
在App Engine上使用OpenID验证登陆 {1}
Google App Engine最新发布的SDK 1.3.4提供了对OpenID的原生支持。下面我们就来演示在app engine上的应用如何使用OpenID来登陆。
首先你需要登陆到App Engine的管理控制台中,在你应用的"Application Settings"中选择"Authentication Options"为 "(Experimental) Federated Login"并保存。

一旦你设置好了上面这一步,App Engine的Users API就能够提供对OpenID的支持了。在使用Users API之前,我们先看看OpenID的登陆流程,我按照自己的理解画了一个示意图。
- 用户访问web app
- web app返回一个登陆表单,提供OpenID identifier的输入框
- 用户输入OpenID identifier,提交表单
- web app根据用户输入的OpenID identifier用create_login_url()函数生成并重定向到OpenID登陆页面
- 用户在OpenID provider处登陆,并授权web app获取用户的OpenID信息
- OpenID provider把用户重定向到web app(重定向的url包含了用户的OpenID信息)
- web app通过get_current_user()函数获取到用户信息,登陆完成
上面的流程省略掉了一些步骤和细节,比如web app和OpenID provider的交互,web app对重放攻击的处理等等。这些步骤和细节App Engine全都帮我们做了,所以对web开发者来说是透明的,我们不用去关心。我们需要做的就是第2,4,7步。
提供一个用户登陆页面
准备一个简单login.html文件内容如下,主要就是提供一个能够接收用户OpenID标识的表单。
<html>
<head>
<title>Log in with OpenID</title>
</head>
<body>
<h1>Log in with OpenID</h1>
<form method="get" action="/testopenid">
<input type="text" name="openid" />
<input type="submit" value="Log In" />
</form>
</body>
</html>
修改app.yaml,让用户访问 http://your-app.appspot.com/testopenid 时能显示上面的login.html
- url: /testopenid script: testopenid.py
添加testopenid.py文件,内容如下。
import os
from google.appengine.ext import webapp
from google.appengine.ext.webapp import template
from google.appengine.api import users
from google.appengine.ext.webapp.util import run_wsgi_app
class UsersHandler(webapp.RequestHandler):
def get(self):
path = os.path.join(os.path.dirname(__file__), 'templates', 'login.html')
self.response.out.write(template.render(path,{}))
application = webapp.WSGIApplication(
[('/', MainPage),
('/testopenid',UsersHandler)],
debug=True)
def main():
run_wsgi_app(application)
if __name__ == "__main__":
main()
生成OpenID登陆url并重定向
当用户提交OpenID identifier后,我们用Users API中的create_login_url()函数生成需要跳转的url。具体的函数定义见这里.
修改testopenid.py中的UsersHandler类
class UsersHandler(webapp.RequestHandler):
def get(self):
openid_url = self.request.GET.get('openid')
if not openid_url:
path = os.path.join(os.path.dirname(__file__), 'templates', 'login.html')
self.response.out.write(template.render(path,{}))
else:
self.redirect(users.create_login_url('/testopenid', None, openid_url))
验证用户登陆,并取得OpenID信息
当用户在OpenID Provider处登陆并跳转到我们的web app时,我们用Users API中的get_current_user()函数验证用户是否登陆并返回一个User对象,这个对象中就保存着登陆用户的OpenID信息.
继续修改我们的UsersHandler类
class UsersHandler(webapp.RequestHandler):
def get(self):
user = users.get_current_user()
openid_url = self.request.GET.get('openid')
if user:
greeting = ("Welcome, %s! %s(sign out)" %
(user.__dict__, user.nickname(),
users.create_logout_url("/testopenid")))
self.response.out.write(greeting)
else:
if not openid_url:
path = os.path.join(os.path.dirname(__file__), 'templates', 'login.html')
self.response.out.write(template.render(path,{}))
else:
self.redirect(users.create_login_url('/testopenid', None, openid_url))
到目前为止我们的web app已经能够支持OpenID登陆了。可以看到我们所需要做的工作非常简单,App Engine给我们处理了大量的细节,生活顿时变的非常美好。
还有一点需要注意。如果你在app.yaml中针对某个url设置成必须要先登录(login: required),那么当你未登录访问那个url时,App Engine会把你重定向到 http://your-app.appspot.com/_ah/login_required 对于这种情况你需要做的就是针对"/_ah/login_required"这个地址创建一个登陆页面。
参考文章 Using OpenID authentication on App Engine