07_新增登陆界面

2018-11-05 大宝

1 效果图

添加登陆界面后,能够实现注册用户、用户登陆、用户退出、指定页面控制访问的功能。

2 代码说明

flask-admin的github上有关于权限管理的案例,我们直接模仿即可。链接地址如下:

https://github.com/flask-admin/flask-admin/blob/master/examples/auth-flask-login/app.py

将代码下载到本次,使用git命令操作:

yum install -y git
git clone https://github.com/flask-admin/flask-admin.git

3 操作指南

3.1 安装python模块

pip install Flask-Login Flask-wtf

[root@am_01 ~]# pip install Flask-Login Flask-wtf

3.2 使用myweb用户登陆服务器

su - myweb
>[myweb@am_01 PonyTail]$ pwd
>/home/myweb/PonyTail
>[myweb@am_01 PonyTail]$ ll
>total 8
>-rw-rw-r--. 1 myweb myweb 1 Nov 2 18:33 __init__.py
>-rw-rw-r--. 1 myweb myweb 1743 Nov 2 19:19 manage.py
>drwxrwxr-x. 2 myweb myweb 63 Nov 2 17:32 templates

3.3 下载flask-admin项目到本地

git clone git clone https://github.com/flask-admin/flask-admin/blob/master/examples/auth-flask-login/app.py
>[myweb@am_01 ~]$ git clone git clone https://github.com/flask-admin/flask-admin/blob/master/examples/auth-flask-login/app.py

>[myweb@am_01 ~]$ ll
>total 12
>drwxrwxr-x. 7 myweb myweb 4096 Nov 5 16:24 flask-admin
>drwxrwxr-x. 3 myweb myweb 59 Nov 5 13:30 PonyTail
>[myweb@am_01 ~]$ ll flask-admin/examples/auth-flask-login/
>total 16
>-rw-rw-r--. 1 myweb myweb 7039 Nov 5 16:24 app.py
>-rw-rw-r--. 1 myweb myweb 0 Nov 5 16:24 __init__.py
>-rw-rw-r--. 1 myweb myweb 738 Nov 5 16:24 README.rst
>-rw-rw-r--. 1 myweb myweb 54 Nov 5 16:24 requirements.txt
>drwxrwxr-x. 3 myweb myweb 59 Nov 5 16:24 templates
>[myweb@am_01 ~]$ ll flask-admin/examples/auth-flask-login/templates/ -R
>flask-admin/examples/auth-flask-login/templates/:
>total 8
>drwxrwxr-x. 2 myweb myweb 24 Nov 5 16:24 admin
>-rw-rw-r--. 1 myweb myweb 135 Nov 5 16:24 index.html
>-rw-rw-r--. 1 myweb myweb 447 Nov 5 16:24 my_master.html

>flask-admin/examples/auth-flask-login/templates/admin:
>total 4
>-rw-rw-r--. 1 myweb myweb 1128 Nov 5 16:24 index.html

/home/myweb/flask-admin/examples/auth-flask-login/ 目录中存放的就是能够实现登陆界面的案例。

3.4 清空无关的数据

首先我们将上一节课使用的UserAdmin表从数据库中删除,新建一张user表用于存放用户和密码。

mysql -uroot -pmyweb myweb -e "drop table AdminUser;"
mysql -uroot -pmyweb myweb -e "create table user (id int primary key auto_increment,first_name varchar(100),last_name varchar(100),login varchar(80),email varchar(120),password varchar(64));"
mysql -uroot -pmyweb myweb -e "alter table user add unique index idx_login (login);"

同时修改manage.py,将代码中涉及到AdminUser表的代码清除。如果对代码不是很懂,可以直接将文末的manage.py的代码直接替换为最终的代码。

3.5 准备登陆模板

我们直接复制flask-admin的案例中的模板稍加修改即可,具体操作如下:

