csrf跨站请求、相关装饰器、auth模块使用

昨日内容回顾

  • django操作cookie和session
# 作用:就是保存用户信息,保存一系列数据,还可以做缓存 保留一段时间

# session是基于cookie工作的
	1. 数据是保存在服务端
	2. 存储的介质:
		01 文件
		02 数据库
		03 redis
		3. 如果以后项目中使用了负载均衡,注意考虑是否有session共享的问题

# 如何使用session:
	1. 设置session
		request.session['username'] = 'aaa'
		request.session['id'] = 111
		'''
		1. 生成一个随机字符串,
		2. 保存数据到数据库中
			session_key  session_data
		3. 把数据加密处理之后保存的。
		'''
	2. 获取session
		request.session['username']
		# session设置的时候,是被加密的,获取出来的session值是明文的
		'''
		1. 先拿到sessionid  => session中的随机字符串 session_key
		2. 会拿着sessionid的值去表中查询
			如果有数据,进行反解密,在把数据封装到request.session中,因此,我们直接可以通过request.session['id'] 取值
		'''
        
	# 以上操作是在中间件中处理的,sessionmiddleware
    
# 如何设置session的过期时间
	request.session.set_expity(120)
    
# 设置会话Session和Cookie的超时时间
	'''
		request.session.set_expiry(value)
		* 如果value是个整数,session会在些秒数后失效
		* 如果value是个datatime或timedelta,session就会在这个时间后失效
		* 如果value是0,用户关闭浏览器session就会失效
		* 如果value是None,session会依赖全局session失效策略
	'''
  • CBV添加装饰器
# FBV:直接在函数的头上面添加装饰器的名称

# CBV:添加装饰器与FBV添加装饰器是有区别的
	cbv添加装饰器需要借助于一个装饰器
    
from django.utils.decorators import method_dectorator

'''drf:django rest framework => '''
from django.views import View

'''
请求方式:8种, get, post,
	options
	put
	patch
在前后端分离项目中,会出现跨域问题 简单请求,复杂请求
'''
@method_decorators(login_auth, 'get')
@method_decorators(login_auth, 'post')
@method_decorators(login_auth, 'patch')
class IndexView(View):
    # 重写父类的方法
    @method_decorators()  # 给IndexView所有的方法添加装饰器
    def dispatch(self, request, *args, **kwargs):
        # 依据:mro列表
        return super().dispatch(request, *args, **kwargs):
    
    @method_decorators(login_auth)
    def get(self, request):
        return HttpResponse('ok')
  • 中间件
# 1. 中间件的位置在哪里?在路由层之前
	django提供了7个中间件,在配置文件中,我们是可以查询这七个中间件的源码的

# 2. csrf的中间件, 针对于post请求的提交做csrf的校验

# 3. 支持我们自定义中间件
	3.1 在任意一个应用下,创建一个py文件
	3.2 写一个类,类里面有2个方法,类必须继承middlewaremixin
	3.3 去配置文件中注册中间件
    
# 需要我们掌握的是2个方法:
	1. process_request
		# 请求来的时候,会按照中间的注册顺序,依次从上往下执行
        
	2. procesS_resposne
		# 请求走的时候,会按照中间件的注册顺序,依次从下往上执行。
		'''
		视图函数在所有中间件的process_request之后,所有中间件的process_response之前
		'''
        
		# 如果我们在某一个中间件中的process_reqeust返回了值,之后的中间件都不在走了,然后再走同级别的process_response方法
        
	# 以下3个都不重要(了解)
	3. process_view
	4. process_template
	5. process_excption
    
# 使用场景:
	1. 对全栈做权限校验
	2. 频率限制
	3. 认证

今日内容概要

  • csrf跨站请求
  • csrf的处理(提供的有相关装饰器)
  • Auth模块
    • B端产品(business,eg:crm,)
    • C端产品(consumer面向用户的,eg:淘宝,京东,租号玩)

内容详细

1. csrf跨站请求

# 背景:
	钓鱼网站
'''
英语4级报名网站为例
	你要在这个网站要付费,你去的这个网站是一个冒牌的网站,就去冒牌网站里面付费了,钱付到了冒牌网站,但是没有报名成功
'''
	会出现在form表单中,action参数:朝后端发送的地址
    
# 怎么解决这个问题?
	csrf是针对与post请求的才会做验证
"""
token相关的报错:
	一般都是一个串:秘钥 私钥 公钥...
""" 

# 两种解决方式
# views.py中添加功能:
def index(request):
    return render(request, 'index.html')

# urls.py中添加路由:
	url(r'^index/', views.index),

