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'
复制代码

 

posted @   三三得九86  阅读(75)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· DeepSeek在M芯片Mac上本地化部署
· 葡萄城 AI 搜索升级:DeepSeek 加持,客户体验更智能
点击右上角即可分享
微信分享提示