django-利用session机制实现唯一登录的例子


Posted in Python onMarch 16, 2020

配置连接数据库

DATABASES = {
  'default': {
    'ENGINE': 'django.db.backends.mysql',
    'NAME': '数据库名称',
    'USER': 'root',
    'PASSWORD': '123456',
    'HOST': '10.18.62.2',
    'PORT': '3306',
  }
}

生成session表

python manage.py makemigrations
python manage.py migrate

登录时记住保存用户登录信息

# 登录验证
def login_ver(request):
  if request.method == 'POST':
    username = request.POST.get('username')
    password = request.POST.get('password')
    '''
    # 用前端输入的用户名,密码去数据库里找到用户的信息
    user=数据库(username,password)
    '''
    # 数据库中得有一张users表
    user = list(Users.objects.filter(username=username,password=password).values())
    # 用户信息记录在session中
    request.session['user'] = user
    # 创建session,否则key为None
    if not request.session.session_key:
      request.session.create()
    # 获取session_key
      key = request.session.session_key
    # 当另一机器登录时,本机器应该被挤下即当前sessionkey失效,后登录的用户的session可用,之前的sessionkey从数据库中删除
    # 获取指定key的session_data,下面用的ORM模型去数据库中取数据
    session_data = list(DjangoSession.objects.filter(session_key=key).values_list('session_data'))[0][0]
    # 删除key不为当前key,session_data等于当前session_data的session记录,从而达到一个账号只能一台机器登录的目的
    models.DjangoSession.objects.filter(session_data=session_data).exclude(session_key=key).delete()

补充知识:Django 用Session和Cookie分别实现记住用户登录状态

简介

由于http协议的请求是无状态的。故为了让用户在浏览器中再次访问该服务端时,他的登录状态能够保留(也可翻译为该用户访问这个服务端其他网页时不需再重复进行用户认证)。我们可以采用Cookie或Session这两种方式来让浏览器记住用户。

Cookie与Session说明与实现

Cookie

说明

Cookie是一段小信息(数据格式一般是类似key-value的键值对),由服务器生成,并发送给浏览器让浏览器保存(保存时间由服务端定夺)。当浏览器下次访问该服务端时,会将它保存的Cookie再发给服务器,从而让服务器根据Cookie知道是哪个浏览器或用户在访问它。(由于浏览器遵从的协议,它不会把该服务器的Cookie发送给另一个不同host的服务器)。

Django中实现Cookie

from django.shortcuts import render, redirect

# 设置cookie
"""
key: cookie的名字
value: cookie对应的值
max_age: cookie过期的时间
"""
response.set_cookie(key, value, max_age)
# 为了安全,有时候我们会调用下面的函数来给cookie加盐
response.set_signed_cookie(key,value,salt='加密盐',...)

# 获取cookie 
request.COOKIES.get(key)
request.get_signed_cookie(key, salt="加密盐", default=None)

# 删除cookie
reponse.delete_cookie(key)

下面就是具体的代码实现了

views.py

# 编写装饰器检查用户是否登录
def check_login(func):
  def inner(request, *args, **kwargs):
    next_url = request.get_full_path()
    # 假设设置的cookie的key为login,value为yes
    if request.get_signed_cookie("login", salt="SSS", default=None) == 'yes':
      # 已经登录的用户,则放行
      return func(request, *args, **kwargs)
    else:
      # 没有登录的用户,跳转到登录页面
      return redirect(f"/login?next={next_url}")

  return inner


