flask基礎(中篇)


目錄

1、session/cookie介紹

2、使用session實現登陸驗證

3、flask擴展之flask-login

session/cookie

前言

Session和Cookie的結合使用,通常有兩種存儲方式:html

第一種: session數據存儲在客戶端: Flask採用'secure cookie'方式保存session,即session數據是使用base64編碼後保存在客戶端的cookie中。也就是說無須依賴第三方數據庫保存session數據。前端

第二種: session數據存儲在服務端,分爲如下三步驟:python

步驟1: 當客戶端發送請求到服務端的時候,服務端會校驗請求中cookie參數中的sessionid值,若是cookie中不存在sessionid則認爲客戶端訪問服務端時,是發起了一個新的會話。redis

步驟2: 若是是新的會話,則服務端會傳遞給客戶端一個cookie,並在cookie中存儲一個新的sessionid值,並將相關數據保存在session中。sql

步驟3: 客戶端下次再發送請求的時候,請求上下文對象會攜帶cookie,經過校驗cookie中的sessionid值,便可判斷是不是同一會話。mongodb

步驟4: 若是校驗會話是同一會話,則能夠從session中獲取到以前保存的數據。數據庫

訪問者的標識問題服務器須要識別來自同一訪問者的請求。這主要是經過瀏覽器的cookie實現的。 訪問者在第一次訪問服務器時,服務器在其cookie中設置一個惟一的ID號——會話ID(session)。 這樣,訪問者後續對服務器的訪問頭中將自動包含該信息,服務器經過這個ID號,便可區 隔不一樣的訪問者。flask

官網文檔地址後端

概念:跨域

a)客戶端會話技術,瀏覽器的會話技術

b)數據所有存儲在客戶端中

c)存儲使用的鍵值對結構進行存儲

特性:
    支持過時時間
    默認會自動攜帶本網站的cookie
    不能跨域名
    不能跨瀏覽器

建立:

Cookie是經過服務器建立的Response來建立的

設置:set_cookie('key', value, max_ages='', expires='')

刪除, 有三種刪除方式
    
    1. 直接清空瀏覽器的cookie
    2. delete_cookie('key') 直接使用delete_cookie函數
    3. set_cookie('key','',expires=0) 從新設置key的值爲空,過時時間爲0

獲取:

在每次請求中,url都會向服務器傳遞Request,在request中能夠獲取到cookie的信息

request.cookies.get('name')

例子1,設置cookie:

import datetime

@blue.route('/setcookie/')
def set_cookie():
    temp = render_template('index.html')
    response = make_response(temp)
    outdate=datetime.datetime.today() + datetime.timedelta(days=30)
    # 設置cookie中的name的存在時長,設置爲30天才過時  
    response.set_cookie('name','cocoococo',expires=outdate)
    return response

例子2,刪除cookie中的值

@blue.route('/setcookie/')
def set_cookie():
    temp = render_template('index.html')
    response = make_response(temp)
    # 第一種方式,經過set_cookie去刪除
    response.set_cookie('name','',expires=0)
    # 第二種方式,del_cookie刪除
    response.del_cookie('name')
    return response

例子3,獲取cookie中的值

@blue.route('/getcookie/')
def get_cookie():
    name=request.cookies.get('name')  
    return name

2. 將session數據存儲在數據庫

flask-session是flask框架的session組件

該組件則將支持session保存到多個地方

如:

redis:保存數據的一種工具,五大類型。非關係型數據庫

memcached

mongodb

sqlalchmey:那數據存到數據庫表裏面

2.1 安裝

pip install flask-session

若是指定存session的類型爲redis的話,須要安裝redis

pip install redis

2.2 語法

設置session:

session['key'] = value

讀取session:

result = session['key'] :若是內容不存在,將會報異常

result = session.get('key') :若是內容不存在,將返回None

刪除session:

session.pop('key')

清空session中全部數據:

session.clear()

2.2 使用

咱們在初始化文件中建立一個方法,經過調用該方法來獲取到Flask的app對象

def create_app():
    app = Flask(__name__)
    # SECRET_KEY 祕鑰
    app.config['SECRET_KEY'] = 'secret_key'
    # session類型爲redis
    app.config['SESSION_TYPE'] = 'redis'
    # 添加前綴
    app.config['SESSION_KEY_PREFIX'] = 'flask'
    
    # 加載app的第一種方式
    se = Session()
    se.init_app(app=app)
    #加載app的第二種方式
    Session(app=app)
    app.register_blueprint(blueprint=blue)

    return app

2.3 案例

定義一個登錄的方法,post請求獲取到username,直接寫入到redis中,而且在頁面中展現出redis中的username

a)須要先啓動redis,開啓redis-server,使用redis-cli進入客戶端

b)定義方法

@blue.route('/login/', methods=['GET', 'POST'])
def login():
    if request.method == 'GET':
        username = session.get('username')
        return render_template('login.html', username=username)
    else:
        username = request.form.get('username')
        session['username'] = username

        return redirect(url_for('first.login'))

