Google app engine 取而代之的是一些从单词“go”开始就意味着应用程序引擎的轻量级和漂亮的框架,比如?它使用自己的用户系统或App Engine自己的用户、OpenIn、OAuth和Facebook为您提供身份验证;使用安全cookie或GAE数据存储的会话;除此之外,所有这些都是基于WSGI和Werkzeug的超轻量“非框架”方法。有什么不喜欢的

Google app engine 取而代之的是一些从单词“go”开始就意味着应用程序引擎的轻量级和漂亮的框架,比如?它使用自己的用户系统或App Engine自己的用户、OpenIn、OAuth和Facebook为您提供身份验证;使用安全cookie或GAE数据存储的会话;除此之外,所有这些都是基于WSGI和Werkzeug的超轻量“非框架”方法。有什么不喜欢的,google-app-engine,session,forms-authentication,cookies,tornado,Google App Engine,Session,Forms Authentication,Cookies,Tornado,如果您只想在cookie中存储用户的用户ID(想必这样您就可以在数据存储中查找他们的记录),您不需要“安全”或防篡改cookie-您只需要一个足够大的名称空间,使猜测用户ID变得不切实际-例如,GUID或其他随机数据 一个预先制作的选项是,它使用数据存储进行会话存储。或者,如果您真的只需要存储他们的用户ID,您可以通过设置cookie/cookie头来处理此问题。最近有人从Tornado中提取了身份验证和会话代码,并专门为GAE创建了一个新库 也许这比你需要的要多,但既然他们是专门为GAE做的,

如果您只想在cookie中存储用户的用户ID(想必这样您就可以在数据存储中查找他们的记录),您不需要“安全”或防篡改cookie-您只需要一个足够大的名称空间,使猜测用户ID变得不切实际-例如,GUID或其他随机数据


一个预先制作的选项是,它使用数据存储进行会话存储。或者,如果您真的只需要存储他们的用户ID,您可以通过设置cookie/cookie头来处理此问题。

最近有人从Tornado中提取了身份验证和会话代码,并专门为GAE创建了一个新库

也许这比你需要的要多,但既然他们是专门为GAE做的,你就不必担心自己会适应它

他们的图书馆叫盖马。以下是他们于2010年3月4日在GAE Python group发布的公告:

对于那些仍在寻找的人,我们只提取了Tornado cookie实现,您可以在ThriveSmart的App Engine中使用它。我们正在App Engine上成功使用它,并将继续更新它

cookie库本身位于:

您可以在我们附带的示例应用程序中看到它的实际应用。如果存储库的结构发生变化,您可以在github.com/thrivesmart/prayls中查找lilcookes.py


我希望这对外面的人有帮助

如果有人感兴趣:

from google.appengine.ext import webapp

import Cookie
import base64
import time
import hashlib
import hmac
import datetime
import re
import calendar
import email.utils
import logging

def _utf8(s):
    if isinstance(s, unicode):
        return s.encode("utf-8")
    assert isinstance(s, str)
    return s

def _unicode(s):
    if isinstance(s, str):
        try:
            return s.decode("utf-8")
        except UnicodeDecodeError:
            raise HTTPError(400, "Non-utf8 argument")
    assert isinstance(s, unicode)
    return s 

def _time_independent_equals(a, b):
    if len(a) != len(b):
        return False
    result = 0
    for x, y in zip(a, b):
        result |= ord(x) ^ ord(y)
    return result == 0


