首页 > 其他分享 >csrf相关知识、auth认证模块、扩展auth_user表

csrf相关知识、auth认证模块、扩展auth_user表

时间:2023-01-04 21:11:33浏览次数:52  
标签:request auth user csrf login password

csrf相关知识、auth认证模块、扩展auth_user表

目录

csrf跨站请求伪造

# CSRF(Cross-site request forgery)
中文名称:
	跨站请求伪造,也被称为:one click attack/session riding,缩写为:CSRF/XSRF。
    
CSRF攻击:
	攻击者盗用了你的身份,以你的名义发送恶意请求。
    
CSRF能够做的事情包括:
	以当事人名义发送邮件、发消息,盗取当事人账号、甚至于购买商品、虚拟货币转账…造成的问题包括个人隐私泄露以及财产安全。
    
# 钓鱼网站
模仿一个正规的网站让用户在该网站上做操作,但是操作的结果会影响到用户正常的网站账户。

eg:
    英语四六级考试需要在网上先缴费,当发现卡里的钱扣了却交到了一个莫名其妙的账户,而并不是真正的四六级官方账户的时候,可能就是遇到了钓鱼网站。
# 钓鱼网站html部分代码
<form method="post" action="http://127.0.0.1:8000/real/">
<p>username:<input type="text" name="username"></p>
<p>target_user<input type="text"><input type="text" name="target_user" value="土匪" style="display: none"></p>
<p>Money:<input type="text" name="money"></p>
        <input type="submit">
</form>

