如何在App Engine请求处理前注入自定义用户模型实例(webapp2框架)
在Webapp2中为认证请求注入自定义用户模型实例
我来帮你搞定这个需求!在App Engine Python2.7的Webapp2框架里,要实现类似Django process_request 的请求前置处理、注入自定义用户实例,完全可以通过自定义中间件来实现,不用每次在handler里重复查询。下面一步步来:
1. 先明确你的自定义用户模型(示例)
假设你已经有了基于NDB的自定义用户模型,大概是这样的:
from google.appengine.ext import ndb from google.appengine.api import users class CustomUser(ndb.Model): email = ndb.StringProperty(required=True) display_name = ndb.StringProperty() # 这里可以加你的其他自定义字段,比如头像URL、权限等级等 @classmethod def get_by_auth_user(cls): # 通过App Engine内置的认证用户,关联到我们的自定义模型 auth_user = users.get_current_user() if not auth_user: return None return cls.query(cls.email == auth_user.email()).get()
2. 编写自定义中间件类
Webapp2支持WSGI中间件,我们可以写一个中间件,在每个请求被路由到具体handler之前,完成用户实例的查询和注入:
import webapp2 class CustomUserMiddleware(object): def __init__(self, app): self.app = app def __call__(self, environ, start_response): # 从WSGI环境中取出Webapp2的request对象 request = webapp2.Request(environ) # 查询并注入自定义用户实例 request.custom_user = CustomUser.get_by_auth_user() # 把修改后的request放回环境,让后续handler能拿到 environ['webapp2.request'] = request # 继续传递请求到下一个环节 return self.app(environ, start_response)
3. 把中间件注册到你的Webapp2应用
在创建WSGI应用的时候,通过middleware参数把我们的中间件加进去:
app = webapp2.WSGIApplication( [ # 你的路由配置,比如: ('/', MainHandler), ('/profile', ProfileHandler), # 其他路由... ], debug=True, middleware=[ CustomUserMiddleware, # 如果有其他中间件,也可以在这里添加 ] )
4. 在Handler里直接用注入的用户实例
现在所有的handler都可以直接通过self.request.custom_user获取自定义用户对象了,再也不用每个handler里重复写查询逻辑:
class MainHandler(webapp2.RequestHandler): def get(self): if self.request.custom_user: self.response.write(f'嗨,{self.request.custom_user.display_name}!') else: login_url = users.create_login_url('/') self.response.write(f'请<a href="{login_url}">登录</a>') class ProfileHandler(webapp2.RequestHandler): def get(self): user = self.request.custom_user if not user: self.redirect(users.create_login_url('/profile')) return # 直接用user对象渲染资料页 self.response.write('<h1>你的个人资料</h1>') self.response.write(f'邮箱:{user.email}<br>') self.response.write(f'昵称:{user.display_name}')
进阶优化:用基类统一处理认证
如果你的大部分页面都需要用户登录才能访问,可以写一个基类handler,在dispatch方法里统一做登录检查,省得每个handler都写一遍:
class AuthenticatedBaseHandler(webapp2.RequestHandler): def dispatch(self): # 先执行父类的dispatch,确保中间件已经注入了用户实例 super(AuthenticatedBaseHandler, self).dispatch() # 检查用户是否已登录,未登录就跳转到登录页 if not self.request.custom_user: login_url = users.create_login_url(self.request.path) self.redirect(login_url) return # 之后需要认证的handler直接继承这个基类就行 class ProfileHandler(AuthenticatedBaseHandler): def get(self): # 这里肯定能拿到已登录的custom_user user = self.request.custom_user # 你的业务逻辑...
一些注意点
- 如果你用的是Datastore而不是NDB,只需要把查询逻辑改成Datastore的写法就行,原理完全一样。
- 可以考虑给自定义用户实例加缓存(比如用memcache),减少每次请求都查Datastore的开销,提升性能。
- 确保
CustomUser和App Engine内置认证用户的关联逻辑是可靠的,比如用唯一的用户ID而不是邮箱(邮箱可能会变),这样更稳定。
内容的提问来源于stack exchange,提问作者snakecharmerb
相关产品推荐
相关产品推荐

