Django——认证系统(Day72)

阅读目录

  COOKIE 与 SESSION

  用户认证

 

COOKIE 与 SESSION

概念

cookie不属于http协议范围,由于http协议无法保持状态,但实际情况,我们却又需要“保持状态”,因此cookie就是在这样一个场景下诞生。

cookie的工作原理是:由服务器产生内容,浏览器收到请求后保存在本地;当浏览器再次访问时,浏览器会自动带上cookie,这样服务器就能通过cookie的内容来判断这个是“谁”了。

cookie虽然在一定程度上解决了“保持状态”的需求,但是由于cookie本身最大支持4096字节,以及cookie本身保存在客户端,可能被拦截或窃取,因此就需要有一种新的东西,它能支持更多的字节,并且他保存在服务器,有较高的安全性。这就是session。

问题来了,基于http协议的无状态特征,服务器根本就不知道访问者是“谁”。那么上述的cookie就起到桥接的作用。

我们可以给每个客户端的cookie分配一个唯一的id,这样用户在访问时,通过cookie,服务器就知道来的人是“谁”。然后我们再根据不同的cookie的id,在服务器上保存一段时间的私密资料,如“账号密码”等等。

总结而言:cookie弥补了http无状态的不足,让服务器知道来的人是“谁”;但是cookie以文本的形式保存在本地,自身安全性较差;所以我们就通过cookie识别不同的用户,对应的在session里保存私密的信息以及超过4096字节的文本。

另外,上述所说的cookie和session其实是共通性的东西,不限于语言和框架

登陆应用

前几节的介绍中我们已经有能力制作一个登陆页面,在验证了用户名和密码的正确性后跳转到后台的页面。但是测试后也发现,如果绕过登陆页面。直接输入后台的url地址也可以直接访问的。这个显然是不合理的。其实我们缺失的就是cookie和session配合的验证。有了这个验证过程,我们就可以实现和其他网站一样必须登录才能进入后台页面了。

      先说一下这种认证的机制。每当我们使用一款浏览器访问一个登陆页面的时候,一旦我们通过了认证。服务器端就会发送一组随机唯一的字符串(假设是123abc)到浏览器端,这个被存储在浏览端的东西就叫cookie。而服务器端也会自己存储一下用户当前的状态,比如login=true,username=hahaha之类的用户信息。但是这种存储是以字典形式存储的,字典的唯一key就是刚才发给用户的唯一的cookie值。那么如果在服务器端查看session信息的话,理论上就会看到如下样子的字典

{'123abc':{'login':true,'username:hahaha'}}

因为每个cookie都是唯一的,所以我们在电脑上换个浏览器再登陆同一个网站也需要再次验证。那么为什么说我们只是理论上看到这样子的字典呢?因为处于安全性的考虑,其实对于上面那个大字典不光key值123abc是被加密的,value值{'login':true,'username:hahaha'}在服务器端也是一样被加密的。所以我们服务器上就算打开session信息看到的也是类似与以下样子的东西

{'123abc':dasdasdasd1231231da1231231}

知道了原理,下面就来用代码实现。

Django实现的COOKIE

1、获取Cookie

1
2
3
4
5
6
request.COOKIES['key']
request.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None)
    #参数:
        default: 默认值
           salt: 加密盐
        max_age: 后台控制过期时间

2、设置Cookie

1
2
3
4
rep = HttpResponse(...) 或 rep = render(request, ...) 或 rep = redirect()
rep.set_cookie(key,value,...)
rep.set_signed_cookie(key,value,salt='加密盐',...) 

 参数:

复制代码
'''def set_cookie(self, key,                 键value='',            值max_age=None,        超长时间expires=None,        超长时间path='/',           Cookie生效的路径,浏览器只会把cookie回传给带有该路径的页面,这样可以避免将cookie传给站点中的其他的应用。/ 表示根路径,特殊的:根路径的cookie可以被任何url的页面访问domain=None,         Cookie生效的域名你可用这个参数来构造一个跨站cookie。如, domain=".example.com"所构造的cookie对下面这些站点都是可读的:www.example.com 、 www2.example.com 
                         和an.other.sub.domain.example.com 。如果该参数设置为 None ,cookie只能由设置它的站点读取。secure=False, 如果设置为 True ,浏览器将通过HTTPS来回传cookie。httponly=False 只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)): pass'''
复制代码

由于cookie保存在客户端的电脑上,所以,JavaScript和jquery也可以操作cookie。

1
2
3
<script src='/static/js/jquery.cookie.js'>
</script> $.cookie("key", value,{ path: '/' });

