11_09、cooki和session、中间件、auth模块
一、cookie和session理论
1、保存个人数据的技术
在学习前端的时候,我们了解过http协议的四大特征:基于请求相应,作用域应用层,无状态,短连接
其中无状态指的就是,网页无法保存用户信息,没有数据的交互,哥哥网页只是静态的页面,网页无法保存用户信息
但是随着电商等发展,需要网页中注册登录来识别用户的个人信息,与服务器交互以便更好的提供服务,这种需要保存用户信息的技术也呼之欲出了
常见的包括cookie,session,token,json web token => jwt
2、cookie
cookie把用户信息保存到浏览器端
cookie工作原理,以登录功能为例:
当用户登陆成功后,Django后端会把用户数据保存到浏览器中
下次访问网站时,浏览器会自动把用户数据传递到后端
如果Django从cookie中拿到了用户信息,说明已经登录,否则就是没登录
3、session
cookie虽然能够保存用户信息,但是保存在浏览器中的cookie信息,安全性不能保证
session就是基于cookie,把数据存储到服务端,以此保证了用户信息的安全
session工作原理,以登录功能为例:
当用户登录成功后:
1.Django后端会把用户信息存到MySQL中
2.Django后端会随机生成一段字符串,并把这段字符串再次保存到浏览器cookie中
3.当用户再次访问网站时,浏览器带着这个cookie发送到后端,Django后端通过拿到这个cookie值去数据库查询,如果查到,说明登录,否则未登录
4、总结
1.cookie数据存放在浏览器中
2.session数据存放在服务端汇总
3.session是基于cookie工作的
4.用户可以主动禁止cookie的保存
5.用户禁止cookie,session在一些情况下依然可以使用
一,把session中的字符串一参数形式传递到后端
二,我们可以把session随机字符串放在请求头中
二、Django操作cookie
以登录功能为例
'''Django操作cookie''' def login(request): if request.method == 'POST': username = request.POST.get('username') password = request.POST.get('password') # userinfo = models.Book.objects.filter(username=username, password=password).first() if username == 'ly' and password == '123': # 记录用户的信息,才能证明用户登录成功了 # 我们把用户信息保存到cookie中, '''只要保存用户信息,就要借助于HttpResponse对象''' obj = redirect('/home/') '''cookie的存在形式是:k:v的''' # 设置cookie ''' max_age=None, expires=None, 过期时间 expires:用在IE浏览器上 max_age=None, 其他浏览器上 path='/', 设置cookie的生效路径, domain=None, 在某个域名下生效,默认是当前域名下 secure=False, 安全 httponly=True 只能通过http请求才能获取cookie 也可以通过js设置cookie和获取cookie, ''' # max_age=20 20秒之后cookie自动失效 obj.set_cookie('username', 'ly', max_age=20) obj.set_cookie('id', 1, max_age=20) obj.set_cookie('aa', 'bb', max_age=20) obj.set_cookie('cc', 'dd', max_age=20) return obj return render(request, 'login.html') '''验证是否登录的装饰器''' def login_auth(func): def inner(request, *args, **kwargs): # request = args[0] if not request.COOKIES.get('username'): return redirect('/login/') else: return func(request, *args, **kwargs) return inner
三、Django操作session
1、Django中Session相关方法
# 获取、设置、删除Session中数据 request.session['k1'] request.session.get('k1',None) request.session['k1'] = 123 request.session.setdefault('k1',123) # 存在则不设置 del request.session['k1'] # 所有 键、值、键值对 request.session.keys() request.session.values() request.session.items() request.session.iterkeys() request.session.itervalues() request.session.iteritems() # 会话session的key request.session.session_key # 将所有Session失效日期小于当前日期的数据删除 request.session.clear_expired() # 检查会话session的key在数据库中是否存在 request.session.exists("session_key") # 删除当前会话的所有Session数据(只删数据库) request.session.delete() # 删除当前的会话数据并删除会话的Cookie(数据库和cookie都删)。 request.session.flush() 这用于确保前面的会话数据不可以再次被用户的浏览器访问 例如,django.contrib.auth.logout() 函数中就会调用它。 # 设置会话Session和Cookie的超时时间 request.session.set_expiry(value) * 如果value是个整数,session会在些秒数后失效。 * 如果value是个datatime或timedelta,session就会在这个时间后失效。 * 如果value是0,用户关闭浏览器session就会失效。 * 如果value是None,session会依赖全局session失效策略。
2、Django中的Session配置
1. 数据库Session SESSION_ENGINE = 'django.contrib.sessions.backends.db' # 引擎(默认) 2. 缓存Session SESSION_ENGINE = 'django.contrib.sessions.backends.cache' # 引擎 SESSION_CACHE_ALIAS = 'default' # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置 3. 文件Session SESSION_ENGINE = 'django.contrib.sessions.backends.file' # 引擎 SESSION_FILE_PATH = None # 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir() 4. 缓存+数据库 SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db' # 引擎 5. 加密Cookie Session SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies' # 引擎 其他公用设置项: 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、清空session
'''清空session''' def del_Session(request): request.session.flush() # 把所有的session全部清空,不但清空session,还清除cookie request.session.delete('username') request.session.delete('id') request.session.delete() # 把所有的session全部清除
4、总结:
session的默认过期时间:14天
同一个IP地址(同一个电脑)的电脑同一个浏览器,session只会存一条记录
四、CBV添加装饰器
# @method_decorator(login_auth, 'get') # @method_decorator(login_auth, 'post') # 第二种方式 class IndexView(View): '''必须登录之后才允许访问''' @method_decorator(login_auth) # 给所有的方法加 def dispatch(self, request, *args, **kwargs): return super().dispatch(request, *args, **kwargs) # @login_auth # 不能这样加了 # @method_decorator(login_auth) # 第一种方式 def get(self, request): return HttpResponse('get')
五、中间件的理论介绍
中间件是指settings.py文件中的MIDDLEWARE
MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ]
Django中默认有七个中间件,它是七个路径,可以转换成:
from django.middleware.security import SecurityMiddleware from django.contrib.sessions.middleware import SessionMiddleware ...
中间件的特点:中间件都是一个继承MiddlewareMixin的类
需要我们掌握的几个方法: process_request: '''请求来的时候走''' process_response: '''响应走的时候会走''' 了解: process_view process_exception process_template
# 中间件的作用: 1. 频率的限制 2. 权限认证 3. 认证
注意:中间的作用可以结合Django请求生命周期流程图
六、自定义中间件
1、自定义中间件:
1. 在任何一个应用下面,创建一个py文件
2. 在这个py文件中,写一个类,继承MiddlewareMixin
3. 中间件写完之后,一定要去配置文件注册中间件
2、具体操作
# 创建mydd.py文件 from django.shortcuts import render, HttpResponse, redirect from django.utils.deprecation import MiddlewareMixin
class MyMiddleware(MiddlewareMixin): def process_request(self, request): # 必修登录之后才能往下 print('第一个process_request') # return HttpResponse('第一个process_request') def process_response(self, request, response): print('第一个process_response') # 必须要有返回值 return response
''' 注意: 如果在process_request方法中有返回值了,视图函数不在执行,在执行同级别的process_response '''
配置文件注册中间件
MIDDLEWARE = [ 'app01.mydd.MyMiddleware', ] # 注册中间件
3、中间件的执行顺序
第一步:按照正常顺序,所有中间件的process_request先从上到下执行一遍
第二步:执行函数
第三步:按照反向顺序,所有中间件的process_response从下往上执行一遍
七、csrf跨站请求处理
1、什么是csrf跨站请求
csrf跨站请求保障:浏览器向服务端请求数据(post)的时候,只有本网页的post请求可以通过,其他的请求已改不予通过,保证了安全
适用:会出现在form表单中,action参数,指定朝后端发送的地址
常见的csrf跨站请求攻击:钓鱼网站
2、如何使用
form表单跨站请求
<form action="" method="post"> {% csrf_token %} <p> username:<input type="text" name="username"> </p> <input type="submit" value="提交"> </form>
ajax跨站请求(两种方式)
<script> $('.btn').click(function () { {#var a = $('[name="csrfmiddlewaretoken"]').val();#} $.ajax({ url:'', type:'post', // 第一种方式 {#data:{'a':1, csrfmiddlewaretoken:'a'},#} // 第二种方式 data:{'a':1, csrfmiddlewaretoken:'{{ csrf_token }}'}, success:function () { } }) }) </script>
八、csrf相关装饰器
1、为什么要用到csrf装饰器
默认情况,csrf的中间件要么全部验证,要么全部不验证,但是实际情况下:
有几个函数是不需要验证的,其他的都验证;有几个函数需要验证,其他的函数都不验证
针对上述问题,Django提供了2个装饰器:
csrf_protect: 某些函数需要验证
csrf_exempt:某些函数不需要验证
2、fbv加csrf装饰器
直接在函数上面加
from django.views.decorators.csrf import csrf_exempt, csrf_protect # 不注释中间件,需要验证函数index @csrf_protect def index(request): return render(request) # 不注释中间件,不需要验证函数index @csrf_exempt def home(request): return render(request)
3、cbv加csrf装饰器
针对csrf_protect三种方式都可以
针对csrf_exempt第一种方式不可以,第二种方式不可以,第三张方式可以
from django.views import View from django.shortcuts import HttpResponse # @method_decorator(csrf_protect, 'post') # 第二种方式可以 # @method_decorator(csrf_exempt, 'post') # 第二种方式可以 class CbvView(View): # @method_decorator(csrf_protect) @method_decorator(csrf_exempt) def dispatch(self, request, *args, **kwargs): return super().dispatch(request, *args, **kwargs) def get(self, request): return HttpResponse('get') # @method_decorator(csrf_protect) # 第一种方式可以 # @method_decorator(csrf_exempt) def post(self, request):
九、auth模块介绍
1、auth模块介绍
迁移数据库的时候,生成了很多张表,其中有一张表auth_user,admin/后台登录参考的数据就是auth_user表
路由文件中,有一个admin/的路由,Django自带的后台管理系统,可以通过浏览器范围访问
# 配置文件设置语言
# LANGUAGE_CODE = 'en-us' # 英文 LANGUAGE_CODE = 'zn-hans' # 中文
要想登录后台,必须是超级管理员,如何生成超级管理员账号?
'''创建超级管理员账号:'''
方式一cmd:
python3 manage.py createsuperuser
方式二pycharm控制台:
createsuperuser
2、auth注册账号
from django.contrib.auth.models import User
# 相当于auth_user的表模型
def reg(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
# 入库
# User.objects.create(username=username, password=password) # 入库之后,密码没有加密
# User.objects.create_user(username=username, password=password) # 入库之后,密码加密,普通身份
User.objects.create_superuser(username=username, password=password) # 超级管理员
3、auth实现登录
# 注册,登录,退出系统,修改密码... # 登录功能 from django.contrib import auth '''auth模块要用就用全套的,不要只用一部分''' def login(request): if request.method == 'POST': username = request.POST.get('username') password = request.POST.get('password') # 验证用户名和是否正确?参考的数据表是谁呢?auth_user表 '''传值的话,要把用户名和密码同时传入,不能只传入用户名''' user_obj = auth.authenticate(request, username=username, password=password) print(user_obj) if user_obj: '''保存用户信息到session中''' # request.session['username'] = user_obj.username # request.session['id'] = user_obj.id auth.login(request, user_obj) ''' 你只要写了auth.login,把数据给你存储到session了,在全局任何位置都能够通过 request.user属性拿到用户信息,因为login方法给你吧用户信息封装到了request.user中了 ''' return redirect('/home/') return render(request, 'auth/login.html')
<form action="" method="post"> <p>username:<input type="text" name="username"></p> <p>password:<input type="password" name="password"></p> <input type="submit" value="提交"> </form>
4、auth验证是否登录
# auth,模块提供了一个装饰器,验证是否登录的 from django.contrib.auth.decorators import login_required # @login_required # @login_required(login_url='/app02/login/') 括号里面表示如果未登录,自动跳转到指定页面 ''' 当局部和全局都存在的时候,局部大于全局的
全局配置:
LOGIN_URL = '/自定义位置(一般是登录界面login)/'
''' @login_required(login_url='/app02/login/') def func(request): print(request.user) # admin print(request.user) # AnonymousUser 匿名用户 # 判断是否登录 print(request.user.is_authenticated()) # False 没有登录 print(request.user.is_authenticated()) # True 登录了 # if request.user.is_authenticated(): # return HttpResponse('登录了') # else: # return HttpResponse('未登录') return HttpResponse('func')
5、修改密码
@login_required def set_pwd(request): if request.method == 'POST': old_pwd = request.POST.get('old_pwd') new_pwd = request.POST.get('new_pwd') re_pwd = request.POST.get('re_pwd') '''1. 先验证两次密码是否一致''' if new_pwd == re_pwd: '''2. 老密码是否正确''' is_right = request.user.check_password(old_pwd) # True, False if is_right: '''3. 操作数据库,修改密码''' request.user.set_password(new_pwd) # 修改密码,只写这一句不行,这一句并没有真正的修改数据库 request.user.save() # 这一句才真正的操作数据库的修改操作 return redirect('/app02/login') return render(request, 'auth/set_pwd.html')
<form action="" method="post"> <p>原密码:<input type="text" name="old_pwd"></p> <p>新密码:<input type="text" name="new_pwd"></p> <p>确认密码:<input type="text" name="re_pwd"></p> <input type="submit" value="提交"> </form>
6、扩展auth_user表
from django.contrib.auth.models import AbstractUser '''扩展auth_user表的时候,必须继承AbstractUser类''' class UserInfo(AbstractUser): ''' 1. 如果你已经执行了数据库迁移命令了,那么,就不能再扩展了,非要扩展也行,只不过太麻烦了(删除三分迁移记录——配置文件、应用、数据库) 2. 扩展表之后,不要动原来的字段,你自己只需要写你要扩展的字段就行 3. auth_user表已经不存在了,而是生成一张新的表UserInfo 4. 需要到配置文件中配置 AUTH_USER_MODEL = '应用名.UserInfo' 5. 在执行数据库迁移命令之前,进行扩展 ''' phone = models.CharField(max_length=32) avatar = models.CharField(max_length=32) # 扩展表,需要配置 AUTH_USER_MODEL = 'app02.UserInfo'
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· DeepSeek在M芯片Mac上本地化部署
· 葡萄城 AI 搜索升级:DeepSeek 加持,客户体验更智能