# 编写用户登录页面的控制函数
@csrf_exempt
def login(request):
  if request.method == "POST":
    username = request.POST.get("username")
    passwd = request.POST.get("password")
    next_url = request.POST.get("next_url")

    # 对用户进行验证,假设用户名为:aaa, 密码为123
    if username === 'aaa' and passwd == '123':
      # 执行其他逻辑操作,例如保存用户信息到数据库等
      # print(f'next_url={next_url}')
      # 登录成功后跳转,否则直接回到主页面
      if next_url and next_url != "/logout/":
        response = redirect(next_url)
      else:
        response = redirect("/index/")
      # 若登录成功,则设置cookie,加盐值可自己定义取,这里定义12小时后cookie过期
      response.set_signed_cookie("login", 'yes', salt="SSS", max_age=60*60*12)
      return response
    else:
      # 登录失败,则返回失败提示到登录页面
      error_msg = '登录验证失败,请重新尝试'
      return render(request, "app/login.html", {
        'login_error_msg': error_msg,
        'next_url': next_url,
      })
  # 用户刚进入登录页面时,获取到跳转链接,并保存
  next_url = request.GET.get("next", '')
  return render(request, "app/login.html", {
    'next_url': next_url
  })


# 登出页面
def logout(request):
  rep = redirect("/login/")
  # 删除用户浏览器上之前设置的cookie
  rep.delete_cookie('login')
  return rep


# 给主页添加登录权限认证
@check_login
def index(request):
  return render(request, "app/index.html")

由上面看出,其实就是在第一次用户登录成功时,设置cookie,用户访问其他页面时进行cookie验证,用户登出时删除cookie。

另外附上前端的login.html部分代码

<form action="{% url 'login' %}" method="post">
       <h1>请使xx账户登录</h1>
       <div>
        <input id="user" type="text" class="form-control" name="username" placeholder="账户" required="" />
       </div>
       <div>
        <input id="pwd" type="password" class="form-control" name="password" placeholder="密码" required="" />
       </div>
        <div style="display: none;">
          <input id="next" type="text" name="next_url" value="{{ next_url }}" />
        </div>
        {% if login_error_msg %}
          <div id="error-msg">
            <span style="color: rgba(255,53,49,0.8); font-family: cursive;">{{ login_error_msg }}</span>
          </div>
        {% endif %}
       <div>
         <button type="submit" class="btn btn-default" style="float: initial; margin-left: 0px">登录</button>
       </div>
      </form>

Session

Session说明

Session则是为了保证用户信息的安全,将这些信息保存到服务端进行验证的一种方式。但它却依赖于cookie。具体的过程是:服务端给每个客户端(即浏览器)设置一个cookie(从上面的cookie我们知道,cookie是一种”key, value“形式的数据,这个cookie的value是服务端随机生成的一段但唯一的值)。

当客户端下次访问该服务端时,它将cookie传递给服务端,服务端得到cookie,根据该cookie的value去服务端的Session数据库中找到该value对应的用户信息。(Django中在应用的setting.py中配置Session数据库)。

根据以上描述,我们知道Session把用户的敏感信息都保存到了服务端数据库中,这样具有较高的安全性。

Django中Session的实现

# 设置session数据, key是字符串,value可以是任何值
request.session[key] = value
# 获取 session
request.session.get[key]
# 删除 session中的某个数据
del request.session[key]
# 清空session中的所有数据
request.session.delete()

下面就是具体的代码实现了:

首先就是设置保存session的数据库了。这个在setting.py中配置:(注意我这里数据库用的mongodb,并使用了django_mongoengine库;关于这个配置请根据自己使用的数据库进行选择,具体配置可参考官方教程)

SESSION_ENGINE = 'django_mongoengine.sessions'
SESSION_SERIALIZER = 'django_mongoengine.sessions.BSONSerializer'

views.py

# 编写装饰器检查用户是否登录
def check_login(func):
  def inner(request, *args, **kwargs):
    next_url = request.get_full_path()
    # 获取session判断用户是否已登录
    if request.session.get('is_login'):
      # 已经登录的用户...
      return func(request, *args, **kwargs)
    else:
      # 没有登录的用户,跳转刚到登录页面
      return redirect(f"/login?next={next_url}")

  return inner


