- 首页
- 正文
在Flask中设置用户身份验证(下)【翻译】
第6步:创建 UserForms.py
下一步就是定义我们的表单验证逻辑。数据检查是我们工作的中心。每当我们收到用户的一些信息。我们希望确定我们有创建用户和登录的所有数据。
from flask_wtf import Form
from wtforms import (BooleanField, TextField, HiddenField, PasswordField,
DateTimeField, validators, IntegerField, SubmitField)
import UserConstants
class LoginForm(Form):
login = TextField('user_name', [validators.Required()])
password = TextField('password', [validators.Required()])
remember_me = BooleanField('remember_me', default = False)
class SignupForm(Form):
user_name = TextField('user_name', [
validators.Length(
min = UserConstants.MIN_USERNAME_LEN,
max = UserConstants.MAX_USERNAME_LEN
),
validators.Regexp(
"^[a-zA-Z0-9]*$",
message="Username can only contain letters and numbers"
)
])
first_name = TextField('first_name', [validators.Required()])
last_name = TextField('last_name', [validators.Required()])
email = TextField('email', [validators.Required(), validators.Email()])
password = PasswordField(
'New Password',
[validators.Length(min=UserConstants.MIN_PASSWORD_LEN,max=UserConstants.MAX_PASSWORD_LEN)]
)
confirm = PasswordField('Repeat Password', [
validators.Required(),
validators.EqualTo('password', message='Passwords must match')
])
这是相当直接的。我们定义了一个登录单表和另外一个注册表单。Flask-WTF
允许我们定义一些字段和指定特定的字段来验证。有些默认的验证是提供的,但是我们也可能自己定义。请参见用户名的逻辑验证,我们使用正则表达式限制了只能是字母和数字。
第7步:创建验证终端 api/auth.py
vim app/api/auth.py
# Users API for authentication
'''
Users API for authentication
'''
from flask import (Blueprint, render_template, current_app, request,
flash, url_for, redirect, session, abort, jsonify)
from flask.ext.login import login_required, login_user, current_user, logout_user, confirm_login, login_fresh
from ..common import Response
from ..extensions import db
from ..users import User, SignupForm, LoginForm
auth = Blueprint('auth', __name__, url_prefix='/api/auth')
@auth.route('/verify_auth', methods=['GET'])
@login_required
def verify_auth():
return Response.make_data_resp(data=current_user.to_json())
@auth.route('/login', methods=['POST'])
def login():
""" POST only operation. check login form. Log user in """
# 这里应该是 current_user.is_authenticated:
if current_user.is_authenticated():
return Response.make_success_resp(msg="You are already logged in")
form = LoginForm()
if form.validate_on_submit():
user, authenticated = User.authenticate(form.login.data,
form.password.data)
if user :
if authenticated:
login_user(user, remember=form.remember_me.data)
return Response.make_data_resp(data=current_user.to_json(), msg="You have successfully logged in")
else:
return Response.make_error_resp(msg="Invalid username or password", type="Wrong Authentication", code=422)
else:
return Response.make_error_resp(msg="Username does not exist", type="Wrong Authentication", code=422)
return Response.make_form_error_resp(form=form)
@auth.route('/logout', methods=['POST'])
@login_required
def logout():
""" logout user """
session.pop('login', None)
logout_user()
return Response.make_success_resp(msg="You have successfully logged out")
@auth.route('/signup', methods=['POST'])
def signup():
# 这里应该是 current_user.is_authenticated:
if current_user.is_authenticated():
# 这里应该是 return Response.make_success_resp("You're already signed up")
return make_success_resp("You're already signed up")
form = SignupForm()
if form.validate_on_submit():
# check if user_name or email is taken
if User.is_user_name_taken(form.user_name.data):
return Response.make_error_resp(msg="This username is already taken!", code=409)
if User.is_email_taken(form.email.data):
return Response.make_error_resp(msg="This email is already taken!", code=409)
try:
# create new user
user = User()
form.populate_obj(user)
db.session.add(user)
db.session.commit()
except Exception as e:
return Response.make_exception_resp(exception=e)
# log the user in
login_user(user)
return Response.make_success_resp(msg="You successfully signed up! Please check your email for further verification.")
return Response.make_form_error_resp(form=form)
这里我们定义了4个终端,将使用它们来进行身份验证。你可能想知道为什么我们需要 /api/auth/verify_auth
。就像我之前提到的,我们创建一个纯API后端和用javascript驱动的前端。因此,作为javascript应用程序的第一次启动,我们需要确定用户是否已经登录了。这个终端不只是允许前端来启动应用程序状态。你将会在下面的UI部分看到一个快速的示例。
这个 Form.validate_on_submit
就像它的名字建议那样 - 验证输入的表单。它将确保每个字段都会传递我们为它定义的验证规则,否则就失败。
默认情况下,由于设置了 Flask-WTF
,每个POST请示都会受到 csrf
的保护。跨站点请求伪造不同于其他黑客技术,恶意用户伪造他们的证书并代表你的行为。相反,黑客会在你已经的登录的网站上插入恶意的脚本来欺骗你的浏览器。在网站方面,这个行为是真实的,值得信任的,因为是直接来自你的,虽然你的浏览器不希望这样做。这里有很多常见的修复方式 - 其中一种就是 CSRF 保护。Flask-WTF 将会对每个 POST 请求都会验证一个散列令牌。
更新 app.py
包含我们的 API 蓝图认证。
# in app/app.py
from .api import helloworld, auth
DEFAULT_BLUEPRINTS = [
helloworld,
auth,
]
第8步:基本前端
在最后这一部分,我将简短地说一下实现简单的前端,和通过jquery实现的后端。
第一步,用一个新的控制器来服务静态 HTML。
$ vim app/frontend/controller.py
from flask import (Flask, Blueprint, render_template, current_app, request,
flash, url_for, redirect, session, abort, jsonify, send_from_directory)
frontend = Blueprint('frontend', __name__)
@frontend.route('/')
@frontend.route('/<path:path>')
def index(path=None):
return render_template('app.html')
这个控制器负责服务静态页面,在这种情况下, app/template/app.html
现在从 github 复制 app/templates
和 app/static
目录。打开这个文件, 注意我们如何加载这两个 javascript 文件,jquery 和 我们自定义的用来跟后端通信的 javascript 文件。我们将会使用 bootstrap 样式。
// app/templates/app.html
{% block js_btm %}
<!-- Put javascript here !-->
<script src="/static/desktop/vendors/jquery.js"></script>
<script src="/static/desktop/js/main.js"></script>
{% endblock %}
因此我们所有的游戏计划都在 /static/desktop/js/main.js
。
// setup csrf token for all ajax calls
var csrftoken = $('meta[name=csrf-token]').attr('content');
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type)) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
$(document).ready(function(){
// initial check to see if user is logged in or not
updateAuthStatus();
// setup logged in view
$('#logged-in-view button').click(function(){
logout()
.done(function(response){
showLoggedout()
}).fail(function(response){
showLoggedIn();
});
});
// setup signup view
$('#signup-view #signup-form').submit(function(e) {
e.preventDefault();
var form = $(this);
var signupData = extractFormInput(form);
signup(signupData)
.done(function(response){
alert('You just created a new user');
form.trigger('reset');
updateAuthStatus();
}).fail(function(response){
alert('Something went wrong');
});
});
});
// helpers
// 这里应该是 function updateAuthStatus()
function updateAuth() {
verifyAuth()
.done(function(response){
showLoggedIn(response.data.user_name)
}).fail(function(response){
showLoggedout()
});
}
function extractFormInput(form) {
var inputs = form.serializeArray();
var data = {};
$.each(inputs, function(index, input) {
data[input.name] = input.value;
});
return data;
}
function showLoggedIn(username) {
// show logged in view and show username
$("#logged-in-view span").text(username);
$("#logged-out-view").addClass('hidden');
$("#logged-in-view").removeClass('hidden');
}
function showLoggedout() {
// show logged out view
$("#logged-out-view").removeClass('hidden');
$("#logged-in-view").addClass('hidden');
}
// API calls
function verifyAuth(callback) {
var url = '/api/auth/verify_auth';
return $.get(url);
}
function login(loginData){
var url = '/api/auth/login';
return $.post(url, loginData);
}
function logout() {
var url = '/api/auth/logout';
return $.post(url);
}
function signup(signupData) {
var url = '/api/auth/signup';
return $.post(url, signupData);
}
登录视图
登录之后的视图
注册视图
就这些了!现在你已经在Flask中创建了一个简单的用户系统,它能够创建新用户和用已经存在的用户来登录。在下面的文章,我将会讨论UI方面的工作和展示一个用Backbone创建用户验证的示例。
注意:我用 python2.6去运行下载的代码会报错,只要把 current_user.is_authenticated()
改成 current_user.is_authenticated
就可以了,因为 is_authenticated
是 current_user
的一个属性,不是 current_user
的一个方法
参考网站
http://blog.sampingchuang.com/setup-user-authentication-in-flask/
原文:http://blog.sampingchuang.com/setup-user-authentication-in-flask/
【下一篇】Mac常用软件