# real.views(真实网页的后端)
def real_html(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        target_user = request.POST.get('target_user')
        money = request.POST.get('money')
        print(f'用户{username}给{target_user}转账了{money}元!!!')
	return render(request, 'real.html')

# 区分真假网站页面发送的请求
	"""引入csrf校验策略。"""
	当访问官方网站时需要访问一些核心页面,通常会给核心页面做唯一的标识。当核心页面朝官方网站发送的请求时,官方会根据唯一标识做判断,没有标识则有可能是恶意网站。

csrf攻击原理图解

img

要完成一次CSRF攻击,受害者必须依次完成两个步骤:
  1.登录受信任网站A,并在本地生成Cookie。
  2.在不登出A的情况下,访问危险网站B。

“如果不满足以上两个条件中的一个,就不会受到CSRF的攻击”。
是的,确实如此,但不能保证以下情况不会发生:
  1.不能保证登录了一个网站后,不再打开一个tab页面并访问另外的网站。
  2.不能保证关闭浏览器了后,本地的Cookie立刻过期,上次的会话已经结束。
	#(事实上,关闭浏览器不能结束一个会话,但大多数人都会错误的认为关闭浏览器就等于退出登录/结束会话了......)
	3.上图中的攻击网站,可能是一个存在其他漏洞的、可信任的、经常被人访问的网站。

csrf校验策略

csrf校验策略可以在提交数据的位置添加唯一标识。
# 方法一、form表单csrf策略
	form表单内部添加{% csrf_token %} 
 eg:
<h1>我是真的网站</h1>
<form action="" method="post">
        {% csrf_token %}
    <p>付款人:
        <input type="text" name="username" >
    </p>
    <p>收款账户:
        <input type="text" name="target_name">
    </p>
        <p>转账金额:
        <input type="text" name="money">
    </p>
    <input type="submit">
</form>

# 方法二、ajax请求csrf策略
# 方式1自己动手取值,较为繁琐
<script>
    $('#d1').click(function (){
        $.ajax({
            url:'',
            type:'post',
            // 方式1:自己动手取值,较为繁琐
            data:{'csrfmiddlewaretoken':$('input[name="csrfmiddlewaretoken"]').val()},
            success:function (args){

            }
        })
    })
</script>

# 方式2利用模板语法自动获取
<script>
    $('#d1').click(function (){
        $.ajax({
            url:'',
            type:'post',
             // 方式2:利用模板语法自动获取(一定要用引号引起来)
            data:{'csrfmiddlewaretoken':'{{ csrf_token }}','username':'kimi'},
            {#data:{'csrfmiddlewaretoken':$('input[name="csrfmiddlewaretoken"]').val()},#}
            success:function (args){

            }
        })
    })
</script>
        
# 方式3:直接引入一个js脚本即可(官网提供的)
js直接复制下面的代码
function getCookie(name) {
    var cookieValue = null;
    if (document.cookie && document.cookie !== '') {
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) {
            var cookie = jQuery.trim(cookies[i]);
            // Does this cookie string begin with the name we want?
            if (cookie.substring(0, name.length + 1) === (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}
var csrftoken = getCookie('csrftoken');

function csrfSafeMethod(method) {
  // these HTTP methods do not require CSRF protection
  return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}

$.ajaxSetup({
  beforeSend: function (xhr, settings) {
    if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
      xhr.setRequestHeader("X-CSRFToken", csrftoken);
    }
  }
});
 """
	将上述的文件配置到项目的静态文件中,在html页面上通过导入该文件即可自动解决ajax提交post数据时校验csrf_token的问题,导入配置文件必须先导入jQuery,因为上述文件的内容时基于jQuery来实现的。
 """       

csrf相关装饰器

当知道csrf的作用和使用方式后,联系实际情况考虑到实际应用中会出现下列情况:
    1.整个django项目都校验csrf,但是某些个视图函数\类不想校验
    2.整个django项目都不校验csrf,但是某些个视图函数\类需要校验
根据FBV和CBV的分类,导入时候有所区别:
# FBV添加装饰器的方式(与正常函数添加装饰器一致)
from django.views.decorators.csrf import csrf_exempt, csrf_protect

# @csrf_exempt
想让csrf校验检测就使用装饰器@csrf_protect;
不想让csrf校验检测就使用@csrf_exempt

@csrf_protect
def transfer_func(request):pass

# CBV添加装饰器的方式(与正常情况不一样 需要注意)
主要有三种方式:
# @method_decorator(csrf_protect, name='post')  # 方式2:单独生效

class MyView(views.View):
    @method_decorator(csrf_protect)  # 方式3:整个类中生效
    这里需要会去看CBV的源码剖析,CBV源码内起作用的也是dispaly,通过反射执行字符串表示的功能,因此第三种方式是整个类中生效的。
    
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request, *args, **kwargs)
    # @method_decorator(csrf_protect)  # 方式1:单独生效
    def post(self, request):
        return HttpResponse('from cbv post view')
  
注意:
	有一个装饰器是特例只能有一种添加方式>>>:csrf_exempt,只有在dispatch方法处添加才会生效。
from django.views.decorators.csrf import csrf_exempt
class MyView(views.View):
    @method_decorator(csrf_exempt)  
    # csrf_exempt只能通过第三种方式全类取消csrf校验
    def dispatch(request):
        return super().dispatch(request, *args, **kwargs)
    def get(request):pass
    def post(request):pass

auth认证模块

Auth模块是Django自带的用户认证模块:
	在开发一个网站的时候,无可避免的需要设计实现网站的用户系统。此时需要实现包括用户注册、用户登录、用户认证、注销、修改密码等功能,真是有些复杂。
	Django作为一个完美主义者的终极框架,当然也会想到用户的这些痛点。它内置了强大的用户认证系统--auth,它默认使用 auth_user 表来存储用户数据。

# auth模块常用方法
from django.contrib import auth
字段 释义
id ID
password 密码
last_login 最后登录时间
is_superuser 是否是管理员
username 用户名
first_name
last_name
email 邮箱
is_staff 是否是工作人员
is_active 是否激活
date_joined 创建时间
# 导入auth模块
from django.contrib import auth

# 在执行auth模块相关操作前要先导入数据库中的表
from django.contrib.auth.models import User

# 用户注册功能(即用户创建)
User.objects.create_user(username=username, password=password)

# 判断用户名和密码是否正确
from django.contrib.auth.models import User
1.普通用户
user = User.objects.create_user(username='用户名',password='密码',...)
2.管理员用户,必须要有email
user = User.object.create_superuser(username='用户名',password='密码',email='邮箱',...)

# 判断用户是否登录
request.user.is_authenticated
# 如果登陆了,结果为布尔值Ture,否则为False

# 获取登录用户对象数据
request.user
用户信息可以在user中用点的方式获取

# 校验用户是否登录装饰器
from django.contrib.auth.decorators import login_required
我们如果不指定这里的url,就不会跳转到我们制作的登陆页面.
@login_required(login_url='/login/')  局部配置 
@login_required						全局配置
配置文件中 LOGIN_URL = '/login/'
配置文件中修改,会让全局的@login_required影响下的视图函数/类全都跳转向一个页面

# 校验原密码是否正确
request.user.check_password(原密码)

# 修改密码
request.user.set_password(新密码)
request.user.save()

# 退出登录
auth.logout(request)

# 部分代码操作代码展示
'''判断当前用户有没有登录操作'''
# html
<form method="post">
{% csrf_token %}
<p>username:<input type="text" name="username"></p>
    <p>password:<input type="text" name="password"></p>
        <input type="submit">
        </form>

# views
def login(request):		
	print(request.user)
'''
用户登录成功之后执行Auth.login 该方法返回当前登录用户对象  admin
用户没有登录成功没有执行Auth.login 该方法返回匿名用户对象  AnonymousUser
'''
	print(request.user.is_authenticated)    
    # 判断当前用户是否登录 返回True False
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
	# 现在遇到一个问题就是怎么通过models.的方式去操作auth_user表格呢? 这个时候就有auth模块了
	res = auth.authenticate(request, username=username, password=password)
	# print(res.username, res.password,res.pk)  
    # admin pbkdf2_sha256$150000$4NZp3wuIgf9A$7hfw7pcm35QosjTRWFpj9U3F5SoGTRqUv/H8DpBp308= 2

'''数据正确的情况下会有一个返回值是数据对象 数据错误的情况下返回的是None'''
	if res:
		auth.login(request, res)    
    # 自动操作Cookie与Session
	return render(request, 'login.html')
		
	'''
	用户登录装饰器
	当用户没有登录的情况下跳转到注册界面 在settings文件中设置跳转的页面地址 LOGIN_URL = '/login/'
	'''
from django.contrib.auth.decorators import login_required
		@login_required
		def index(request):
		    return HttpResponse('Form index view')

		@login_required
		def func(request):
		    return HttpResponse('Form func view')

'''重置密码'''
# views
@login_required
def set_password(request):
    if request.method == 'POST':
        old_password = request.POST.get('old_password')
        new_password = request.POST.get('new_password')
        '''校验原密码是否正确 自定加密并检验'''
        is_right = request.user.check_password(old_password)
        if is_right:
            request.user.set_password(new_password)  # 修改密码
            request.user.save()  # 保存数据
            return render(request, 'set_password.html')
        
# html
<form action="" method="post">
{% csrf_token %}
<p>old_password:<input type="text" name=""></p>
    <p>new_password:<input type="text" name=""></p>
        <input type="submit">
        </form>

'''自动清除Cookie与Session'''
# views
@login_required
def loginout(request):
    auth.logout(request)  # 自动清楚cookie和Session
    return HttpResponse('清除成功!!!')

'''创建用户'''
views
from django.contrib.auth.models import User

def register(request):
    User.objects.create(username='Like', password=123, email='[email protected]')		# 这里创建的是普通用户 不能登录管理员系统
    return HttpResponse('注册成功!!!')

扩展auth_user表

如果既想使用auth模块的功能,又想扩展auth_user表的字段,有以下两种方式:

  • 一对一字段关联

因为操作相对繁琐,不建议使用.

img

  • 替换auth_user表

点进调入的User表查看源码,可以发现它只是继承了AbstractUser模块,然后点进AbstractUser源码,我们发现它就相当于一张模型表,配置了auth需要使用的表的具体内容.因此我们可以自己定义一个模型表,只要导入父类AbstractUser即可自定义功能.

操作简单,推荐使用.

步骤1:模型层编写模型类继承AbstractUser
    from django.contrib.auth.models import AbstractUser
    class UserInfo(AbstractUser):
        # 填写AbstractUser表中没有的字段
        phone = models.BigIntegerField()
        desc = models.TextField()

步骤2:一定要在配置文件中声明替换关系(把表替换成我们自定义的模型表)
    AUTH_USER_MODEL = 'app01.UserInfo'
    ps:替换还有一个前提 就是数据库迁移没有执行过(auth相关表没有创建)

标签:request,auth,user,csrf,login,password
From: https://www.cnblogs.com/zhiliaowang/p/17026004.html

相关文章