# 新建index.html文件:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
{#<form action="" method="post">#}
{#    {% csrf_token %}  {# 解决csrf_token相关报错 方法一 #}
{#    <p>username<input type="text" name="username"></p>#}
{#    <p>password<input type="text" name="password"></p>#}
{#    <input type="submit">#}
{#</form>#}

<button class="btn">ajax</button>
<script>    {# 解决csrf_token相关报错 方法二 #}
$('.btn').click(function () {
    $.ajax({
        url: '',
        type: 'post',
        {#data:{'a':1, 'csrfmiddlewaretoken':$('[name="csrfmiddlewaretoken"]').val()},  {# 有form表单这样写 #}
        data: {'a': 1, 'csrfmiddlewaretoken': '{{ csrf_token }}'}, {# 没有form表单这样写 #}
        success: function () {

        }
    })
})
</script>
</body>
</html>

image

image

2. csrf相关装饰器

# 如果使用中间件限制的话,就会限制全局的,要么全部限制,要么全部不限制

# 两种情况
	只有index函数需要验证,其他的不需要验证
	只想让home函数不验证,其他的都需要验证

# 提供了2个装饰器
	csrf_protect: 需要验证
	csrf_exempt: 不需要验证
	'''按照FBV和CBV的使用即可'''
    
    
# 在views.py中测试:

from django.views.decorators.csrf import csrf_exempt, csrf_protect
from django.utils.decorators import method_decorator
from django.views import View

'''
    针对CBV:
        csrf_protect的三种方式都是可以的
        csrf_exempt前两种方式都不行,只有第三种方式可以的
'''
# @method_decorator(csrf_protect, 'post')  # 2.针对CBV需要验证 方式二
# @method_decorator(csrf_exempt, 'post')  # 5.这种方式也不行
# class IndexView(View):
    # @method_decorator(csrf_protect)  # 1.针对CBV需要验证 方式一
    # @method_decorator(csrf_exempt)  # 4.这种方式不可以
    # def post(self, request):
    #     return HttpResponse('post')

class IndexView(View):
    # @method_decorator(csrf_protect)  # 3.针对CBV需要验证 方式三
    @method_decorator(csrf_exempt)  # 6.这种方式是可以的
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request, *args, **kwargs)
    def post(self, request):
        return HttpResponse('post')

3. Auth模块

# 迁移数据库会有一个表生成,auth_user
# django项目创建完后之后,会有一个默认的路由,admin/
# admin/是django默认提供的后台管理界面

# 访问admin/
	登录参照的数据就是从auth_user表中来,前提是必须是超级管理员

# 如何创建超级管理员?
	python3 manage.py createsuperuser

image

image

image

# auth模块实现登录功能

# 在views.py中测试:
def home(request):
    return render(request, 'home.html')
from django.contrib import auth

def login(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        # 1.去哪个表查询登录数据:auth_user
        # 2.密码如何比对
        """
        注意事项:
            用户名与密码必须两者同时传入
        """
        obj = auth.authenticate(request, username=username, password=password)
        # print(obj)  # None 密码不正确返回的值 结果是当前对象
        # print(obj)  # root 密码正确返回的值 结果是当前对象
        # print(obj.username)
        # print(obj.password)

        if obj:
            # 保存用户信息 auth模块有全套功能需要使用
            auth.login(request, obj)  # 相当于保存了用户信息
            """
            一旦执行了上面的这句话 就可以在全局任何地方 通过request.user 拿到用户对象
            """
            return redirect('/home/')
    return render(request, 'login.html')



# login.html内容:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
<form action="" method="post">
    <p>username:<input type="text" name="username"></p>
    <p>password:<input type="text" name="password"></p>
    <input type="submit">
</form>
</body>
</html>


# urls.py添加路由:
	url(r'^home/', views.home),
	url(r'^login/', views.login),

# home.html写入:
	body标签内:<h1>home页</h1>

image

image

# auth模块验证是否登录(装饰器)

from django.contrib.auth.decorators import login_required

"""
登录装饰器跳转的地址有两种:
    1.局部的 
        @login_required(login_url=login)
        
    2.全局的 在settings.py文件中配置
        LOGIN_URL = '/login/' 
        
    如果同时存在局部的和全局的 那么优先访问 局部 的地址
"""

@login_required  # 判断是否登录装饰器 代替了下面的 if判断
def func(request):
    # 必须登录之后才能访问
    print(request.user)  # AnonymousUser 未登录状态下访问
    print(request.user)  # root 用户名 登录状态下访问
    print(request.user.is_authenticated())  # 验证是否登录 False True
    # if request.user.is_authenticated():
    #     return HttpResponse('func')
    # else:
    #     return redirect('/login/')
    
    
# 添加路由:
	url(r'^func/', views.func),

image

# auth模块实现修改密码

@login_required
def set_pwd(request):
    if request.method == 'POST':
        old_pwd = request.POST.get('old_pwd')
        new_pwd = request.POST.get('new_pwd')
        again_pwd = request.POST.get('again_pwd')

        # 1. 先判断两次密码输入是否一致
        if new_pwd == again_pwd:
            # 2. 校验老密码是否正确
            is_right = request.user.check_password(old_pwd)
            print(is_right)  # 返回的是布尔值
            if is_right:
                # 3. 修改密码
                request.user.set_password(new_pwd)  # 这句话 并没有把密码修改到数据库里 只是修改了password密码的属性
                request.user.save()  # 这句话才是真正的操作数据了
        return redirect('/home/')

    return render(request, 'set_pwd.html')


# 添加路由:
	url(r'^set_pwd/', views.set_pwd),

image

# auth模块实现注销功能

def logout(request):
    # 清空cookie和session
    # request.session.delete()
    # request.session.flush()

    auth.logout(request)
    return redirect('/login/')


# 添加路由:
	url(r'^logout/', views.logout),
# auth模块实现注册用户功能

from django.contrib.auth.models import User  # 相当于使用 auth_user表

def register(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)  # 密码是加密的
        
        return redirect('/home/')
    
    
# 添加路由:
	url(r'^register/', views.register),
posted @ 2022-03-11 00:28  Deity_JGX  阅读(225)  评论(0编辑  收藏  举报