@csrf_exempt
def login(request):
  if request.method == "POST":
    username = request.POST.get("username")
    passwd = request.POST.get("password")
    next_url = request.POST.get("next_url")
    # 若是有记住密码功能
    # remember_sign = request.POST.get("check_remember")
    # print(remember_sign)

    # 对用户进行验证
    if username == 'aaa' and passwd == '123':
      # 进行逻辑处理,比如保存用户与密码到数据库

      # 若要使用记住密码功能,可保存用户名、密码到session
      # request.session['user_info'] = {
        # 'username': username,
        # 'password': passwd
      # }
      request.session['is_login'] = True
      # 判断是否勾选了记住密码的复选框
      # if remember_sign == 'on':
      #  request.session['is_remember'] = True
      # else:
        # request.session['is_remember'] = False

      # print(f'next_url={next_url}')
      if next_url and next_url != "/logout/":
        response = redirect(next_url)
      else:
        response = redirect("/index/")
      return response
    else:
      error_msg = '登录验证失败,请重新尝试'
      return render(request, "app/login.html", {
        'login_error_msg': error_msg,
        'next_url': next_url,
      })
  next_url = request.GET.get("next", '')
  # 检查是否勾选了记住密码功能
  # password, check_value = '', ''
  # user_session = request.session.get('user_info', {})
  # username = user_session.get('username', '')
  # print(user_session)
  #if request.session.get('is_remember'):
  #  password = user_session.get('password', '')
  #  check_value = 'checked'
  # print(username, password)
  return render(request, "app/login.html", {
    'next_url': next_url,
    # 'user': username,
    # 'password': password,
    # 'check_value': check_value
  })


def logout(request):
  rep = redirect("/login/")
  # request.session.delete()
  # 登出,则删除掉session中的某条数据
  if 'is_login' in request.session:
    del request.session['is_login']
  return rep


@check_login
def index(request):
  return render(request, "autotest/index.html")

另附login.html部分代码:

<form action="{% url 'login' %}" method="post">
       <h1>请使xxx账户登录</h1>
       <div>
        <input id="user" type="text" class="form-control" name="username" placeholder="用户" required="" value="{{ user }}" />
       </div>
       <div>
        <input id="pwd" type="password" class="form-control" name="password" placeholder="密码" required="" value="{{ password }}" />
       </div>
        <div style="display: none;">
          <input id="next" type="text" name="next_url" value="{{ next_url }}" />
        </div>
        {% if login_error_msg %}
          <div id="error-msg">
            <span style="color: rgba(255,53,49,0.8); font-family: cursive;">{{ login_error_msg }}</span>
          </div>
        {% endif %}
        // 若设置了记住密码功能
        // <div style="float: left">
        //   <input id="rmb-me" type="checkbox" name="check_remember" {{ check_value }}/>记住密码
        // </div>
       <div>
         <button type="submit" class="btn btn-default" style="float: initial; margin-right: 60px">登录</button>
       </div>
      </form>

总的来看,session也是利用了cookie,通过cookie生成的value的唯一性,从而在后端数据库session表中找到这value对应的数据。session的用法可以保存更多的用户信息,并使这些信息不易被暴露。

总结

session和cookie都能实现记住用户登录状态的功能,如果为了安全起见,还是使用session更合适

