几周来,我一直在绞尽脑汁,试图让这个身份验证模块在使用 Jinja、NDB 和 WTForms 的 webapp2 框架下工作。我在网上到处都看过,已经到了我的崩溃点,需要向某人寻求帮助。我一直在关注这个教程(它非常彻底,但我认为遗漏了一些重要的细节,特别是对于像我这样的新手):
使用 Webapp2 + Google App Engine 的用户帐户
据我所知,我已经正确设置了所有内容,但我不断收到 404 - 找不到资源。我可能做错了什么?这是我的代码...
处理程序.py:
import webapp2
import sys
from google.appengine.ext import ndb
sys.modules['ndb'] = ndb
import webapp2_extras.appengine.auth.models as auth_models
from google.appengine.api import users
from webapp2_extras import sessions, auth # we'll use auth later on
from webapp2_extras.auth import InvalidAuthIdError
from webapp2_extras.auth import InvalidPasswordError
from wtforms import Form, TextField, PasswordField, validators
from webapp2_extras.appengine.users import login_required
def jinja2_factory(app):
j = jinja2.Jinja2(app)
j.environment.filters.update({
# Set filters. (http://tinyurl.com/jinja2-factory)
# ...
})
j.environment.globals.update({
# Set global variables.
'uri_for': webapp2.uri_for,
# ...
})
return j
def login_required(handler):
def check_login(self, *args, **kwargs):
if not self.user:
return self.redirect_to('login')
else:
return handler(self, *args, **kwargs)
return check_login
class UserAwareHandler(webapp2.RequestHandler):
def dispatch(self):
try:
super(UserAwareHandler, self).dispatch()
finally:
# Save the session after each request
self.session_store.save_sessions(self.response)
@webapp2.cached_property
def session_store(self):
return sessions.get_store(request=self.request)
@webapp2.cached_property
def session(self):
return self.session_store.get_session(backend="datastore")
@webapp2.cached_property
def auth(self):
return auth.get_auth(request=self.request)
@webapp2.cached_property
def user(self):
user = self.auth.get_user_by_session()
return user
@webapp2.cached_property
def user_model(self):
user_model, timestamp = self.auth.store.user_model.get_by_auth_token(
self.user['user_id'],
self.user['token']) if self.user else (None, None)
return user_model
@webapp2.cached_property
def jinja2(self):
return jinja2.get_jinja2(factory=jinja2_factory, app=self.app)
def render_response(self, _template, **context):
ctx = {'user': self.user_model}
ctx.update(context)
rv = self.jinja2.render_template(_template, **ctx)
self.response.write(rv)
class SignupForm(Form):
email = TextField('Email',
[validators.Required(),
validators.Email()])
password = PasswordField('Password',
[validators.Required(),
validators.EqualTo('confirm_password',
message="Passwords must match.")])
password_confirm = PasswordField('Confirm Password',
[validators.Required()])
class SignupHandler(UserAwareHandler):
#Serves up a signup form, creates new users
def get(self):
self.render_response("templates/signup.html", form=SignupForm())
def post(self):
form = SignupForm(self.request.POST)
error = None
if form.validate():
success, info = self.auth.store.user_model.create_user(
"auth:" + form.email.data,
unique_properties=['email'],
email= form.password.data,
password_raw= form.password.data)
if success:
self.auth.get_user_by_password("auth:"+form.email.data,
form.password.data)
return self.redirect_to("index")
else:
error = "That email is already in use." if 'email'\
in user else "Something has gone horrible wrong."
self.render_response("templates/signup.html", form=form, error=error)
class LoginForm(Form):
email = TextField('Email',
[validators.Required(), validators.Email()])
password = PasswordField('Password',
[validators.Required()])
class LoginHandler(UserAwareHandler):
def get(self):
self.render_response("templates/index.html", form=LoginForm())
def post(self):
form = LoginForm(self.request.POST)
error = None
if form.validate():
try:
self.auth.get_user_by_password(
"auth:"+form.email.data,
form.password.data)
return self.redirect_to('secure')
except (auth.InvalidAuthIdError, auth.InvalidPasswordError):
error = "Invalid Email / Password"
self.render_response("templates/login.html", form=form, error=error)
class LogoutHandler(UserAwareHandler):
#Destroy the user session and return them to the login screen.
@login_required
def get(self):
self.auth.unset_session()
self.redirect_to('login')
class IndexHandler(UserAwareHandler):
def get(self):
ctx = {
'title1': "ALAZA",
'title2': "HOA",
'slogan': "A communication tool for the Alazan HOA.",
'message1': """
<p>The whole idea here is to show how to set up a simple static web site
on Google App Engine. I want to create an easy way to host your modest web
site on App Engine. My approach is dead simple. All I use is some boilerplate
code almost anyone can follow. You can have multiple pages and use template
variable features that are part of App Engine's WebApp Framework. Most modest
web sites don't do much more than this. Your certainly free to expand on what
you find here.</p>""",
}
self.render_response('templates/index.html', **ctx)
主要.py:
import webapp2
import config
import routes
import sys
from google.appengine.ext import ndb
sys.modules['ndb'] = ndb
import webapp2_extras.appengine.auth.models as auth_models
class AwesomeUser(auth_models.User):
email = ndb.StringProperty()
webapp2_config = {}
webapp2_config['webapp2_extras.sessions'] = {
'secret_key': 'othello',}
webapp2_config['webapp2_extras.auth'] = {
'user_model': AwesomeUser,}
app = webapp2.WSGIApplication(config=config.webapp2_config)
routes.add_routes(app)
路线.py:
import handlers
import webapp2
from webapp2_extras.routes import RedirectRoute
# Using redirect route instead of simple routes since it supports strict_slash
# Simple route: http://webapp-improved.appspot.com/guide/routing.html#simple-routes
# RedirectRoute: http://webapp-improved.appspot.com/api/webapp2_extras/routes.html#webapp2_extras.routes.RedirectRoute
_routes = [
RedirectRoute('templates/login.html', handlers.LoginHandler, name='login'),
RedirectRoute('/templates/logout.html', handlers.LogoutHandler, name='logout'),
RedirectRoute('/templates/index.html', handlers.IndexHandler, name='index'),
RedirectRoute('/templates/signup.html', handlers.SignupHandler, name='signup'),]
def get_routes():
return _routes
def add_routes(app):
if app.debug:
secure_scheme = 'http'
for r in _routes:
app.router.add(r)
应用程序.yaml:
application: alazan-hoa
version: main
runtime: python27
api_version: 1
threadsafe: true
handlers:
- url: /js
static_dir: js
- url: /images
static_dir: images
- url: /css
static_dir: css
- url: /.*
script: main.app
libraries:
- name: webapp2
version: "2.5.1"
- name: jinja2
version: "2.6"
builtins:
- appstats: on