c)定義模板

<body>
<h3>歡迎:{{ username }}</h3>
<form action="" method="POST">
    用戶名:<input type="text" name="username" placeholder="請輸入你的名字">
    <input type="submit" value="提交">
</form>
</body>

d)redis中數據

注意:咱們在定義app.config的時候指定了SESSION_KEY_PREFIX爲flask,表示存在session中的key都會加一個前綴名flask

e) cookie和session的聯繫

訪問者在第一次訪問服務器時,服務器在其cookie中設置一個惟一的ID號——會話ID(session)。 這樣,訪問者後續對服務器的訪問頭中將自動包含該信息,服務器經過這個ID號,便可區 隔不一樣的訪問者。而後根據不一樣的訪問者來獲取其中保存的value值信息。

使用session實現登陸驗證

第一種方式: flask默認的session/cookie使用方式

將session中的數據存儲在cookie中,並返回給客戶端。

缺點:數據存儲在cookie中,不安全

1. 前端login.html頁面

登陸頁面就兩個輸入框,分別接收用戶名和密碼

<dd class="user_icon">
   <input type="text" name="username" placeholder="帳號" class="login_txtbx"/>
  </dd>
  <dd class="pwd_icon">
   <input type="password" name="password" placeholder="密碼" class="login_txtbx"/>
  </dd>

2. 後端方法

@blue.route('login/', methods=['GET'])
def login():
    if request.method == 'GET':
        # 獲取提交的用戶名和密碼
        username = request.args.get('username')
        password = request.args.get('password')
        # 模擬判斷用戶名和密碼
        if username == '小明' and password == '123456':
            # 啓動permanent修改成True
            session.permanent = True
            # 在session中記錄登陸狀態
            session['login_status'] = 1
            return '登陸成功'
        else:
            return '登陸失敗'

3. 修改啓動manage.py文件中定義加密以及過時時間

# session加密方式
app.secret_key = '123'

# 設置過時時間,5秒後session失效
app.permanent_session_lifetime = 5

注意:

1)設置一個持久化會話的存活時間,必須修改session.permanent的屬性和flask對象app的permanent_session_lifetime屬性,permanent_session_lifetime屬性做爲datetime.timedelta對象,從Flask0.8開始也能夠用一個整數表示多少秒後過時。

2)加密的強度取決於SECRET_KEY的複雜程度。通常SECRET_KEY能夠經過os.urandom(24)隨機生成。

第二種方式: 使用flask_session擴展庫實現登陸功能描述

使用session實現用戶的模擬登錄功能。在前面已經說過了,在用戶第一次訪問服務端的時候,在服務端的redis中會建立一個session值,在客戶端瀏覽器的cookies中也會建立一個session的值。該cookies中的session值和redis中的session值是同樣的,那麼在日後的訪問操做中,請求request都會傳遞給後端,後端在獲取到request的時候,其實就是獲取到了request.cookies中的session的值了,那麼就能夠作登陸的校驗了。校驗功能以下:

素材地址

1. 前端login.html頁面

登陸頁面就兩個輸入框,分別接收用戶名和密碼

<dd class="user_icon">
   <input type="text" name="username" placeholder="帳號" class="login_txtbx"/>
  </dd>
  <dd class="pwd_icon">
   <input type="password" name="password" placeholder="密碼" class="login_txtbx"/>
  </dd>

2. 後端方法

模擬用戶的登陸,直接判斷用戶的名稱爲妲己以及密碼爲123123.若是驗證成功,就向session中保存用戶的id值。若是沒有登陸成功的話,那就對session不作任何的處理,直接跳轉到登陸頁面上去。

@app_blue.route('/new_login/', methods=['GET', 'POST'])
def new_login():
    if request.method == 'GET':
        return render_template('login.html')
    else:
        username = request.form.get('username')
        password = request.form.get('password')
        # 數據庫校驗,用戶密碼是否正確
        if username == '妲己' and password == '123123':
            session['user_id'] = 1
            return redirect((url_for('first.index')))
        else:
            return redirect(url_for('first.new_login'))


@app_blue.route('/index/', methods=['GET'])
def index():
    return render_template('index.html')

3. 修改啓動manage.py文件中定義加密以及過時時間

# 配置session
from flask_session import Session   

# 指定redis做爲緩存數據庫
app.config['SESSION_TYPE'] = 'redis'
# 指定訪問哪個redis,ip和端口
app.config['SESSION_REDIS'] = redis.Redis(host='127.0.0.1', port=6379)

# 初始化app
se = Session()
se.init_app(app=app)

裝飾器

使用裝飾器去裝飾咱們的index()函數,若是用戶登陸了,則session中有user_id的key,若是沒有登陸的話,session中是沒有user_id的key的。那麼驗證用戶是否登陸了,其實就是驗證session的user_id

