Ⅰ Django框架之csrf跨站请求
【一】跨站请求伪造介绍
【1】引入
- CSRF(Cross-Site Request Forgery)跨站请求伪造是一种常见的网络攻击方式。
- 攻击者通过诱导受害者访问恶意网站或点击恶意链接
- 将恶意请求发送到目标网站上
- 利用受害者在目标网站中已登录的身份来执行某些操作
- 从而达到攻击的目的。
【2】举例
- 假设受害者在一家网银网站上登录账户,然后继续浏览其他网页。
- 同时,攻击者通过电子邮件等方式向受害者发送了一封包含恶意链接的邮件。
- 当受害者点击该链接时,潜在的威胁就会变得非常现实。
- 该链接指向一个由攻击者操纵的网站,该网站上的恶意代码会自动向网银网站发送一个请求,请求转账到攻击者的账户。
- 由于受害者在网银网站中已经登录,所以该请求会被认为是合法的,这样攻击者就可以成功地进行转账操作。
【3】保护措施
- 要保护自己免受CSRF攻击,网站开发者可以采取以下措施:
(1)使用CSRF令牌
- 在用户的请求中添加随机生成的令牌,并将该令牌保存在用户会话中。
- 每次提交请求时都会验证该令牌,以确保请求是合法的。
(2)启用SameSite属性:
- 将Cookie的SameSite属性设置为Strict或Lax,以限制跨站请求。
- 这可以在一定程度上缓解CSRF攻击。
(3)严格验证请求来源
- 服务器端可以验证请求的来源是否为预期的网站域名
- 例如检查HTTP Referer头部。
(4)使用验证码
- 在敏感操作(如转账、更改密码等)上使用验证码
- 增加用户身份验证的防护。
【二】跨域请求伪造实际案例
【1】钓鱼网站
- 搭建一个类似正规网站的页面
- 用户点击网站链接,给某个用户打钱
- 打钱的操作确确实实提交给了中国银行的系统,用户的钱也确实减少
- 但是唯一不同的是,账户打钱的账户不是用户想要打钱的目标账户,变成了其他用户
【2】内部本质
- 在钓鱼网站的页面针对对方账户,只给用户提供一个没有name属性的普通input框
- 然后在内部隐藏一个已经写好带有name属性的input框
【3】如何避免
- csrf跨域请求伪造校验
- 网站在给用户返回一个具有提交数据功能的页面的时候会给这个页面加一个唯一标识
- 当这个页面后端发送post请求的时候,我们后端会先校验唯一标识
- 如果成功则正常执行
- 如果唯一标识不符合则拒绝连接(403 forbidden)
【4】钓鱼网站实现示例
(1)正常网站
- 路由
from django.urls import path
from user.views import home,transform
urlpatterns = [
path('', home, name="home"),
path('transform/', transform, name="transform"),
]
- 视图
from django.shortcuts import render, HttpResponse, reverse
def transform(request):
if request.method == "POST":
print(request.POST)
# 自己的账户和取款密码
bank_card = request.POST.get("bank_card")
password = request.POST.get("password")
# 目标账户
to_bank_card = request.POST.get("to_bank_card")
money = request.POST.get("money")
message = f"当前账户 {bank_card} 向目标账户 {to_bank_card} 转账了 {money}"
print(message)
return HttpResponse(message)
return render(request, "transform.html", locals())
-
前端
-
transform.html
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>这是真正的转账页面</h1>
<form action="" method="post">
<p>bank_card <input type="text" name="bank_card"></p>
<p>password <input type="text" name="password"></p>
<p>to_bank_card <input type="text" name="to_bank_card"></p>
<p>money <input type="text" name="money"></p>
<p><input type="submit"></p>
</form>
</body>
</html>
- home.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p><a href="{% url 'transform' %}">正常转账页面</a></p>
<p><a href="http://127.0.0.1:8080/transform/">钓鱼网站转账页面</a></p>
</body>
</html>
(2)钓鱼网站
-
重启创建一个Django项目 修改启动端口
-
路由
from django.urls import path
from user import views
urlpatterns = [
path('transform/', views.transform, name="transform"),
]
- 视图
from django.shortcuts import render, HttpResponse, reverse
def transform(request):
if request.method == "POST":
# 自己的账户和取款密码
bank_card = request.POST.get("bank_card")
password = request.POST.get("password")
# 目标账户
to_bank_card = request.POST.get("to_bank_card")
money = request.POST.get("money")
message = f"当前账户 {bank_card} 向目标账户 {to_bank_card} 转账了 {money}"
print(message)
return HttpResponse(message)
return render(request, "transform.html", locals())
-
前端
-
transform.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>这是钓鱼的转账页面</h1>
<form action="" method="post">
<p>bank_card <input type="text" name="bank_card"></p>
<p>password <input type="text" name="password"></p>
<p>to_bank_card <input type="text"></p>
<p><input type="text" name="to_bank_card" style="display: none" value="96963636"></p>
<p>money <input type="text" name="money"></p>
<p><input type="submit"></p>
</form>
</body>
</html>
(3)前端图片展示
- 正常网站
- 钓鱼网站
【三】CSRF校验
【1】介绍
- csrf校验是一种用于防止跨站请求伪造(Cross-Site Request Forgery)攻击的安全措施。
【2】CSRF校验策略
(1)添加CSRF Token字段
- 在form表单中添加一个隐藏字段,用于存储CSRF Token的值。
- 后端服务器在渲染表单时生成一个CSRF Token,并将其存储在会话中或者以其他方式关联到当前用户。
- 当用户提交表单时,前端将CSRF Token的值包含在请求中。
- 后端在验证表单数据时,检查请求中的CSRF Token是否与存储的Token匹配,如果不匹配,则拒绝请求。
(2)设置Cookie
- 后端服务器在渲染表单时,在客户端设置一个包含随机生成的CSRF Token的Cookie。
- 当用户提交表单时,表单数据会被一同发送到服务器,并自动包含该Cookie。
- 后端在验证表单数据时,检查请求中的CSRF Token是否与Cookie中的值匹配,如果不匹配,则拒绝请求。
(3)双重Cookie校验
- 后端服务器在渲染表单时,在Cookie中设置一个随机生成的CSRF Token,并将其存储在会话中或以其他方式关联到当前用户。
- 当用户提交表单时,表单数据会被一同发送到服务器,请求头或请求参数中携带一个包含CSRF Token的自定义字段。
- 后端在验证表单数据时,同时检查请求中的CSRF Token和Cookie中的值是否匹配,如果不匹配,则拒绝请求。
【3】CSRF令牌验证
MIDDLEWARE = [
'django.middleware.csrf.CsrfViewMiddleware', # 把这个放开
]
(1)签发令牌
# 每一个请求过来的时候 都去生成一个随机的令牌
# {% csrf_token %} ---> 在前端会自动生成一个 csrfmiddlewaretoken input 标签
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>这是真正的转账页面</h1>
<form action="" method="post">
{% csrf_token %}
<p>bank_card <input type="text" name="bank_card"></p>
<p>password <input type="text" name="password"></p>
<p>to_bank_card <input type="text" name="to_bank_card"></p>
<p>money <input type="text" name="money"></p>
<p><input type="submit"></p>
</form>
</body>
</html>
(2)form表单验证令牌
# csrfmiddlewaretoken 也会随着我们携带的数据发送过来
# 这个数据就很被csrf中间件捕获到 ---> 验证 ---> 正常进去
# 不正常拦截掉
def transform(request):
if request.method == "POST":
print(request.POST)
# <QueryDict: {'csrfmiddlewaretoken': ['b7PVLK5at66ktcHBmHbXqS1HlXOqVyrgehvdfIWspQIoT45M8he4oDxHTEWwGA0O'], 'bank_card': ['123'], 'password': ['741'], 'to_bank_card': ['456'], 'money': ['888888']}>
# 自己的账户和取款密码
bank_card = request.POST.get("bank_card")
password = request.POST.get("password")
# 目标账户
to_bank_card = request.POST.get("to_bank_card")
money = request.POST.get("money")
message = f"当前账户 {bank_card} 向目标账户 {to_bank_card} 转账了 {money}"
print(message)
return HttpResponse(message)
return render(request, "transform.html", locals())
【4】Ajax携带CSRF
(1)方式一:在form表单遍历每一个标签获取到 键和值拼接到对象里面
- 自己构建字典数据
- data = {}
- let data = {} 把 csrf_token的键值传请求体中
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
</head>
<body>
<h1>这是真正的转账页面</h1>
<form id="transform_form">
{% csrf_token %}
<p>bank_card
<input type="text" name="bank_card">
</p>
<p>password
<input type="text" name="password">
</p>
<p>to_bank_card
<input type="text" name="to_bank_card">
</p>
<p>money
<input type="text" name="money">
</p>
<p>
<input type="button" value="点我转账" id="btn_click">
</p>
</form>
<script>
$(document).ready(
$("#btn_click").click(function () {
let data = {}
$("#transform_form").serializeArray().forEach(
// 第一个参数 是当前标签的name 和 value
// 第二个参数 当前元素的索引
// 第三个参数 原本的数组
function (a,b,c) {
{#data[a.name] = a.value#}
console.log(a)
console.log(b)
console.log(c)
})
)
</script>
</script>
</body>
</html>
(2)方式二:获取到制定的 input 标签 提取 val
- 根据属性选择器
- 拿出csrf_token的键值对 data["csrfmiddlewaretoken"]= $("input[name='csrfmiddlewaretoken']").val() 把 csrf_token的值传请求体中
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>这是真正的转账页面</h1>
<form id="transform_form">
{% csrf_token %}
<p>bank_card
<input type="text" name="bank_card">
</p>
<p>password
<input type="text" name="password">
</p>
<p>to_bank_card
<input type="text" name="to_bank_card">
</p>
<p>money
<input type="text" name="money">
</p>
<p>
<input type="button" value="点我转账" id="btn_click">
</p>
</form>
<script>
$(document).ready(
$("#btn_click").click(function () {
let data = {}
data["csrfmiddlewaretoken"]= $("input[name='csrfmiddlewaretoken']").val()
{# {'csrfmiddlewaretoken': ['1y0zjU0ZwqKRV33CpALZMmEA0BIEYbHu4IGRNSRhsamVlVrNbaO6K7aAyiQKJdg2'] #}
$.ajax({
url: "",
type: "post",
data: data,
success: function (response) {
alert(response.msg)
}
})
})
)
</script>
</script>
</script>
</body>
</html>
(3)方式三:Django的模版语法系统自动加载
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>这是真正的转账页面</h1>
<form id="transform_form">
{% csrf_token %}
<p>bank_card
<input type="text" name="bank_card">
</p>
<p>password
<input type="text" name="password">
</p>
<p>to_bank_card
<input type="text" name="to_bank_card">
</p>
<p>money
<input type="text" name="money">
</p>
<p>
<input type="button" value="点我转账" id="btn_click">
</p>
</form>
<script>
$(document).ready(
$("#btn_click").click(function () {
let data = {}
data["csrfmiddlewaretoken"] = "{{ csrf_token }}"
$.ajax({
url: "",
type: "post",
data: data,
success: function (response) {
alert(response.msg)
}
})
})
)
</script>
</script>
</script>
</script>
</body>
</html>
(4)方式四:官方提供的 js 脚本文件将 csrf 跨过去 csrf.js
- static 'csrf.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);
}
}
});
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>这是真正的转账页面</h1>
<form id="transform_form">
{% csrf_token %}
<p>bank_card
<input type="text" name="bank_card">
</p>
<p>password
<input type="text" name="password">
</p>
<p>to_bank_card
<input type="text" name="to_bank_card">
</p>
<p>money
<input type="text" name="money">
</p>
<p>
<input type="button" value="点我转账" id="btn_click">
</p>
</form>
<script src="{% static 'csrf.js' %}"></script>
<script>
$(document).ready(
$("#btn_click").click(function () {
let data = {}
// 方式四 : jQuery 官方文档 通过给我们一个解决方案
// ?我们可以借助 官方提供的 js 脚本文件将 csrf 跨过去
$.ajax({
url: "",
type: "post",
data: data,
success: function (response) {
alert(response.msg)
}
})
})
)
</script>
</script>
</script>
</script>
</script>
</body>
</html>
Ⅱ CSRF相关装饰器
- 策略一:网站整体部分校验csrf,部分不校验csrf
- 策略二:网站整体全部校验csrf,部分不校验csrf
【一】csrf_protect装饰器:
- csrf_protect装饰器用于需要进行CSRF保护的视图函数或类视图。
- 当一个视图被csrf_protect装饰器修饰时,Django会对该视图接收到的所有POST、PUT、DELETE等非安全HTTP方法的请求进行CSRF校验。
- 如果请求中没有有效的CSRF令牌或令牌校验失败,Django将返回403 Forbidden响应。
【二】csrf_exempt装饰器:
- csrf_exempt装饰器用于不需要进行CSRF保护的视图函数或类视图。
- 当一个视图被csrf_exempt装饰器修饰时,Django将不会对该视图接收到的任何请求进行CSRF校验。
- 这个装饰器主要用于一些特殊情况,比如与第三方系统进行集成、开放API接口等。
【三】装饰器位置
from django.views.decorators.csrf import csrf_protect, csrf_exempt
【1】全局开启 局部禁用
# 开启 django.middleware.csrf.CsrfViewMiddleware
# 局部禁用
# 只有在 CBV 视图中的 dispatch 生效 其他不生效
from django.views import View
from django.views.decorators.csrf import csrf_protect, csrf_exempt
# csrf_protect 增加 csrf 验证保护
# csrf_exempt 取消 csrf 验证保护
from django.utils.decorators import method_decorator
# 方式二 加载了类上面 --- 不生效
# @method_decorator(csrf_protect, name='post')
class CSRFView(View):
def get(self, request):
return render(request, "csrf_index.html", locals())
# 方式一 : 局部增加装饰器 取消验证 --- 不生效
# @method_decorator(csrf_exempt)
def post(self, request):
return HttpResponse("post")
@method_decorator(csrf_exempt) # --- 可以取消
def dispatch(self, request, *args, **kwargs):
# Try to dispatch to the right method; if a method doesn't exist,
# defer to the error handler. Also defer to the error handler if the
# request method isn't on the approved list.
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs)
【2】全局关闭 局部开启
# 每一个方法都会生效
# 全局关闭 # django.middleware.csrf.CsrfViewMiddleware
from django.views import View
from django.views.decorators.csrf import csrf_protect, csrf_exempt
# csrf_protect 增加 csrf 验证保护
# csrf_exempt 取消 csrf 验证保护
from django.utils.decorators import method_decorator
# 方式二 加载了类上面 --- 生效
# @method_decorator(csrf_protect, name='post')
class CSRFView(View):
def get(self, request):
return render(request, "csrf_index.html", locals())
# 方式一 : 局部增加装饰器 取消验证 --- 生效
# @method_decorator(csrf_protect)
def post(self, request):
return HttpResponse("post")
@method_decorator(csrf_protect) # --- 生效
def dispatch(self, request, *args, **kwargs):
# Try to dispatch to the right method; if a method doesn't exist,
# defer to the error handler. Also defer to the error handler if the
# request method isn't on the approved list.
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs)
Ⅲ Auth模块
【一】Auth模块引入
# auth模块
# auth 模块是Django提供的默认的用户模块
# 包括我们后端 Django的admin 后台的用户校验都是从 auth】 模块里面验证的
- 我们在创建一个Django项目之后,直接执行数据库迁移命令会自动生成很多表
- django_session
- auth_user
- Django在启动之后就可以直接访问admin路由,需要输入用户名和密码,数据参考的就是auth_user表,并且必须是管理员用户才能进入
【二】创建超级用户(管理员)
python manage.py createsuperuser
manage.py@third > createsuperuser
E:\python\python310\python.exe "E:\pycharm\PyCharm 2023.3.5\plugins\python\helpers\pycharm\django_manage.py" createsuperuser E:/yjjj/third
Tracking file by folder pattern: migrations
Username (leave blank to use 'zhangyubin'): silence
Email address:
Warning: Password input may be echoed.
Password: 741741
Warning: Password input may be echoed.
Password (again): 741741
This password is too short. It must contain at least 8 characters.
This password is too common.
This password is entirely numeric.
Bypass password validation and create user anyway? [y/N]: y
Superuser created successfully.
- 在数据库查看
【三】常规用户操作
# 【1】注册
# 【2】登陆
# 【3】注销
# 【4】修改密码
# 【5】校验当前用户的登陆状态
from django.contrib import auth
# Django的 auth 模块的模型表
from django.contrib.auth.models import User
【1】数据准备
- 路由
from django.contrib import admin
from django.urls import path,re_path
from user import views
from user.views import home
urlpatterns = [
path('admin/', admin.site.urls),
path('', home, name="home"),
path('register/', views.RegisterView.as_view(), name="register"),
path('login/', views.LoginView.as_view(), name="login"),
path('update/', views.UpdateView.as_view(), name="update"),
path('check_login/', views.index, name="check_login"),
path('logout/', views.logout, name="logout"),
path('check_login_decorators/', views.index_decorators, name="check_login_decorators"),
]
前端总界面
- home.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<hr>
<p><a href="{% url 'register' %}">注册</a></p>
<p><a href="{% url 'login' %}">登陆</a></p>
<p><a href="{% url 'update' %}">修改密码</a></p>
<p><a href="{% url 'logout' %}">注销登录</a></p>
<p><a href="{% url 'check_login' %}">方法属性 校验是否登陆</a></p>
<p><a href="{% url 'check_login_decorators' %}">装饰器 校验是否登陆</a></p>
</body>
</html>
【2】验证注册
from django.http import JsonResponse
from django.shortcuts import render, HttpResponse, reverse,redirect
from django.views import View
from django.contrib import auth
# Django的 auth 模块的模型表
from django.contrib.auth.models import User
def home(request):
return render(request, "home.html", locals())
class RegisterView(View):
def get(self, request):
return render(request, "register.html", locals())
def post(self, request):
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(reverse("home"))
【3】验证登录及保存登陆状态
from django.http import JsonResponse
from django.shortcuts import render, HttpResponse, reverse,redirect
from django.views import View
from django.contrib import auth
# Django的 auth 模块的模型表
from django.contrib.auth.models import User
def home(request):
return render(request, "home.html", locals())
class LoginView(View):
def get(self, request):
return render(request, "login.html", locals())
def post(self, request):
username = request.POST.get("username")
password = request.POST.get("password")
# 用户登陆
# 验证当前用户的用户名和密码
# 验证用户名没问题
# 密码是明文的 数据库是密文
user_obj = auth.authenticate(username=username, password=password)
# print(user_obj, type(user_obj)) # dream1 <class 'django.contrib.auth.models.User'>
# print(user_obj.username) # dream1
print(dir(request))
print(request.user) # AnonymousUser 匿名用户
# 保存用户的登陆状态
# 以前的使用Cookie和 session
if user_obj:
auth.login(request, user_obj) # 起始就是将request 里面的 user 属性替换成当前验证过的用户对象
# print(request.user,type(request.user))
return redirect(reverse("home"))
else:
return redirect(reverse("login"))
【4】修改密码
from django.http import JsonResponse
from django.shortcuts import render, HttpResponse, reverse,redirect
from django.views import View
from django.contrib import auth
# Django的 auth 模块的模型表
from django.contrib.auth.models import User
def home(request):
return render(request, "home.html", locals())
class UpdateView(View):
def get(self, request):
return render(request, "update.html", locals())
def post(self, request):
username = request.POST.get("username")
old_password = request.POST.get("old_password")
new_password = request.POST.get("new_password")
# 用户修改密码
# 明文的密码 将密码转换成密文
# 校验原来的密码是否正确
if request.user.check_password(old_password):
# 旧密码正确修改新密码
request.user.set_password(new_password)
# 没有触发保存
request.user.save()
return redirect(reverse("home"))
else:
return redirect(reverse("update"))
【5】注销登录
from django.http import JsonResponse
from django.shortcuts import render, HttpResponse, reverse,redirect
from django.views import View
from django.contrib import auth
# Django的 auth 模块的模型表
from django.contrib.auth.models import User
def home(request):
return render(request, "home.html", locals())
def logout(request):
# 注销登录
auth.logout(request)
return redirect(reverse("home"))
【6】校验登陆
from django.http import JsonResponse
from django.shortcuts import render, HttpResponse, reverse,redirect
from django.views import View
from django.contrib import auth
# Django的 auth 模块的模型表
from django.contrib.auth.models import User
def home(request):
return render(request, "home.html", locals())
# 校验登陆
def index(request):
# 校验当前用户是否登录
if request.user.is_authenticated:
return render(request, "index.html", locals())
else:
return redirect(reverse("home"))
【7】登陆认证装饰器
from django.http import JsonResponse
from django.shortcuts import render, HttpResponse, reverse,redirect
from django.views import View
from django.contrib import auth
# Django的 auth 模块的模型表
from django.contrib.auth.models import User
def home(request):
return render(request, "home.html", locals())
# 登陆认证装饰器
from django.contrib.auth.decorators import login_required
'''
Decorator for views that checks that the user is logged in, redirecting
to the log-in page if necessary.
'''
# 【方案一】:直接在装饰器上面 login_url
# 没有登陆过的用户访问某个页面 ---> 跳转到登陆页面让用户去登录
# @login_required(login_url="/login/")
# 【方案二】:在全局的 settings 里面配置参数
# LOGIN_URL = '/login/'
@login_required
def index_decorators(request):
# 校验当前用户是否登录
return render(request, "index.html", locals())
【8】前端代码
- home.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<hr>
<p><a href="{% url 'register' %}">注册</a></p>
<p><a href="{% url 'login' %}">登陆</a></p>
<p><a href="{% url 'update' %}">修改密码</a></p>
<p><a href="{% url 'logout' %}">注销登录</a></p>
<p><a href="{% url 'check_login' %}">方法属性 校验是否登陆</a></p>
<p><a href="{% url 'check_login_decorators' %}">装饰器 校验是否登陆</a></p>
</body>
</html>
- index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>登陆成功后才能仿问</h1>
</body>
</html>
- login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>登陆页面</h1>
<form action="" method="post">
{% csrf_token %}
<p>
username <input type="text" name="username">
</p>
<p>
password <input type="text" name="password">
</p>
<p>
<input type="submit">
</p>
</form>
</body>
</html>
- register.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>注册页面</h1>
<form action="" method="post">
{% csrf_token %}
<p>
username <input type="text" name="username">
</p>
<p>
password <input type="text" name="password">
</p>
<p>
<input type="submit">
</p>
</form>
</body>
</html>
- update.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>修改密码页面</h1>
<form action="" method="post">
{% csrf_token %}
<p>
username <input type="text" name="username">
</p>
<p>
old_password <input type="text" name="old_password">
</p>
<p>
new_password <input type="text" name="new_password">
</p>
<p>
<input type="submit">
</p>
</form>
</body>
</html>
【四】扩展Auth表
【1】方式一
from django.db import models
# Create your models here.
from django.contrib.auth.models import User,AbstractUser
# 扩展 auth模块的 User表
# 方式一 : 继承 AbstractUser 扩写字段
class UserInfo(AbstractUser):
'''
原本有很多字段 原来的字段我不做更改!
基于原本的字段进行扩充
扩充字段 手机号 地址
'''
phone = models.CharField(max_length=11, null=True, blank=True)
addr = models.CharField(max_length=100, null=True, blank=True)
【2】方式二
from django.db import models
# 配置参数 在settings 里面 有一个参数项
# AUTH_USER_MODEL = 'user.UserInfo'
# 方式二 : 在新表中关联旧表
class UserInfo(models.Model):
phone = models.CharField(max_length=11, null=True, blank=True)
user = models.OneToOneField(
to="User"
)
- 需要再配置文件中声明 Django 要使用 UserInfo 替代 auth_user
AUTH_USER_MODEL = 'app01.UserInfo' ---'应用名.表名'
- 如果自己写表代替了 auth_user
- auth模块功能正常使用,参考的表也由 auth_user 变成了 UserInfo