前言
在規劃一個web的時候,肯定會遇到這種情況,有一些頁面不能讓未登入的用戶訪問,這個時候那些頁面就要進行視圖保護。
flask_login是一個十分方便且優秀的flask插件,更多內容請查閱flask_login官方文檔。
編寫示例代碼
現在就以登陸和登出爲例子
在登出視圖函數上做視圖保護,就和前言中的解釋類似,登陸了的用戶可以訪問登出視圖,未登錄的用戶要先登陸才能登出
初始化app
from flask import Flask, url_for, render_template, flash
from flask_login import LoginManager, current_user, login_user, login_required, logout_user
from flask_bootstrap import Bootstrap
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField, BooleanField
from wtforms.validators import DataRequired, Length
app = Flask(__name__)
login_manager = LoginManager(app)
bootstrap = Bootstrap(app)
'''
當然也可以利用init_app
login_manager = LoginManager()
login_manager.init_app(app)
Bootstrap()同理
'''
class LoginForm(FlaskForm):
username = StringField('Username',validators=[DataRequired(),Length(1,20)])
password = PasswordField('Password',validators=[DataRequired(),Length(8,128)])
remember = BooleanField('Remember me')
submit = SubmitField('Sign in')
def redirect_back(default='blog.index', **kwargs):
'''函數功能: 放回上一頁'''
for target in request.args.get('next'), request.referrer:
if not target:
continue
if is_safe_url(target):
return redirect(target)
return redirect(url_for(default, **kwargs))
登錄視圖函數
@app.route('/login', methods=['GET', 'POST'])
def login():
if current_user.is_authenticated:
return 'success login, you can enjoy it'
form = LoginForm()
if form.validate_on_submit():
username = form.username.data
password = form.password.data
remember = form.remember.data
admin = Admin.query.first()
if admin:
# 驗證用戶名和密碼
if username == admin.name and admin.password:
login_user(admin, remember)
return "success login"
else:
return "賬號或者密碼錯誤"
return render_template('login.html', form=form)
login.html
{% from 'bootstrap/form.html' import render_form %}
<div>
<div>
<h1>Log in</h1>
</div>
<div>
{{ render_form(form, extra_classes='col-6') }}
</div>
</div>
登出函數
@app.route("/logout")
@login_required
def logout():
logout_user()
flash("Logout success.", 'info')
return redirect_back()
登出函數既要實現登出功能也要對其視圖保護
其中
@login_required就是用於標明需要視圖保護的視圖
所以只要實現了flask_login的初始化,就可以可插拔的進行添加視圖保護,十分方便。
例如
@app.route('/hello_1')
@login_required
def hello_1():
return "hello_1"
@app.route('/hello_2')
def hello_2():
return "hello_2"
當訪問http://localhost/hello_1的時候 只有登入了才能看到hello_1,
訪問/hello_2的時候 就直接可以看到hello_2
添加視圖保護內容
......
login_manager = LoginManager(app)
login_manager.login_view = 'login'# 指定視圖保護的視圖函數
login_manager.login_message_category = 'warning'
# login_manager.login_message = u'請先登錄!'
# 當用戶沒有登陸 卻要訪問需要登陸的url 就會跳轉到視圖保護的頁面
login_manager.login_view 即是指定視圖保護所跳轉的視圖函數,在這裏是登入視圖函數
login_manager.login_message 可以指定f消息內容,默認爲"Please log in to access this."
login_manager.login_message_category 指定消息的類別,默認爲"message"
更多內容請關注 flask_login官方文檔
整理代碼
.
├── app.py
└── templates
└── login.html
app.py
from flask import Flask, url_for, render_template, flash
from flask_login import LoginManager, current_user, login_user, login_required, logout_user, UserMixin
from flask_bootstrap import Bootstrap
from flask_sqlalchemy import SQLAlchemy
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField, BooleanField
from wtforms.validators import DataRequired, Length
import os
basedir = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
app = Flask(__name__)
# SECRET_KEY =
app.config['SECRET_KEY'] = "hello flask login"
app.config['SQLALCHEMY_DATABASE_URI']= 'sqlite:///' + os.path.join(basedir, 'data-dev.db')
login_manager = LoginManager(app)
bootstrap = Bootstrap(app)
db = SQLAlchemy(app)
login_manager.login_view = 'login'# 指定視圖保護的視圖函數
login_manager.login_message_category = 'warning'
'''
當然也可以利用init_app
login_manager = LoginManager()
login_manager.init_app(app)
Bootstrap()同理
'''
class LoginForm(FlaskForm):
username = StringField('Username', validators=[DataRequired(), Length(1, 20)])
password = PasswordField('Password', validators=[DataRequired(), Length(8, 128)])
remember = BooleanField('Remember me')
submit = SubmitField('Sign in')
class Admin(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(20), unique=True)
password = db.Column(db.String(50))
def init():
'''building, kiesblog, just for you '''
db.drop_all()
db.create_all()
admin = Admin.query.first()
admin = Admin(name="admin",
password="password")
db.session.add(admin)
db.session.commit()
init()
@login_manager.user_loader
def load_user(userid):
return User.get(userid)
@app.route('/')
@app.route('/login', methods=['GET', 'POST'])
def login():
if current_user.is_authenticated:
return 'success login, you can enjoy it'
form = LoginForm()
if form.validate_on_submit():
username = form.username.data
password = form.password.data
remember = form.remember.data
admin = Admin.query.first()
if admin:
# 驗證用戶名和密碼
if username == admin.name and admin.password:
login_user(admin, remember)
return "success login"
else:
return "賬號或者密碼錯誤"
return render_template('login.html', form=form)
@app.route("/logout")
@login_required
def logout():
logout_user()
return "logout success"
@app.route('/hello_1')
@login_required
def hello_1():
return "hello_1"
@app.route('/hello_2')
def hello_2():
return "hello_2"
if __name__ == '__main__':
app.run(host="0.0.0.0", port=80)
login.html
{% from 'bootstrap/form.html' import render_form %}
<div>
<div>
<h1>Log in</h1>
</div>
<div>
{{ render_form(form, extra_classes='col-6') }}
</div>
</div>
賬號密碼分別爲 admin password
ps: 此爲示例代碼,未對password進行hash加密,如有需要請自行添加!
好了,可以開始你的測試了😄