class ExtendedRequestHandler(webapp.RequestHandler):
    """Extends the Google App Engine webapp.RequestHandler."""
    def clear_cookie(self,name,path="/",domain=None):
        """Deletes the cookie with the given name."""
        expires = datetime.datetime.utcnow() - datetime.timedelta(days=365)
        self.set_cookie(name,value="",path=path,expires=expires,
                        domain=domain)    

    def clear_all_cookies(self):
        """Deletes all the cookies the user sent with this request."""
        for name in self.cookies.iterkeys():
            self.clear_cookie(name)            

    def cookies(self):
        """A dictionary of Cookie.Morsel objects."""
        if not hasattr(self,"_cookies"):
            self._cookies = Cookie.BaseCookie()
            if "Cookie" in self.request.headers:
                try:
                    self._cookies.load(self.request.headers["Cookie"])
                except:
                    self.clear_all_cookies()
        return self._cookies

    def _cookie_signature(self,*parts):
        """Hashes a string based on a pass-phrase."""
        hash = hmac.new("MySecretPhrase",digestmod=hashlib.sha1)
        for part in parts:hash.update(part)
        return hash.hexdigest() 

    def get_cookie(self,name,default=None):
        """Gets the value of the cookie with the given name,else default."""
        if name in self.request.cookies:
            return self.request.cookies[name]
        return default

    def set_cookie(self,name,value,domain=None,expires=None,path="/",expires_days=None):
        """Sets the given cookie name/value with the given options."""
        name = _utf8(name)
        value = _utf8(value)
        if re.search(r"[\x00-\x20]",name + value): # Don't let us accidentally inject bad stuff
            raise ValueError("Invalid cookie %r:%r" % (name,value))
        new_cookie = Cookie.BaseCookie()
        new_cookie[name] = value
        if domain:
            new_cookie[name]["domain"] = domain
        if expires_days is not None and not expires:
            expires = datetime.datetime.utcnow() + datetime.timedelta(days=expires_days)
        if expires:
            timestamp = calendar.timegm(expires.utctimetuple())
            new_cookie[name]["expires"] = email.utils.formatdate(timestamp,localtime=False,usegmt=True)
        if path:
            new_cookie[name]["path"] = path
        for morsel in new_cookie.values():
            self.response.headers.add_header('Set-Cookie',morsel.OutputString(None))

    def set_secure_cookie(self,name,value,expires_days=30,**kwargs):
        """Signs and timestamps a cookie so it cannot be forged"""
        timestamp = str(int(time.time()))
        value = base64.b64encode(value)
        signature = self._cookie_signature(name,value,timestamp)
        value = "|".join([value,timestamp,signature])
        self.set_cookie(name,value,expires_days=expires_days,**kwargs)

    def get_secure_cookie(self,name,include_name=True,value=None):
        """Returns the given signed cookie if it validates,or None"""
        if value is None:value = self.get_cookie(name)
        if not value:return None
        parts = value.split("|")
        if len(parts) != 3:return None
        if include_name:
            signature = self._cookie_signature(name,parts[0],parts[1])
        else:
            signature = self._cookie_signature(parts[0],parts[1])
        if not _time_independent_equals(parts[2],signature):
            logging.warning("Invalid cookie signature %r",value)
            return None
        timestamp = int(parts[1])
        if timestamp < time.time() - 31 * 86400:
            logging.warning("Expired cookie %r",value)
            return None
        try:
            return base64.b64decode(parts[0])
        except:
            return None

我不打算将Tornado与应用程序引擎一起使用,我只想像他们那样设置和获取签名cookie。我看了一下tipfy/werkzeug安全cookie代码,我认为他们在Tornado中所做的更优雅。将用户id存储在cookie中不是问题,但这并不是我想要的全部。应用引擎GUID并不是不切实际的猜测,使用其他GUID对用户进行身份验证似乎要麻烦得多。只要哈希算法运行得相当快,将用户id放入签名cookie中就可以很好地解决问题。我已经看过几次烧杯,并决定反对它,因为它看起来不像我想要的。我相信有人会看到这一点,并确切地知道如何使代码从龙卷风的工作。问题帖子中断章取义地显示了它,但代码片段是Tornado请求处理程序的一部分。我尝试扩展webapp请求处理程序,但无法使其工作。修复方法可能很简单,但我需要有更多经验的人来告诉我怎么做。我很好奇为什么你这么决心要使用Tornado的会话模块?还有其他几个很好的会话模块,包括Bicker,它提供了一个只有签名cookie的选项。webapp框架应该增加对第三方身份验证机制的支持,因为这似乎是一种流行趋势。下面是他们在gaema页面上所说的“gaema只对用户进行身份验证,不提供会话或安全cookie之类的持久性来保持用户登录…”
from google.appengine.ext import webapp

import Cookie
import base64
import time
import hashlib
import hmac
import datetime
import re
import calendar
import email.utils
import logging

def _utf8(s):
    if isinstance(s, unicode):
        return s.encode("utf-8")
    assert isinstance(s, str)
    return s