以上这篇django-利用session机制实现唯一登录的例子就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python UnicodeEncodeError: 'gbk' codec can't encode character 解决方法
Apr 24 Python
python 时间戳与格式化时间的转化实现代码
Mar 23 Python
教你用Python写安卓游戏外挂
Jan 11 Python
Python使用matplotlib实现绘制自定义图形功能示例
Jan 18 Python
对numpy中的transpose和swapaxes函数详解
Aug 02 Python
python中对数据进行各种排序的方法
Jul 02 Python
python实现简单日志记录库glog的使用
Dec 13 Python
python中的selenium安装的步骤(浏览器自动化测试框架)
Mar 17 Python
使用Python对Dicom文件进行读取与写入的实现
Apr 20 Python
python实现在线翻译
Jun 18 Python
如何使用python自带IDLE的几种方法
Oct 10 Python
用Python实现定时备份Mongodb数据并上传到FTP服务器
Jan 27 Python
python安装dlib库报错问题及解决方法
Mar 16 #Python
使用python图形模块turtle库绘制樱花、玫瑰、圣诞树代码实例
Mar 16 #Python
关于win10在tensorflow的安装及在pycharm中运行步骤详解
Mar 16 #Python
Python3.6 中的pyinstaller安装和使用教程
Mar 16 #Python
python pandas利用fillna方法实现部分自动填充功能
Mar 16 #Python
Python Flask上下文管理机制实例解析
Mar 16 #Python
Python threading.local代码实例及原理解析
Mar 16 #Python
You might like
ThinkPHP自动验证失败的解决方法
2011/06/09 PHP
PHP数据库调用类调用实例(详细注释)
2012/07/12 PHP
php计算指定目录下文件占用空间的方法
2015/03/13 PHP
php从字符串创建函数的方法
2015/03/16 PHP
PHP怎样用正则抓取页面中的网址
2016/08/09 PHP
CI框架使用composer安装的依赖包步骤与方法分析
2016/11/21 PHP
PHP连接MySQL数据库的三种方式实例分析【mysql、mysqli、pdo】
2019/11/04 PHP
总结AJAX相关JS代码片段和浏览器模型
2007/08/15 Javascript
jQuery 操作下拉列表框实现代码
2010/02/22 Javascript
JQuery中的$.getJSON 使用说明
2011/03/10 Javascript
window.location不跳转的问题解决方法
2014/04/17 Javascript
js实现鼠标悬停图片上时滚动文字说明的方法
2015/02/17 Javascript
JavaScript中诡异的delete操作符
2015/03/12 Javascript
使用RequireJS优化JavaScript引用代码的方法
2015/07/01 Javascript
jquery+ajax请求且带返回值的代码
2015/08/12 Javascript
javascript bom是什么及bom和dom的区别
2015/11/26 Javascript
js HTML5多媒体影音播放
2016/10/17 Javascript
Angualrjs 表单验证的两种方式(失去焦点验证和点击提交验证)
2017/05/09 Javascript
vue项目webpack中Npm传递参数配置不同域名接口
2018/06/15 Javascript
Vue核心概念Action的总结
2019/01/18 Javascript
浅析vue cli3 封装Svgicon组件正确姿势(推荐)
2020/04/27 Javascript
JS call()及apply()方法使用实例汇总
2020/07/11 Javascript
浅谈使用nodejs搭建web服务器的过程
2020/07/20 NodeJs
[50:48]LGD vs CHAOS 2019国际邀请赛小组赛 BO2 第二场 8.15
2019/08/16 DOTA
[01:50:49]DOTA2-DPC中国联赛 正赛 PSG.LGD vs Aster BO3 第三场 1月24日
2021/03/11 DOTA
pandas使用get_dummies进行one-hot编码的方法
2018/07/10 Python
python3.6.3转化为win-exe文件发布的方法
2018/10/31 Python
keras得到每层的系数方式
2020/06/15 Python
一款CSS3实现多功能下拉菜单(带分享按)的教程
2014/11/05 HTML / CSS
使用CSS3实现一个3D相册效果实例
2016/12/03 HTML / CSS
Tod’s英国官方网站:意大利奢华手工制作手袋和鞋履
2019/03/15 全球购物
领导证婚人证婚词
2014/01/13 职场文书
群众路线教育实践活动个人对照检查材料思想汇报(社区班子)
2014/10/06 职场文书
商场收银员岗位职责
2015/04/07 职场文书
物业公司管理制度
2015/08/05 职场文书
年中了,该如何写好个人述职报告?
2019/07/02 职场文书