1.简介 钓鱼网站:假设是一个跟银行一模一样的网址页面 用户在该页面上转账 账户的钱会减少 但是受益人却不是自己想要转账的那个人 2.模拟 一台计算机上两个服务端不同端口启动 钓鱼网站提交地址改为正规网站的地址 3.预防 csrf策略:通过在返回的页面上添加独一无二的标识信息从而区分正规网站和钓鱼网站的请求
# 真实网站 def transfer(request): if request.method == 'POST': username = request.POST.get('name') target_name = request.POST.get('target_name') money = request.POST.get('money') print(f'{username}给{target_name}转了{money}钱') return render(request,'transfer.html') 前端代码: <h1>真网站</h1> <form action="" method="post"> <p>name: <input type="text" name="name"></p> <p>target_name : <input type="text" name="target_name"></p> <p>money : <input type="text" name="money"></p> <input type="submit"> </form>
# 钓鱼网站: def transfer(request): return render(request,'transfer.html') 前端代码: <h1>钓鱼网站</h1> <form action="http://127.0.0.1:8000/transfer/" method="post"> <p>name: <input type="text" name="name"></p> <p>target_name : <input type="text" > <input type="text" name="target" value="jerry" style="display: none"> </p> <p>money : <input type="text" name="money"></p> <input type="submit"> </form>
'''先打开settings里面的MIDDLEWARE的第四行'django.middleware.csrf.CsrfViewMiddleware'''' 全局校验 需要携带一串随机字符串验证通过才可以朝服务端发送post请求
![image](https://img20
form表单方法: 1.给form表单内部添加方法 <form action="" method="post"> {% csrf_token %} # 前后端分离的时候用不了这个方法 </form> # 这时候就会产生一串随机字符串 当提交post请求的时候 服务端会自动校验身份
Ajax方法: # 方法1:先编写csrf模板语法 然后利用标签查找和值获取 手动添加 {% csrf_token %} <button id=" d1">ajax</button> <script> $('#d1').click(function () { $.ajax({ url: '', type: 'post', data: {'username': 'summer', 'csrfmiddlewaretoken': $('[name = "csrfmiddlewaretoken"]').val()}, success:function (args){ } }) }) </script> # 方法2:直接利用模板语法 data:{'username': 'summer', 'csrfmiddlewaretoken':'{{csrf_token}}'}, # 方法3: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); } } }); # 直接拷贝代码放在静态文件目录的js文件夹内即可
1.当整个网站默认都不校验csrf 但是局部视图函数需要校验 如何处理 # 注掉settings里面的MIDDLEWARE的第四行代码 2.当整个网站默认都校验csrf 但是局部视图函数不需要校验 如何处理
# FBV from django.views.decorators.csrf import csrf_exempt, csrf_protect @csrf_protect # csrf校验 def home(request): return HttpResponse('下午好啊,北鼻!') ''' csrf_exempt 不校验csrf csrf_protect 校验csrf '''
# CBV from django import views from django.utils.decorators import method_decorator # @method_decorator(csrf_protect , name='post') # 方式2 可以指定给哪个方法装 class MyHome(views.View): @method_decorator(csrf_protect) #方式3 影响类中的所有方法 def dispatch(self, request, *args, **kwargs): super(MyHome, self).dispatch(request, *args, **kwargs) def get(self, request): return HttpResponse('home get view') # @method_decorator(csrf_protect) # 方式1 def post(self, request): return HttpResponse('home post view') ''' 针对CBV不能直接在方法上添加装饰器 需要借助于专门添加装饰器的方法 from django.utils.decorators import method_decorator ''' # @method_decorator(csrf_exempt) 针对不校验csrf只有继承的dispatch方法可以使用
django执行数据库迁移命令以后会产生一个auth_user表 基于这张表可以创建一个管理员用户 python manage.py createsupersuer 该表可以配合auth模块操作用户相关的功能:注册 登录 删除 修改等
1.创建用户 from django.contrib.auth.models import User user.object.create_user(username,password) user.object.create_superuser(username,password,email) 2. 校验用户名和密码是否正确 from django.contrib import auth auth.authenticate(request,username,password) 3.用户登录 auth.login(request,user_obj) 4.判断用户是否登录 request.user.is_authenticated 5.获取登录用户对象 request.user 6.校验用户登录装饰器 from django.contrib.auth.decorators import login_required 跳转局部配置 login_required(login_url='/login/') 跳转全局配置 在settings里面配置需要跳转的页面 适合操作量大的数据 LOGIN_URL = '/login/' 7.检验密码是否正确 request.user.check_password(old_password) 8.修改密码 request.user.set_password(new_password) request.user.save() 9.注销登录 auth.logout(request)
from django.contrib import auth from django.contrib.auth.decorators import login_required def login(request): print(request.user) ''' request.user 该方法登录成功(auth.login)会返回一个当前登录对象 没有登录(auth.login)会返回一个AnonymousUser 匿名用户对象 ''' print(request.user.is_authenticated) # 判断当前用户是否登录 返回的是布尔值 if request.method == 'POST': username = request.POST.get('username') password = request.POST.get('password') # 查询数据库 校验数据 密码自动加密比对 user_obj = auth.authenticate(request, username=username, password=password) print(user_obj) # 该方法返回的是对象 如果没有则返回None if user_obj: # 记录用户登录状态 auth.login(request, user_obj) # 自动创建session表 返回随机字符串给前端 return render(request, 'login.html') @login_required(login_url='/login/') # 局部配置 每次都需要自己写 def index(request): return HttpResponse('登录index') @login_required(login_url='/login/') def func(request): return HttpResponse('登录func') @login_required def set_password(request): if request.method == 'POST': old_password = request.POST.get('old_password') new_password = request.POST.get('new_password') # 1.校验原密码是否正确 res = request.user.check_password(old_password) if res: # 修改密码 request.user.set_password(new_password) # 保存密码 request.user.save() return render(request,'set_password.html') @login_required def logout(request): auth.logout(request) # 自动清除cookie和session return HttpResponse('注销功能') from django.contrib.auth.models import User def register(request): User.objects.create_user(username='summer',password=123) # 创建普通用户 User.objects.create_superuser(username= 'jerry',password=123,email='123@qq.com') # 创建管理员用户 return HttpResponse('注册功能')
# 想创建更多的表的字段 相当于自定义auth_user表 第一步: from django.contrib.auth.models import AbstractUser class Userinfo(AbstractUser): phone = models.BigIntegerField() desc = models.TextField() 第二步: 在settings中配置 AUTH_USER_MODEL = 'app01.Userinfo' auth模块的功能都可以用 除了自己创建的字段 其他的都一样操作
import importlib # 功能是通过字符串来导模块 s1 = 'b.ddd' res = importlib.import_module(s1) # from b import ddd print(res.s) # 导入模块的底层原理 : 首先拿到字符串 按最右边的切割 s1.rsplit('.',maxsplit=1) 右边的单位最小为py文件 切完结果 ['b', 'ddd']
函数封装 def send_qq(content): print('qq消息通知:',content) def send_we(content): print('微信消息通知:',content) def send_msg(content): print('短信消息通知:',content) def send_all(content): send_qq(content) send_we(content) send_qq(content) if __name__ == '__main__': send_all('放假通知!!!')
# 创建settings.py文件 模仿中间件 NOTIFY_FUNC_LIST = [ 'notifys.notify.qq.QQ', 'notifys.notify.weixin.Weixin', 'notifys.notify.msg.Msg', ]
# 创建需要发送消息的py文件 class QQ(object): def __init__(self): pass def send(self,content): print('qq消息通知:',content)
自定义一个文件 创建一个__init__.py # __init__.py 代码 import importlib import settings def send_all(content): for i in settings.NOTIFY_FUNC_LIST: module_path, class_str_name = i.rsplit('.', maxsplit=1) module = importlib.import_module(module_path) class_name = getattr(module, class_str_name) # 真正的类名 obj = class_name() obj.send(content)