def _unicode(s):
    if isinstance(s, str):
        try:
            return s.decode("utf-8")
        except UnicodeDecodeError:
            raise HTTPError(400, "Non-utf8 argument")
    assert isinstance(s, unicode)
    return s 

def _time_independent_equals(a, b):
    if len(a) != len(b):
        return False
    result = 0
    for x, y in zip(a, b):
        result |= ord(x) ^ ord(y)
    return result == 0


class ExtendedRequestHandler(webapp.RequestHandler):
    """Extends the Google App Engine webapp.RequestHandler."""
    def clear_cookie(self,name,path="/",domain=None):
        """Deletes the cookie with the given name."""
        expires = datetime.datetime.utcnow() - datetime.timedelta(days=365)
        self.set_cookie(name,value="",path=path,expires=expires,
                        domain=domain)    

    def clear_all_cookies(self):
        """Deletes all the cookies the user sent with this request."""
        for name in self.cookies.iterkeys():
            self.clear_cookie(name)            

    def cookies(self):
        """A dictionary of Cookie.Morsel objects."""
        if not hasattr(self,"_cookies"):
            self._cookies = Cookie.BaseCookie()
            if "Cookie" in self.request.headers:
                try:
                    self._cookies.load(self.request.headers["Cookie"])
                except:
                    self.clear_all_cookies()
        return self._cookies

    def _cookie_signature(self,*parts):
        """Hashes a string based on a pass-phrase."""
        hash = hmac.new("MySecretPhrase",digestmod=hashlib.sha1)
        for part in parts:hash.update(part)
        return hash.hexdigest() 

    def get_cookie(self,name,default=None):
        """Gets the value of the cookie with the given name,else default."""
        if name in self.request.cookies:
            return self.request.cookies[name]
        return default

    def set_cookie(self,name,value,domain=None,expires=None,path="/",expires_days=None):
        """Sets the given cookie name/value with the given options."""
        name = _utf8(name)
        value = _utf8(value)
        if re.search(r"[\x00-\x20]",name + value): # Don't let us accidentally inject bad stuff
            raise ValueError("Invalid cookie %r:%r" % (name,value))
        new_cookie = Cookie.BaseCookie()
        new_cookie[name] = value
        if domain:
            new_cookie[name]["domain"] = domain
        if expires_days is not None and not expires:
            expires = datetime.datetime.utcnow() + datetime.timedelta(days=expires_days)
        if expires:
            timestamp = calendar.timegm(expires.utctimetuple())
            new_cookie[name]["expires"] = email.utils.formatdate(timestamp,localtime=False,usegmt=True)
        if path:
            new_cookie[name]["path"] = path
        for morsel in new_cookie.values():
            self.response.headers.add_header('Set-Cookie',morsel.OutputString(None))

    def set_secure_cookie(self,name,value,expires_days=30,**kwargs):
        """Signs and timestamps a cookie so it cannot be forged"""
        timestamp = str(int(time.time()))
        value = base64.b64encode(value)
        signature = self._cookie_signature(name,value,timestamp)
        value = "|".join([value,timestamp,signature])
        self.set_cookie(name,value,expires_days=expires_days,**kwargs)

    def get_secure_cookie(self,name,include_name=True,value=None):
        """Returns the given signed cookie if it validates,or None"""
        if value is None:value = self.get_cookie(name)
        if not value:return None
        parts = value.split("|")
        if len(parts) != 3:return None
        if include_name:
            signature = self._cookie_signature(name,parts[0],parts[1])
        else:
            signature = self._cookie_signature(parts[0],parts[1])
        if not _time_independent_equals(parts[2],signature):
            logging.warning("Invalid cookie signature %r",value)
            return None
        timestamp = int(parts[1])
        if timestamp < time.time() - 31 * 86400:
            logging.warning("Expired cookie %r",value)
            return None
        try:
            return base64.b64decode(parts[0])
        except:
            return None
class MyHandler(ExtendedRequestHandler):
    def get(self):
        self.set_cookie(name="MyCookie",value="NewValue",expires_days=10)
        self.set_secure_cookie(name="MySecureCookie",value="SecureValue",expires_days=10)

        value1 = self.get_cookie('MyCookie')
        value2 = self.get_secure_cookie('MySecureCookie')