Oct 28 2010

一个纯粹的JavaScript blog {4}

REWORK上说有了灵感就立刻去做,所以我花了两天时间实现了自己的一个想法--一个纯粹的JavaScript blog。

前后端都是由javascript驱动。
前端仅仅是一个静态的html文件,后端数据保存在google spreadsheets中,逻辑部分由google apps script来处理(就是一段javascript脚本)。

零成本,你只需要有一个能存放单个html文件的地方就能搭建整个blog.

我把这个blog取名为 purejsblog (pure javascript blog)
关于 PureJsBlog
http://purejsblog.cuoluo.net/index.html?p=3
PureJsBlog demo
http://purejsblog.cuoluo.net/index.html

Jun 10 2010

在App Engine上使用OpenID验证登陆 {2}

Google App Engine最新发布的SDK 1.3.4提供了对OpenID的原生支持。下面我们就来演示在app engine上的应用如何使用OpenID来登陆。

首先你需要登陆到App Engine的管理控制台中,在你应用的"Application Settings"中选择"Authentication Options"为 "(Experimental) Federated Login"并保存。

Authentication Options
一旦你设置好了上面这一步,App Engine的Users API就能够提供对OpenID的支持了。在使用Users API之前,我们先看看OpenID的登陆流程,我按照自己的理解画了一个示意图。

  1. 用户访问web app
  2. web app返回一个登陆表单,提供OpenID identifier的输入框
  3. 用户输入OpenID identifier,提交表单
  4. web app根据用户输入的OpenID identifier用create_login_url()函数生成并重定向到OpenID登陆页面
  5. 用户在OpenID provider处登陆,并授权web app获取用户的OpenID信息
  6. OpenID provider把用户重定向到web app(重定向的url包含了用户的OpenID信息)
  7. 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"这个地址创建一个登陆页面。

demo在这里

参考文章 Using OpenID authentication on App Engine