cp /home/myweb/flask-admin/examples/auth-flask-login/templates/* /home/myweb/PonyTail/templates/ -rp

修改登陆后的首页/home/myweb/PonyTail/templates/admin/index.html

{% extends 'admin/master.html' %}
{% block body %}
{{ super() }}
<div class="row-fluid">

<div>
{% if current_user.is_authenticated %}
<h1>工作管理系统</h1>
<p class="lead">
登陆成功
</p>
<p>
开始管理你的工作.
</p>
{% else %}
<form method="POST" action="">
{{ form.hidden_tag() if form.hidden_tag }}
{% for f in form if f.type != 'CSRFTokenField' %}
<div>
{{ f.label }}
{{ f }}
{% if f.errors %}
<ul>
{% for e in f.errors %}
<li>{{ e }}</li>
{% endfor %}
</ul>
{% endif %}
</div>
{% endfor %}
<button class="btn" type="submit">Submit</button>
</form>
{{ link | safe }}
{% endif %}
</div>

<a class="btn btn-primary" href="/"><i class="icon-arrow-left icon-white"></i> Back</a>
</div>
{% endblock body %}

3.6 修改manage.py

根据flask-admin的example文件/home/myweb/flask-admin/examples/auth-flask-login/app.py来修改我们的manage.py文件。

学习的初期我们将所有的python代码都放在manage.py文件中,最后我们再尝试将代码根据功能进行拆分。

修改后manage.py文件如下:

# -*- coding:utf8 -*- 

from flask import Flask
from flask_admin import Admin
from flask_admin import BaseView
from flask_admin import expose
from flask_babelex import Babel
from flask_sqlalchemy import SQLAlchemy
from flask_admin.contrib.sqla import ModelView
# 07_新增登陆界面:加载模块
from flask import url_for, redirect, render_template, request
from wtforms import form, fields, validators
import flask_admin as admin
import flask_login as login
from flask_admin.contrib import sqla
from flask_admin import helpers
from werkzeug.security import generate_password_hash, check_password_hash



db = SQLAlchemy()
app = Flask(__name__)
babel = Babel(app)

#set optional bootswatch theme
#app.config['FLASK_ADMIN_SWATCH'] = 'cerulean'
app.config['BABEL_DEFAULT_LOCALE'] = 'zh_CN'
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:myweb@localhost:3306/myweb?charset=utf8'
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# 07_新增登陆界面:配置key才能使用session
# Create dummy secrey key so we can use sessions
app.config['SECRET_KEY'] = '123456790'


db.init_app(app)

# models
# Create user model.
# 07_新增登陆界面:将原来的UserAdmin表改为User
class User(db.Model):
__tablename__ = 'user'
id = db.Column(db.Integer, primary_key=True)
first_name = db.Column(db.String(100))
last_name = db.Column(db.String(100))
login = db.Column(db.String(80), unique=True)
email = db.Column(db.String(120))
password = db.Column(db.String(64))

# Flask-Login integration
# NOTE: is_authenticated, is_active, and is_anonymous
# are methods in Flask-Login < 0.3.0
@property
def is_authenticated(self):
return True

@property
def is_active(self):
return True

@property
def is_anonymous(self):
return False

def get_id(self):
return self.id

# Required for administrative interface
def __unicode__(self):
return self.username


# Define login and registration forms (for flask-login)
class LoginForm(form.Form):
login = fields.StringField(validators=[validators.required()])
password = fields.PasswordField(validators=[validators.required()])
#password = fields.StringField(validators=[validators.required()])

def validate_login(self, field):
user = self.get_user()

if user is None:
raise validators.ValidationError('Invalid user')

# we're comparing the plaintext pw with the the hash from the db
#if not check_password_hash(user.password, self.password.data):
# to compare plain text passwords use
if user.password != self.password.data:
raise validators.ValidationError('Invalid password')

def get_user(self):
return db.session.query(User).filter_by(login=self.login.data).first()


class RegistrationForm(form.Form):
login = fields.StringField(validators=[validators.required()])
email = fields.StringField()
password = fields.PasswordField(validators=[validators.required()])

def validate_login(self, field):
if db.session.query(User).filter_by(login=self.login.data).count() > 0:
raise validators.ValidationError('Duplicate username')


# Initialize flask-login
def init_login():
login_manager = login.LoginManager()
login_manager.init_app(app)

# Create user loader function
@login_manager.user_loader
def load_user(user_id):
return db.session.query(User).get(user_id)


# Create customized model view class
class MyModelView(sqla.ModelView):

def is_accessible(self):
return login.current_user.is_authenticated

# Create customized index view class that handles login & registration
class MyAdminIndexView(admin.AdminIndexView):

@expose('/')
def index(self):
if not login.current_user.is_authenticated:
return redirect(url_for('.login_view'))
return super(MyAdminIndexView, self).index()

@expose('/login/', methods=('GET', 'POST'))
def login_view(self):
# handle user login
form = LoginForm(request.form)
if helpers.validate_form_on_submit(form):
user = form.get_user()
login.login_user(user)

if login.current_user.is_authenticated:
return redirect(url_for('.index'))
link = '<p>Don\'t have an account? <a href="' + url_for('.register_view') + '">Click here to register.</a></p>'
self._template_args['form'] = form
self._template_args['link'] = link
return super(MyAdminIndexView, self).index()

@expose('/register/', methods=('GET', 'POST'))
def register_view(self):
form = RegistrationForm(request.form)
if helpers.validate_form_on_submit(form):
user = User()

form.populate_obj(user)
# we hash the users password to avoid saving it as plaintext in the db,
# remove to use plain text:
#user.password = generate_password_hash(form.password.data)

db.session.add(user)
db.session.commit()

login.login_user(user)
return redirect(url_for('.index'))
link = '<p>Already have an account? <a href="' + url_for('.login_view') + '">Click here to log in.</a></p>'
self._template_args['form'] = form
self._template_args['link'] = link
return super(MyAdminIndexView, self).index()

@expose('/logout/')
def logout_view(self):
login.logout_user()
return redirect(url_for('.index'))






# Add administrative views here
class Happy(BaseView):
@expose('/')
def index(self):
return self.render('happy.html')

class Birthday(BaseView):
@expose('/')
def index(self):
return self.render('birthday.html')



# Flask views
@app.route('/')
def index():
return render_template('index.html')


# Initialize flask-login
init_login()

admin = Admin(app, name='PonyTail', index_view=MyAdminIndexView(), base_template='my_master.html', template_mode='bootstrap3')
admin.add_view(Happy(name=u'工作之愉'))
admin.add_view(Birthday(name=u'年年有今日岁岁有今朝'))
admin.add_view(MyModelView(User,db.session,name=u'用户管理'))

if __name__ == "__main__":
app.run(debug=True,host='0.0.0.0',port=5000)

3.7 运行程序

[myweb@am_01 PonyTail]$ python manage.py 
* Serving Flask app "manage" (lazy loading)
* Environment: production
WARNING: Do not use the development server in a production environment.
Use a production WSGI server instead.
* Debug mode: on
* Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
* Debugger PIN: 476-676-292

访问网站http://10.200.6.150:5000/