3 删除cookie

1
response.delete_cookie("cookie_key",path="/",domain=name)

 cookie存储到客户端
       优点:
           数据存在在客户端,减轻服务器端的压力,提高网站的性能。
       缺点:
           安全性不高:在客户端机很容易被查看或破解用户会话信息

Django实现的SESSION

1、 基本操作

1
2
3
4
5
6
7
8
1、设置Sessions值
          request.session['session_name'="admin"
2、获取Sessions值
          session_name = request.session["session_name"]
3、删除Sessions值
          del request.session["session_name"]
4、检测是否操作session值
          if "session_name" is request.session :

2、 流程解析图

 3、 示例

views:

def log_in(request):if request.method=="POST":username=request.POST['user']password=request.POST['pwd']user=UserInfo.objects.filter(username=username,password=password)if user:#设置session内部的字典内容request.session['is_login']='true'request.session['username']=username#登录成功就将url重定向到后台的urlreturn redirect('/backend/')#登录不成功或第一访问就停留在登录页面return render(request,'login.html')def backend(request):print(request.session,"------cookie")print(request.COOKIES,'-------session')"""这里必须用读取字典的get()方法把is_login的value缺省设置为False,当用户访问backend这个url先尝试获取这个浏览器对应的session中的is_login的值。如果对方登录成功的话,在login里就已经把is_login的值修改为了True,反之这个值就是False的"""is_login=request.session.get('is_login',False)#如果为真,就说明用户是正常登陆的if is_login:#获取字典的内容并传入页面文件cookie_content=request.COOKIESsession_content=request.sessionusername=request.session['username']return render(request,'backend.html',locals())else:"""如果访问的时候没有携带正确的session,就直接被重定向url回login页面"""return redirect('/login/')def log_out(request):"""直接通过request.session['is_login']回去返回的时候,如果is_login对应的value值不存在会导致程序异常。所以需要做异常处理"""try:#删除is_login对应的value值del request.session['is_login']# OR---->request.session.flush() # 删除django-session表中的对应一行记录except KeyError:pass#点击注销之后,直接重定向回登录页面return redirect('/login/')

template:

===================================login.html==================
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body><form action="/login/" method="post"><p>用户名: <input type="text" name="user"></p><p>密码: <input type="password" name="pwd"></p><p><input type="submit"></p>
</form></body>
</html>===================================backend.html==================<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body><h3>hello {{ username }}</h3>
<a href="/logout/">注销</a></body>
</html>

4、session存储的相关配置

(1)数据库配置(默认):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Django默认支持Session,并且默认是将Session数据存储在数据库中,即:django_session 表中。
  
a. 配置 settings.py
  
    SESSION_ENGINE = 'django.contrib.sessions.backends.db'   # 引擎(默认)
      
    SESSION_COOKIE_NAME = "sessionid"                       # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认)
    SESSION_COOKIE_PATH = "/"                               # Session的cookie保存的路径(默认)
    SESSION_COOKIE_DOMAIN = None                             # Session的cookie保存的域名(默认)
    SESSION_COOKIE_SECURE = False                            # 是否Https传输cookie(默认)
    SESSION_COOKIE_HTTPONLY = True                           # 是否Session的cookie只支持http传输(默认)
    SESSION_COOKIE_AGE = 1209600                             # Session的cookie失效日期(2周)(默认)
    SESSION_EXPIRE_AT_BROWSER_CLOSE = False                  # 是否关闭浏览器使得Session过期(默认)
    SESSION_SAVE_EVERY_REQUEST = False                       # 是否每次请求都保存Session,默认修改之后才保存(默认)

(2)缓存配置 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
a. 配置 settings.py
  
    SESSION_ENGINE = 'django.contrib.sessions.backends.cache'  # 引擎
    SESSION_CACHE_ALIAS = 'default'                            # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置
  
  
    SESSION_COOKIE_NAME = "sessionid"                        # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串
    SESSION_COOKIE_PATH = "/"                                # Session的cookie保存的路径
    SESSION_COOKIE_DOMAIN = None                              # Session的cookie保存的域名
    SESSION_COOKIE_SECURE = False                             # 是否Https传输cookie
    SESSION_COOKIE_HTTPONLY = True                            # 是否Session的cookie只支持http传输
    SESSION_COOKIE_AGE = 1209600                              # Session的cookie失效日期(2周)
    SESSION_EXPIRE_AT_BROWSER_CLOSE = False                   # 是否关闭浏览器使得Session过期
    SESSION_SAVE_EVERY_REQUEST = False                        # 是否每次请求都保存Session,默认修改之后才保存

(3)文件配置

1
2
3
4
5
6
7
8
9
10
11
12
a. 配置 settings.py
  
    SESSION_ENGINE = 'django.contrib.sessions.backends.file'    # 引擎
    SESSION_FILE_PATH = None                                    # 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir()        
    SESSION_COOKIE_NAME = "sessionid"                          # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串
    SESSION_COOKIE_PATH = "/"                                  # Session的cookie保存的路径
    SESSION_COOKIE_DOMAIN = None                                # Session的cookie保存的域名
    SESSION_COOKIE_SECURE = False                               # 是否Https传输cookie
    SESSION_COOKIE_HTTPONLY = True                              # 是否Session的cookie只支持http传输
    SESSION_COOKIE_AGE = 1209600                                # Session的cookie失效日期(2周)
    SESSION_EXPIRE_AT_BROWSER_CLOSE = False                     # 是否关闭浏览器使得Session过期
    SESSION_SAVE_EVERY_REQUEST = False                          # 是否每次请求都保存Session,默认修改之后才保存

 

用户认证 

auth模块

1
from django.contrib import auth

django.contrib.auth中提供了许多方法,这里主要介绍其中的三个:

1 、authenticate()   

提供了用户认证,即验证用户名以及密码是否正确,一般需要username  password两个关键字参数

如果认证信息有效,会返回一个  User  对象。authenticate()会在User 对象上设置一个属性标识那种认证后端认证了该用户,且该信息在后面的登录过程中是需要的。当我们试图登陆一个从数据库中直接取出来不经过authenticate()的User对象会报错的!!

1
user = authenticate(username='someone',password='somepassword')

2 、login(HttpRequest, user)  

该函数接受一个HttpRequest对象,以及一个认证了的User对象

此函数使用django的session框架给某个已认证的用户附加上session id等信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
from django.contrib.auth import authenticate, login
   
def my_view(request):
  username = request.POST['username']
  password = request.POST['password']
  user = authenticate(username=username, password=password)
  if user is not None:
    login(request, user)
    # Redirect to a success page.
    ...
  else:
    # Return an 'invalid login' error message.
    ...

3 、logout(request) 注销用户  

1
2
3
4
5
from django.contrib.auth import logout
   
def logout_view(request):
  logout(request)
  # Redirect to a success page.

该函数接受一个HttpRequest对象,无返回值。当调用该函数时,当前请求的session信息会全部清除。该用户即使没有登录,使用该函数也不会报错。

4 、user对象的 is_authenticated()

要求:

1  用户登陆后才能访问某些页面,

2  如果用户没有登录就访问该页面的话直接跳到登录页面

3  用户在跳转的登陆界面中完成登陆后,自动访问跳转到之前访问的地址

方法1:

1
2
3
def my_view(request):
  if not request.user.is_authenticated():
    return redirect('%s?next=%s' % (settings.LOGIN_URL, request.path))

方法2:

django已经为我们设计好了一个用于此种情况的装饰器:login_requierd()

1
2
3
4
5
from django.contrib.auth.decorators import login_required
      
@login_required
def my_view(request):
  ...

若用户没有登录,则会跳转到django默认的 登录URL '/accounts/login/ ' (这个值可以在settings文件中通过LOGIN_URL进行修改)。并传递  当前访问url的绝对路径 (登陆成功后,会重定向到该路径)。

User对象

User 对象属性:username, password(必填项)password用哈希算法保存到数据库

is_staff : 用户是否拥有网站的管理权限.

is_active : 是否允许用户登录, 设置为``False``,可以不用删除用户来禁止 用户登录

 

2.1 、is_authenticated()

如果是真正的 User 对象,返回值恒为 True 。 用于检查用户是否已经通过了认证。
通过认证并不意味着用户拥有任何权限,甚至也不检查该用户是否处于激活状态,这只是表明用户成功的通过了认证。 这个方法很重要, 在后台用request.user.is_authenticated()判断用户是否已经登录,如果true则可以向前台展示request.user.name

2.2 、创建用户

使用 create_user 辅助函数创建用户:

1
2
from django.contrib.auth.models import User
user = User.objects.create_user(username='',password='',email='')

2.3 、check_password(passwd)

1
用户需要修改密码的时候 首先要让他输入原来的密码 ,如果给定的字符串通过了密码检查,返回 True

2.4 、修改密码

使用 set_password() 来修改密码

1
2
3
user = User.objects.get(username='')
user.set_password(password='')
user.save 

2.5 、简单示例

注册:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
def sign_up(request):
    state = None
    if request.method == 'POST':
        password = request.POST.get('password', '')
        repeat_password = request.POST.get('repeat_password', '')
        email=request.POST.get('email', '')
        username = request.POST.get('username', '')
        if User.objects.filter(username=username):
                state = 'user_exist'
        else:
                new_user = User.objects.create_user(username=username, password=password,email=email)
                new_user.save()
                return redirect('/book/')
    content = {
        'state': state,
        'user'None,
    }
    return render(request, 'sign_up.html', content)  

修改密码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@login_required
def set_password(request):
    user = request.user
    state = None
    if request.method == 'POST':
        old_password = request.POST.get('old_password', '')
        new_password = request.POST.get('new_password', '')
        repeat_password = request.POST.get('repeat_password', '')
        if user.check_password(old_password):
            if not new_password:
                state = 'empty'
            elif new_password != repeat_password:
                state = 'repeat_error'
            else:
                user.set_password(new_password)
                user.save()
                return redirect("/log_in/")
        else:
            state = 'password_error'
    content = {
        'user': user,
        'state': state,
    }
    return render(request, 'set_password.html', content)

转载于:https://www.cnblogs.com/shaojiafeng/p/7761572.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/393504.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

description方法

1.description基本概念 NSLog("%", objectA);这会自动调用objectA的description方法来输出ObjectA的描述信息. description方法默认返回对象的描述信息(默认实现是返回类名和对象的内存地址) description方法是基类NSObject 所带的方法,因为其默认实现是返回类名和…

leetcode面试题 10.05. 稀疏数组搜索(二分法)

稀疏数组搜索。有个排好序的字符串数组&#xff0c;其中散布着一些空字符串&#xff0c;编写一种方法&#xff0c;找出给定字符串的位置。 示例1: 输入: words [“at”, “”, “”, “”, “ball”, “”, “”, “car”, “”, “”,“dad”, “”, “”], s “ta” 输出…

laravel框架制作缩略图和水印

1.首先需要使用 composer 在命令行安装最新版本的 intervention/image &#xff1a; composer require intervention/image2.注册服务提供者及别名&#xff08;Laravel 版本 ≤ 5.4&#xff09; 如果你的 laravel 版本小于或等于 5.4&#xff0c;安装后需要注册服务提供者和别…

mysql 模糊查询 tp框架_TP框架中模糊查询实现

TP框架中模糊查询实现$where[g.name] array(like,%.$groupname.%);表达式查询上面的查询条件仅仅是一个简单的相等判断&#xff0c;可以使用查询表达式支持更多的SQL查询语法&#xff0c;查询表达式的使用格式&#xff1a;$map[字段1] array(表达式,查询条件1);$map[字段2] ar…

肉体之爱的解释圣经_可以解释的AI简介,以及我们为什么需要它

肉体之爱的解释圣经by Patrick Ferris帕特里克费里斯(Patrick Ferris) 可以解释的AI简介&#xff0c;以及我们为什么需要它 (An introduction to explainable AI, and why we need it) Neural networks (and all of their subtypes) are increasingly being used to build pro…

Python可变与不可变类型及垃圾回收机制

1. 可变与不可变类型 1.1 可变类型 在id不变的情况下&#xff0c;value可以改变&#xff0c;则称之为可变类型。列表、字典与集合是可变的。 l1 [1,2,3,4,5] print(id(l1)) l1[1] 520 #改变列表元素 print(id(l1)) result&#xff1a; 1700748379208 …

12-1 12 防盗链 访问控制 php解析 代理

2019独角兽企业重金招聘Python工程师标准>>> 12.13 Nginx防盗链 12.14 Nginx访问控制 12.15 Nginx解析php相关配置 12.16 Nginx代理 扩展 502问题汇总 http://ask.apelearn.com/question/9109location优先级 http://blog.lishiming.net/?p10012.13 Nginx防盗链 用来…

leetcode911. 在线选举(二分法)

在选举中&#xff0c;第 i 张票是在时间为 times[i] 时投给 persons[i] 的。 现在&#xff0c;我们想要实现下面的查询函数&#xff1a; TopVotedCandidate.q(int t) 将返回在 t 时刻主导选举的候选人的编号。 在 t 时刻投出的选票也将被计入我们的查询之中。在平局的情况下&…

1-13句子逆序

题目描述 将一个英文语句以单词为单位逆序排放。例如“I am a boy”&#xff0c;逆序排放后为“boy a am I”所有单词之间用一个空格隔开&#xff0c;语句中除了英文字母外&#xff0c;不再包含其他字符 接口说明 /** * 反转句子 * * param sentence 原句子 * return 反转后的…

单例模式实现DB类

创建一个类 class DB_class {//public $name andy;//私有的属性private static $db;//公共的静态方法public static function index(){if (self::$db ! null ){return self::$db;}self::$dbnew DB_class();return self::$db;}//私有的构造方法private function __construct()…

终端定时任务 开始缓冲_如何开始使用终端以提高生产力

终端定时任务 开始缓冲by Luciano Strika通过卢西亚诺斯特里卡(Luciano Strika) 如何开始使用终端以提高生产力 (How to start using the terminal to be more productive) As developers, the terminal can be our second home.作为开发人员&#xff0c;码头可以成为我们的第…

图片预览------photoswipe 使用

photoswipe 使用 预览图片后&#xff0c;需要点击关闭按钮才能关闭&#xff0c;点击图片事件效果是放大图片&#xff0c;和微信的效果不一致&#xff0c;最后改用微信预览图片的接口了&#xff0c;但是例子可以用&#xff0c;记录一下&#xff01;&#xff01; http://www.cnbl…

SSKeychain

Keychain 使用? ---为了实用最大化我觉得我应该直接先说使用&#xff01; 当然是使用第三方库啦&#xff1a;sskeychain 3000星星的库不开玩笑。github地址&#xff1a;https://github.com/soffes/sskeychain 导入完之后首先&#xff0c;编译一下有无错。 如果是自己手动导入&…

shell高级-----正则表达式

正则表达式概述 正则表达式是一种定义的规则&#xff0c;Linux工具可以用它来过滤文本。 基础正则表达式 纯文本 [rootnode1 ~]# echo "this is a cat" | sed -n /cat/p this is a cat [rootnode1 ~]# echo "this is a cat" | gawk /cat/{print $0} this …

leetcode130. 被围绕的区域(bfs)

给定一个二维的矩阵&#xff0c;包含 ‘X’ 和 ‘O’&#xff08;字母 O&#xff09;。 找到所有被 ‘X’ 围绕的区域&#xff0c;并将这些区域里所有的 ‘O’ 用 ‘X’ 填充。 示例: X X X X X O O X X X O X X O X X 运行你的函数后&#xff0c;矩阵变为&#xff1a; X X…

linux mysql提交_MySQL 事务提交过程

开发老大要求通过binlog查询一条被修改的数据&#xff0c;数据被查出后问我&#xff0c;有没有可能binlog中不会记录&#xff0c;回答不会&#xff0c;因为数据被修改&#xff0c;若失败直接回滚&#xff0c;不会在binlog中记录&#xff0c;此刻一个朋友用了洪荒之力告诉我&…

spray.json_如何使用Spray-json(Un)在Akka HTTP中封送JSON

spray.jsonby Miguel Lopez由Miguel Lopez 如何使用Spray-json(Un)在Akka HTTP中封送JSON (How to (Un)marshal JSON in Akka HTTP with spray-json) In the previous post, we added JSON support to our Akka HTTP API using circe.在上一篇文章中 &#xff0c;我们使用circ…

React单元测试:Jest + Enzyme(二)

前言 在上一篇教程中&#xff0c;我们成功搭建了基于Jest和Enzyme的单元测试框架并成功地跑起来第一个单元测试&#xff0c;可以点击这里回顾一下。今天&#xff0c;我们重点讨论如何通过Jest来mock数据。 什么是Mock Mock的简单翻译就是模拟。既可以模拟数据&#xff0c;也可以…

input file 文件上传,js控制上传文件的大小和格式

文件上传一般是用jquery的uploadify&#xff0c;比较好用。后面会出文章介绍uploadify这个插件。 但是&#xff0c;有时候为了偷懒&#xff0c;直接就用input 的file进行文件和图片等的上传&#xff0c;input file 可以控制上传的格式&#xff0c;但是是html5&#xff0c;很多浏…

leetcode面试题 17.08. 马戏团人塔(二分法)

有个马戏团正在设计叠罗汉的表演节目&#xff0c;一个人要站在另一人的肩膀上。出于实际和美观的考虑&#xff0c;在上面的人要比下面的人矮一点且轻一点。已知马戏团每个人的身高和体重&#xff0c;请编写代码计算叠罗汉最多能叠几个人。 示例&#xff1a; 输入&#xff1a;…