4.用户登录
1.配置
对于登录系统,使用到扩展:Flask-Login。配置情况如下(app/init.py)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#-*- coding:utf-8 -*-
from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
from flask.ext.login import LoginManager
# 初始化flask应用
app = Flask(__name__)
app.config.from_object('config')
# 初始化数据库
db = SQLAlchemy(app)
# 初始化flask-Login
lm = LoginManager()
lm.setup_app(app)
from app import views, models
2.重构用户模型
Flask-Login 扩展需要在我们的 User 类中实现一些特定的方法,但是类如何去实现这些方法却没有什么要求,让我们为 Flask-Login 实现的 User 类(app/models.py)
1 | class User(db.Model): |
is_authenticated 方法有一个具有迷惑性的名称。一般而言,这个方法应该只返回 True,除非表示用户的对象因为某些原因不允许被认证;is_active 方法应该返回 True,除非是用户是无效的,比如因为他们的账号被禁止;is_anonymous 方法应该返回 True,除非是伪造的用户不允许登录系统;get_id 方法应该返回一个用户唯一的标识符,以 unicode 格式返回我们使用数据库生成的唯一的id。
3.user_loader 回调
我们已经准备好用 Flask-Login 扩展来开始实现登录系统。
首先,我们必须编写一个函数用于从数据库加载用户,这个函数将会被 Flask-Login 使用(app/views.py)
1 |
|
Flask-Login 中的用户的id永远是 unicode 字符串,因此在我们把id 发送给 Flask-SQLAlchemy 之前,需要把id转成整型是必须的,否则会报错。
4.登陆视图函数(app/views.py)
1 | #-*- coding:utf-8 -*- |
整个流程就是,验证用户,验证用户是否已经注册,如果注册则从数据库中加载用户并转到用户页面。如果要让这些都起作用的话,Flask-Login 需要知道哪个视图允许用户登录。我们在应用程序模块初始化中配置(app/init.py)1
2lm = LoginManager()
lm.setup_app(app)
5.首页视图
前面我们的 index 视图函数使用了伪造的对象,因为那时候我们并没有用户或者 blog。现在我们有用户了,让我们使用它。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
def index():
user = 'Man'
posts = [
{
'author': {'nickname': 'John'},
'body': 'Beautiful day in Portland!'
},
{
'author': {'nickname': 'Susan'},
'body': 'The Avengers movie was so cool!'
}
]
return render_template(
"index.html",
title="Home",
user=user,
posts=posts)
6.登录
我们已经实现了登录,现在增加登陆的功能,即对登录视图函数进行修改(app/views.py)
1 |
|
其中login_required是为了验证用户必须是登陆的前提,才会有登出。
7.注册
- 再注册前,我们需要修改app/forms.py文件以绑定数据库
1 | # -*- coding:utf-8 -*- |
在这里添加了类SignUpForm,用户的用户名和邮件的注册提交
- 接着,实现用户注册视图(app/views.py)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34from forms import LoginForm, SignUpForm
def sign_up():
form = SignUpForm()
user = User()
if form.validate_on_submit():
user_name = request.form.get('user_name')
user_email = request.form.get('user_email')
register_check = User.query.filter(db.or_(
User.nickname == user_name, User.email == user_email)).first()
if register_check:
flash("error: The user's name or email already exists!")
return redirect('/sign-up')
if len(user_name) and len(user_email):
user.nickname = user_name
user.email = user_email
user.role = ROLE_USER
try:
db.session.add(user)
db.session.commit()
except:
flash("The Database error!")
return redirect('/sign-up')
flash("Sign up successful!")
return redirect('/index')
return render_template(
"sign_up.html",
form=form)
在提交注册信息的时候验证数据库中是否已经注册该用户信息,如果没有注册则在数据库中提交该信息,并显示注册成功,转到首页。
在修改主页index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15{% extends "base.html" %}
{% block content %}
{% if not current_user.is_authenticated() %}
<h1>Hi, Guys!</h1>
{% else %}
<h1>Welcome back, {{ current_user.nickname }}!</h1>
{% endif %}
{% for post in posts %}
<p>{{ post.author.nickname }} says: <b>{{ post.body }}</b></p>
</div>
{% endfor %}
{% endblock %}修改登录模版(login.html)
1 | {% extends "base.html" %} |
当现在如果运行程序的话,肯定会说用户名不存在,因为还需要建立一个注册模版(sign_up.html)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20{% extends "base.html" %}
{% block content %}
<form action="/sign-up", method="POST" name="sign_up">
{{ form.hidden_tag() }}
<p>Nick name: {{ form.user_name }}</p>
{% for error in form.errors.user_name %}
<p style="color:red;">[-] {{ error }}</p>
{% endfor %}
<p>E-mail: {{ form.user_email }}</p>
{% for error in form.errors.user_email %}
<p style="color:red;">[-] {{ error }}</p>
{% endfor %}
<p>{{ form.submit }}</p>
</form>
{% endblock %}
但是还没有在模版中添加登出和注册的链接。将要把这个链接放在基础层中的导航栏里(app/templates/base.html)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33<html>
<head>
{% if title %}
<title>{{title}} - microblog</title>
{% else %}
<title>microblog</title>
{% endif %}
</head>
<body>
<div>Microblog:
<a href="{{ url_for('index') }}">Home</a>
{% if not current_user.is_authenticated() %}
| <a href="{{ url_for('login') }}">Log in</a>
or <a href="{{ url_for('sign_up') }}">Sign up</a>
{% else %}
| <a href="{{ url_for('logout') }}">Logout</a>
{% endif %}
</div>
<hr />
{% with messages = get_flashed_messages() %}
{% if messages %}
<ul>
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
{% block content %}{% endblock %}
</body>
{% block js %}{% endblock %}
</html>