zoukankan      html  css  js  c++  java
  • flask基础(中篇)


    目录

    一、session/cookie介绍

    二、使用session实现登录验证

    三、flask扩展之flask-login

    session/cookie

    前言

    Session和Cookie的结合使用,一般有两种存储方式:

    第一种: session数据存储在客户端: Flask采用'secure cookie'方式保存session,即session数据是使用base64编码后保存在客户端的cookie中。也就是说无须依赖第三方数据库保存session数据。

    第二种: session数据存储在服务端,分为以下三步骤:

    步骤1: 当客户端发送请求到服务端的时候,服务端会校验请求中cookie参数中的sessionid值,如果cookie中不存在sessionid则认为客户端访问服务端时,是发起了一个新的会话。

    步骤2: 如果是新的会话,则服务端会传递给客户端一个cookie,并在cookie中存储一个新的sessionid值,并将相关数据保存在session中。

    步骤3: 客户端下次再发送请求的时候,请求上下文对象会携带cookie,通过校验cookie中的sessionid值,即可判断是否是同一会话。

    步骤4: 如果校验会话是同一会话,则可以从session中获取到之前保存的数据。

    访问者的标识问题服务器需要识别来自同一访问者的请求。这主要是通过浏览器的cookie实现的。 访问者在第一次访问服务器时,服务器在其cookie中设置一个唯一的ID号——会话ID(session)。 这样,访问者后续对服务器的访问头中将自动包含该信息,服务器通过这个ID号,即可区 隔不同的访问者。

    官网文档地址

    概念:

    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'))
  • 相关阅读:
    oracle数据库的乱码问题解决方案
    @HTML.checkboxFor()用法
    存储过程实现登录(.net)
    .net中大数据的处理
    xml总结
    获取指定日期是当前月的第几周
    JS中正则方法的使用
    获取指定日期的前一天日期
    通过Oracle函数实现.NET String.Format函数的简单版
    ReportViewer实现多语言
  • 原文地址:https://www.cnblogs.com/zhangliang91/p/11109402.html
Copyright © 2011-2022 走看看