跨站请求伪造 auth模块
importlib 利用字符串形式导入模块
import importlib res = 'lib.bbb' # 利用字符串的形式导入模块 md = importlib.import_module(res) # from lib import bbb print(md) # 该模块字符串最小单位只能到文件名
跨站请求伪造 csrf
钓鱼网站
你自己写一个跟中国银行正规网站一模一样的页面
用户输入用户名 密码 对方账户 转账金额提交
请求确实是朝中国银行的接口发送的 钱也扣了
但是对方账户变了 变成了钓鱼网站自己提前设置好的账户
如何实现
你在写form表单的时候 让用户填写的对方账户input并没有name属性
而是你自己在内部偷偷隐藏了一个具有name属性的input框
并且value值是你自己的账户 然后将该标签隐藏了
跨站请求伪造解决思路
解决
网站在返回给用户一个form表单的时候 会自动在该表单隐藏一个input框
这个框的value是一个随机字符串 但是网站能够记住每一个浏览器发送的随机字符串
你以后在写form表单的时候 你只需要在表单中写一个{% csrf_token %} 此时中间件第四条不需要注销了
<form action="" method="post"> {% csrf_token %} <p>username:<input type="text" name="username"></p> <p>target_account:<input type="text" name="target_user"></p> <p>money:<input type="text" name="money"></p> <input type="submit"> </form> # 自动添加隐藏的input框 <input type="hidden" name="csrfmiddlewaretoken" value="rJ47FeK9T55wavvVJGY6UxdM1kTMHhTqotGfaXjXIK8Ahz2Uvs02yR9T8bBn5q2D">
ajax如何解决POST请求csrf校验
方式1 较为繁琐
先在页面任意的位置上书写{% csrf_token %}
然后在发送ajax请求的时候 通过标签查找获取随机字符串添加到data自定义对象即可
data:{'username':'jason','csrfmiddlewaretoken':$('input[name="csrfmiddlewaretoken"]').val()},
方式2 较为简单
data:{'username':'jason','csrfmiddlewaretoken':'{{ csrf_token }}'},
方式3 官网提供的文件 最通用的一种方式
直接新建js文件,放在static下面(注意配置static)拷贝代码 导入即可
你不需要做任何的csrf相关的代码书写
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); } } });
csrf的校验装饰器
from django.views.decorators.csrf import csrf_exempt,csrf_protect
@csrf_exempt # 不校验 csrf
def index(request):
return HttpResponse('index')
@csrf_protect # 校验
def login(request):
return HttpResponse('login')
csrf的校验装饰器在CBV上有何异同
# @method_decorator(csrf_exempt,name='post') # csrf_exempt不支持该方法
@method_decorator(csrf_exempt,name='dispatch') # csrf_exempt
class MyIndex(views.View):
# @method_decorator(csrf_exempt) # 可以
def dispatch(self, request, *args, **kwargs):
return super().dispatch(request,*args,**kwargs)
def get(self,request):
return render(request,'transfer.html')
# @method_decorator(csrf_exempt,name='post') # csrf_exempt不支持该方法
def post(self,request):
return HttpResponse('OK')
csrf_exempt这个装饰器只能给dispatch装才能生效
"""
csrf_protect方式全都可以 跟你普通的装饰器装饰CBV一致
"""
django settings源码剖析
django有两个配置文件
一个是暴露给用户可以配置的
一个是内部全局的(用户配置了就用用户的 用户没有配就用自己的)
obj
obj.name = 'egon' # 全局
obj.name = 'jason' # 局部
先加载全局配置 给对象设置
然后在加载局部配置 再给对象设置
一旦有重复的项 后者覆盖前者
auth模块简介
如何创建超级用户(root)
python3 manage.py createsuperuser
auth模块常用方法
1.创建用户
from django.contrib.auth.models import User
# User.objects.create(username=username,password=password) # 不可用 密码不是加密的
# User.objects.create_user(username=username,password=password) # 创建普通用户 密码自动加密
# User.objects.create_superuser(username=username,password=password,email='123@qq.com') # 创建超级用户 需要邮箱数据
2.校验用户名和密码是否正确
from django.contrib import auth
user_obj = auth.authenticate(request,username=username,password=password)
# 必须传用户名和密码两个参数缺一不能
3.保存用户登录状态
auth.login(request,user_obj)
# 只要这句话执行了 后面在任意位置 只要你能拿到request你就可以通过request.user获取到当前登录的用户对象
4.判断当前用户是否登录
request.user.is_authenticated()
5.校验原密码是否正确
request.user.check_password(old_password)
6.修改密码
request.user.set_password(new_password)
request.user.save() # 千万不要忘了
7.注销
auth.logout(request)
8.校验用户是否登录装饰器
from django.contrib.auth.decorators import login_required
局部配置
@login_required(login_url='/login/')
def index(request):
pass
全局配置
settings配置文件中 直接配置
LOGIN_URL = '/login/'
@login_required
def index(request):
pass
# 如果全局配置了 局部也配置 以局部的为准
from django.contrib.auth.models import User from django.contrib import auth from django.contrib.auth.decorators import login_required def register(request): if request.method == 'POST': username = request.POST.get('username') password = request.POST.get('password') # models.User.objects.create(username=username,password=password) # User.objects.create(username=username,password=password) # 不可用 密码不是加密的 # User.objects.create_user(username=username,password=password) # 创建普通用户 密码自动加密 # User.objects.create_superuser(username=username,password=password,email='123@qq.com') # 创建超级用户 需要邮箱数据 return HttpResponse('OK') return render(request,'register.html') def lgg(request): if request.method == 'POST': username = request.POST.get('username') password = request.POST.get('password') # 校验当前用户名和密码是否正确 # models.User.objects.filter(username=username,password=password) # res = User.objects.filter(username=username,password=password) # 密码无法校验 # print(res) res = auth.authenticate(request,username=username,password=password) # 自动给你加密密码 然后去数据库校验 # print(res) # 数据对象 # print(res.username) # print(res.password) # 密码是密文 if res: # 保存用户登录状态 # request.session['user'] = 'jason' auth.login(request,res) """ 只要执行了这一句话 之后你可以在任意位置 通过request.user获取到当前登录用户对象 """ return HttpResponse('ok') return render(request,'lgg.html') def get_user(request): print(request.user) # 如果用户没有登录就返回AnonymousUser匿名用户 print(type(request.user)) print(request.user.is_authenticated()) # 判断当前用户是否登录 return HttpResponse('ok') # @login_required(login_url='/lgg/') # 局部配置 如果没有登录就跳转到/lgg/登录 # 或者全局配置,现在配置文件中写 LOGIN_URL = '/lgg/' @login_required def check_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() # 修改密码一对要保存 user_obj = request.user return render(request,'change_password.html',locals()) @login_required def logout(request): # request.session.flush() auth.logout(request) return HttpResponse('注销了')
auth拓展表
方式1
利用一对一外键字段关系
class UserDetail(models.Model):
phone = models.BigIntegerField()
user = models.OneToOneField(to='User')
方式2
利用继承关系
from django.contrib.auth.models import AbstractUser
class Userinfo(AbstractUser):
phone = models.BigIntegerField()
register_time = models.DateField(auto_now_add=True)
# 一定要注意 还需要去配置文件中配置
AUTH_USER_MODEL = 'app01.Userinfo' # 应用名.表名
# 这么写完之后 之前所有的auth模块功能全都以你写的表为准
基于djangosettings配置文件实现插拔式设计
import importlib from lib.conf import global_settings import os class Settings(object): def __init__(self): for name in dir(global_settings): if name.isupper(): setattr(self,name,getattr(global_settings,name)) # 获取暴露给用户的配置文件字符串路径 module_path = os.environ.get('xxx') md = importlib.import_module(module_path) # md = settings for name in dir(md): if name.isupper(): k = name v = getattr(md,name) setattr(self,k,v) settings = Settings()
import os import sys BASE_DIR = os.path.dirname(__file__) sys.path.append(BASE_DIR) if __name__ == '__main__': # os.environ.setdefault('xxx','conf.settings') os.environ['xxx'] = 'conf.settings' from lib.conf import settings print(settings.NAME)