def is_login(func):
    @wraps(func)
    def check_login(*args, **kwargs):
        if 'user_id' in session:
            return func(*args, **kwargs)
        else:
            return redirect(url_for('first.new_login'))
    return check_login

修改index()函數,使用裝飾器裝飾

@app_blue.route('/index/', methods=['GET'])
@is_login
def index():
    return render_template('index.html')

flask擴展之flask-login

前言

在flask中如何快速的實現登陸註冊註銷功能,以及登陸狀態驗證等功能? flask的擴展庫中有Flask-Login庫就可快速的實現以上的功能,實現起來是很是的便利。

1. 安裝Flask-Login

pip install flask-login

2. 實現登陸功能

2.1 定義login.html模板

{% extends 'base.html' %}

{% block title %}
    登陸頁面
{% endblock %}

{% block content %}
    <form action="" method="post">
        姓名:<input type="text" name="username">
        密碼:<input type="text" name="password">
        <input type="submit" value="提交">
    </form>
{% endblock %}

2.2 實現登陸功能

登陸方法中定義被login_manager.user_loader裝飾的回調函數,回調函數在以下兩個地方被調用:

1)該函數代表當前用戶登陸成功時調用login_user()方法時,會被回調的函數。回調函數實現的功能是向會話上下文session中存儲最爲中間的鍵值對,key爲user_id, value爲當前登陸用戶的ID值。

2)回調函數在訪問任何一個路由地址時也會被調用。

注意: 由於請求上下文在每次創建鏈接時,都須要獲取當前登陸用戶並將當前登陸用戶設置爲全局上下文current_user,所以回調函數返回的是當前登陸系統的用戶對象。

from flask_login import LoginManager, login_required, login_user, logout_user,current_user

# 獲取登陸管理對象
login_manager = LoginManager()  

@login_manager.user_loader
def load_user(user_id):
    # 必須編寫一個函數用於從數據庫加載用戶。
    # 這個函數在login_user(user)存儲當前登陸用戶到session中時,會被調用
    # 在每次訪問地址的時候都被被調用,用於向請求上下文中綁定當前登陸的用戶信息
    return User.query.get(user_id)


@blue.route('/login/', methods=['GET', 'POST'])
def login():
    if request.method == 'GET':
        return render_template('login.html')

    if request.method == 'POST':
        username = request.form.get('username')
        password = request.form.get('password')
        # 校驗用戶名和密碼是否填寫完成
        if not all([username, password]):
            return render_template('login.html')
        # 經過用戶名獲取用戶對象
        user = User.query.filter_by(username=username).first()
        # 校驗密碼是否正確
        if check_password_hash(user.password, password):
            # 實現登陸
            # login_user()可以將已登陸並經過load_user()的用戶對應的User對象保存在session中
            # 在session中會建立一個鍵值對,key爲user_id,value爲當前登陸用戶的id值
            # 若是但願應用記住用戶的登陸狀態, 只須要爲 login_user()的形參 remember 傳入 True 實參就能夠了.
            login_user(user)
            return redirect(url_for('user.index'))
        else:
            flash('用戶名或者密碼錯誤')

        return redirect(url_for('user.index'))

2.3 啓動文件進行配置

session_protection: 設置存儲用戶登陸狀態的安全級別

login_view: 設置登陸驗證失敗的跳轉地址

from user.views import login_manager

app.config['SECRET_KEY'] = os.urandom(24)

# 登陸管理,初始化app
# 能夠設置None,'basic','strong'以提供不一樣的安全等級,通常設置strong,若是發現異常會登出用戶
# session_protection 可以更好的防止惡意用戶篡改 cookies, 當發現 cookies 被篡改時, 該用戶的 session 對象會被當即刪除, 致使強制從新登陸。
login_manager.session_protection='strong'

# 當登陸認證不經過,則跳轉到該地址
login_manager.login_view='user.login'
login_manager.init_app(app)

2.4 訪問首頁,登陸校驗

使用裝飾器login_required()進行登陸校驗。

核心思想: 校驗session中是否存在key爲user_id的鍵值對。若是校驗成功,則繼續訪問被裝飾的函數。若是校驗失敗,則跳轉到啓動文件中定義的login_manager.login_view定義的視圖函數。

@blue.route('/index/')
@login_required
def index():
    return render_template('index.html')

若是登陸校驗成功,則渲染index.html首頁,在頁面中能夠解析全局變量current_user參數。

{% extends 'base.html' %}

{% block title %}
    首頁頁面
{% endblock %}

{% block content %}
    <p>我是首頁</p>
    <p>當前登陸系統用戶爲: {{ current_user.username }}</p>
{% endblock %}

2.5 註銷

使用logout_user()方法實現註銷,核心功能就是刪除當前會話上下文session中的user_id鍵值對。

# 退出
@blue.route('/logout/', methods=['GET'])
@login_required
def logout():
    logout_user()
    return redirect(url_for('user.login'))
相關文章
相關標籤/搜索