Django作为一个功能完善的web开发框架,自带了一个强大的用户认证系统,可以实现用户认证、会话管理、权限管理等功能。下面用实例实现一个授权访问指定视图的功能。所有功能是在一个complaint应用下实现。
一、创建登录表单
在应用目录下创建一个forms.py文件,在文件内创建一个继承自AuthenticationForm的表单,表单由username和password字段构成。后面在登录页面和视图中都需要用到这个表单。
# forms.py
from django import forms
from django.contrib.auth.forms import AuthenticationForm
from django.contrib.auth.models import User
class CustomLoginForm(AuthenticationForm):
# 可以自定义字段属性,比如增加CSS类
username = forms.CharField(
label='用户名',
max_length=100,
widget=forms.TextInput(attrs={'class': 'form-control',
'placeholder': '用户名',
'autocomplete':'true'})
)
password = forms.CharField(
label='密码',
widget=forms.PasswordInput(attrs={'class': 'form-control',
'placeholder': '密码'})
)
二、创建登录和退出视图
登录视图可以用CBV或FBV来实现,使用authenticate和login函数来验证用户并登录,首先用基于类的视图来实现:
from .forms import CustomLoginForm
from django.contrib.auth import authenticate, login
def user_login(request):
if request.method == 'POST':
# print("获取到了POST请求")
form = CustomLoginForm(data=request.POST)
if form.is_valid():
username = form.cleaned_data.get('username')
password = form.cleaned_data.get('password')
# print(f'收到的用户名是{username},密码是{password}')
user = authenticate(request,username=username, password=password)
if user is not None:#如果user能返回数据,说明用户名密码正确
login(request, user)
return redirect('index')# 'index'已在urls.py中定义
else:
# print("用户名或密码错误啊")
form.add_error(None, '用户名或密码错误')
else:
# print("form.is_valid没有通过")
for field, errors in form.errors.items():
for error in errors:
print(f"Error in {field}: {error}")
else:
# print('初始化表单')
form = CustomLoginForm()
return render(request, 'complaint/login.html', {'form': form}) #返回到登录表单模板
用基于类的视图来实现:
from .forms import CustomLoginForm
from django.contrib.auth.views import LoginView
from django.urls import reverse_lazy
class CustomLoginView(LoginView):
template_name = 'complaint/login.html' # 登录表单模板
# 如果用户已登录,则重定向到的地址
redirect_authenticated_user = True
# 登录成功后的重定向地址
success_url = reverse_lazy('index')
def form_valid(self, form):
# 这里可以添加自定义的登录逻辑
username = form.cleaned_data.get('username')
password = form.cleaned_data.get('password')
print(f'收到的用户名是{username},密码是{password}')
return super().form_valid(form) # 调用父类的 form_valid 来完成默认的登录逻辑
退出视图比较简单,使用auth包中自带的logout函数退出后重定向到‘index’页面
from django.contrib.auth import logout
def user_logout(request):
logout(request)
return redirect('index') # 重定向到登录页面
三、创建一个登录模板
创建一个login.html,用于登录页面。‘login’稍后步骤中定义。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>登录</title>
</head>
<body>
<form method="post" action="{% url 'login' %}">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Login</button>
</form>
</body>
</html>
四、创建URLS路径
创建urls.py,添加路径来处理登录和退出的url。
from django.urls import path
from .views import *
from complaint import views
urlpatterns = [
path("",views.index,name='index'),
path('login/',views.user_login,name='login'),
# 如果是CBV,则使用下面路径。
#path('login/',CustomLoginView.as_view(),name='login'),
path('logout/',views.user_logout,name='logout'),
]
五、使用装饰器保护视图
如果是基于函数的视图,直接在视图函数前面添加@login_required即可。添加后,只有登录用户才可以访问
from django.contrib.auth.decorators import login_required
@login_required
def index(request):
# 只有登录用户才能访问此视图
# 需要在template文件夹下创建index.html。
return render(request, 'complaint/index.html')
如果是基于类的视图,则需要引入LoginRequiredMixin类。让被保护的视图继承自该类。
from django.views.generic import View
from django.contrib.auth.mixins import LoginRequiredMixin
from django.shortcuts import render
class IndexView(LoginRequiredMixin, View):
# 这里可以设置一些登录后重定向的选项
login_url = '/login/' # 未登录用户将被重定向到的URL
redirect_field_name = 'redirect_to'
def get(self, request, *args, **kwargs):
# 视图的GET请求处理逻辑
return render(request, 'complaint/index.html')
LogininRequiredMixin类提供了两个参数来实现自定义的重定向行为。
login_url
:未登录用户将被重定向到的URL。默认是/accounts/login/
。redirect_field_name
:用于存储原始请求路径的查询参数字段名。默认是next
。
六、其他
如果想在登录成功后返回正在访问的页面,可以通过设置redirect_field_name属性,通过在登录页面中设置一个隐藏的next属性来实现。
<!-- login.html -->
<form method="post" action="{% url 'login' %}">
{% csrf_token %}
{{ form.as_p }}
<input type="hidden" name="next" value="{{ request.GET.next }}">
<button type="submit">登录</button>
</form>
然后修改登录视图,在登录成功后重定向到next页面。
def user_login(request):
if request.method == 'POST':
form = CustomLoginForm(data=request.POST)
if form.is_valid():
username = form.cleaned_data.get('username')
password = form.cleaned_data.get('password')
# 在这里获取隐藏的next属性的值
next = request.POST.get('next')
user = authenticate(request,username=username, password=password)
print(user)
if user is not None
login(request, user)
if (next is not None) and next !='':
print(f"登录成功重定向到{next}")
return redirect(next) # 重定向
else:
print('重定向到首页')
return redirect('index')
else:
form.add_error(None, '用户名或密码错误')
else:
for field, errors in form.errors.items():
for error in errors:
print(f"Error in {field}: {error}")
else:
print('初始化表单')
form = CustomLoginForm()
return render(request, 'complaint/login.html', {'form': form})