Django 构建登录界面全面解析(手动写登录逻辑和使用自带验证逻辑)


以下为研究官方文档结合自己项目总结所得,在此做以记录。如果错误请高手指正。

概述

Django身份验证系统包括了身份验证和授权两个功能。
身份验证验证用户是谁
授权是一个被验证过的用户允许做些什么
身份验证系统包括:

  • 用户
  • 权限
  • 用户组
  • 一个可以配置的密码哈希值系统
  • 用于用户登录或者限制访问内用的Form和view
  • 一个可插拔的后端系统
    身份验证系统只包含一些通用的功能,对一切其他特殊功能,可以再其他第三方库中加入。Django不包括以下功能:
  • 密码强度检测
  • 多次尝试登录的限制
  • 第三方身份验证
  • 对象级别的权限

安装

  1. 在setting.py 文件的INSTALLED_APPS中包含以下两个
  • ‘django.contrib.auth’ 包括了验证框架的内核,他是默认模块
  • ‘django.contrib.contenttypes’ 是django的内容类型系统,允许权限和你创建的models相关联
# filename: setting.py
# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'file_sync.apps.FileSyncConfig',
    'note.apps.NoteConfig',
]
  1. 在 MIDDLEWARE 中设置:
  • SessionMiddleware 管理跨请求的sessions
  • AuthenticationMiddleware 使用sessions将users和requests相关联
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware', #HERE
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware', #HERE
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
  1. 设置完以上,运行 python3 manage.py migrate创建必要的database tables,对于已经安装的apps里的所有models,将models和权限联系起来。

用法

Django身份验证同时提供身份验证和授权,通常称为身份验证系统,因为这些功能在某种程度上是耦合的。

##user 对象(user objects),每个用户的属性
User 对象是验证系统的核心,通常代表了进入你网站的用户,并且用来管理他们比如限制进入,限制内容等。在Django中只存在一个user 类,"superusers"或者admin “staff” 的用户只是user对象中带有特殊属性的对象,并不是单独的类。
默认的user对象属性:

创建用户

  1. 通过admin页面创建
  2. 通过create_user()函数
from django.contrib.auth.models import User
user = User.objects.create_user('john', 'lennon@thebeatles.com', 'johnpassword')

创建superusers

使用命令行

$ python manage.py createsuperuser --username=joe --email=joe@example.com

如果不加–username和–email,会提示你输入

修改密码

Django没有显式密码,密码会被hash。改变密码的方式:

  1. manage.py changepassword username
  2. 在程序中:
from django.contrub.auth.models import User
u = User.objects.get(username='john')
u.set_password('new password')
u.save()
  1. 在admin界面修改

验证用户

authenticate(request=None , **credentials)[source]

使用aurhenticate()去验证资格,默认使用username和password去验证。如果验证合法,返回User对象,如果不合法或者后端产生权限禁止,该函数返回None。example:

from django.contrib.auth import authenticate
user = authenticate(username='john', password='secret')
if user is not None:
    # A backend authenticated the credentials
else:
    # No backend authenticated the credentials

request是一个可选项,给验证后端传入HttpRequest。

Note: 这种验证方法有些低级,除非是为你自己写的登录验证,否则请使用LoginView()

网络请求验证(自己写验证和登录逻辑)

登录

先验证身份,在使用login(User)进行登录,Django后台会自动处理cookie

def login_post(request):
    username = request.POST['username']
    password = request.POST['password']
    user = authenticate(request, username=username,password=password)
    if user is not None :
        login(request,user)
        #Redirect to a success page.
        #return render(request,'file_sync/upload.html')
        return HttpResponseRedirect(reverse('file_sync:upload'))
    else:
        return HttpResponse('login failed!')

登出

def logout_view(request):
    logout(request)
# return render(request,'file_sync/login.html')
    return HttpResponseRedirect(reverse('file_sync:loginview'))

Note: 重定向函数是HttpRespinseRedirect(),函数render是一个shortcuts,快捷函数,集成了打开请求,处理要返回的上下文(context)等。不可以用作网页跳转。使用rendr虽然会有跳转的作用,但是会缺少网页渲染所需要的数据,除非你在这个view中将数据处理后传过去。

手动写登录逻辑最终版本,包括对于next的处理

如果此页面需要登录,则跳转到登录界面,并且携带next参数对登录页面进行get请求。
例如:
当前页面为https://www.mysite.com/file_sync/
该页面需要登录查看,该页面的view前面有@login_required修饰,但是你没有登录,则会跳转到登录页面。如果你的登录页面位于/accounts/login/,那么你跳转的页面位置为
https://www.mysite.com/accounts/login/?next=/file_sync/
这里的next的参数是上一个页面的绝对地址,并且添加得到get请求中。在你处理登录界面的时候,需要对next参数进行特殊处理

def loginview(request):
    if 'GET' == request.method: #GET页面请求
        try : #尝试获取请求中GET的next参数,并且构成上写文
            next=request.GET['next'] #注意这里用try,因为当请求不包含next时,比如直接访问登录页面,GET['next']并不存在,会发生错误
            context = {
                'next':next
            }
        except :
            context={
            'next':'/index/' #如果没有next,制定next为主页面
            }
        return render(request,'file_sync/login.html',context)

    if 'POST'== request.method: #密码验证 前端需要传来三个参数
        username = request.POST['username']
        password = request.POST['password']
        next = request.POST['next']
        user = authenticate(request, username=username, password=password)
        if user is not None:
            login(request, user)
            #redirect to a success page.
            return HttpResponseRedirect(next)
        else:
            return HttpResponse('login failed!')

该页面前端

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Login</title>
</head>
<body>
    <div style="margin: 15% 40%;">
        <h1>欢迎登录!</h1>
       <form action="/file_sync/login/" method="post" enctype="multipart/form-data">
            <p>
                <label for="id_username">用户名:</label>
                <input type="text" id="id_username" name="username" placeholder="用户名" autofocus required />
            </p>
            <p>
                <label for="id_password">密码:</label>
                <input type="password" id="id_password" placeholder="密码" name="password" required >
            </p>
            <input type="submit" value="确定">
            <input type="hidden" name="next" value="{{ next }}">
       </form>
    </div>
</body>
</html>

如何使用viewLogin(使用Django自己提供的验证逻辑)

Django提供了viewLogin,只需要自己写前端页面,后端逻辑不用自己处理。当不复杂的时候推荐使用这种方法。

  1. 加入url
urlpatterns = [
   path('admin/', admin.site.urls),
   path('file_sync/',include('file_sync.urls')),
   path('note/',include('note.urls')),
   #path('', include('file_sync.urls')),
   path('accounts/', include('django.contrib.auth.urls'))
]

将会包含以下:

accounts/login/ [name='login']
accounts/logout/ [name='logout']
accounts/password_change/ [name='password_change']
accounts/password_change/done/ [name='password_change_done']
accounts/password_reset/ [name='password_reset']
accounts/password_reset/done/ [name='password_reset_done']
accounts/reset/<uidb64>/<token>/ [name='password_reset_confirm']
accounts/reset/done/ [name='password_reset_complete']
  1. 创建html文件。位置是registration/login.html,也可以更改位置为myapp/login,在
    虽然链接里是accounts开头,默认的位置是registration下,我习惯新建一个app叫做registration,然后在里面创建templates文件夹。
python3 startapp registration
cd registration
mkdir templates && cd templates
mkdir registration

大致目录结构

registration/
├── admin.py
├── apps.py
├── __init__.py
├── migrations
│   └── __init__.py
├── models.py
├── templates
│   └── registration
│       └── login.html
├── tests.py
└── views.py

关于url中可以设置的一些属性和例子

  • template_name 重命名模板
  • redirect_filed_name 重命名next 默认是next
  • authentication_form 验证表单,默认是AuthenticationForm
  • extra_contex 传递上下文的字典
  • redirect_authenticated_user
  • success_url_allowed_hosts 除了request.get_host()之外的一组主机,在登录后可以安全地重定向。默认为空集。

Warning
If you enable redirect_authenticated_user, other websites will be able to determine if their visitors are authenticated on your site by requesting redirect URLs to image files on your website. To avoid this “social media fingerprinting” information leakage, host all images and your favicon on a separate domain.
Enabling redirect_authenticated_user can also result in a redirect loop when using the permission_required() decorator unless the raise_exception parameter is used.

重新定位登录网页位置为myapp/login.html

from django.contrib.auth import views as auth_views
path('accounts/login',auth_views.LoginView.as_view(template_name='myapp/login.html'))

指定登录重定向页面名称,默认名是next,给为nextone

from django.contrib.auth import views as auth_views
path('accounts/login',auth_views.LoginView.as_view(redirect_filed_name='nextone'))

如果没有特殊要求,可以都不改。

前端模板

这个模板将会收到view传来的四个参数:

  • form
  • next 成功登录后的跳转地址。也可能是一个字符串 默认是/accounts/profie/ ,通过setting.py里面的LOGIN_REDIRECT_URL改变
  • site 当前地址
  • sitename site.name 的别名
{% block content %}
    {% if form.errors %}
    <p>Your username and passsword didn't match</p>
    {% endif %}
    {% if next %}
        {% if user.is_authenticated %}
        <p>Your account doesn't have access to this page</p>
        <% else %>
        <p>Please login to see this page</p>
        {% endif %}
    {% endif %}
    <form method="post" action="/accounts/login/">
        {% csrf_token %}
        <table>
            <tr>
                <td> {{ form.username.label_tag }}</td>
                <td> {{ form.username }}</td>
            </tr>
            <tr>
                <td>{{ form.password.label_tag }}</td>
                <td>{{ form.password }}</td>
            </tr>
        </table>
        <input type="submit" value="login">
        <input type="hidden" name="next" value="{{ next }}">
    </form>
{% endblock %}

关于重定向的全局设置

在setting中加入

LOGIN_REDIRECT_URL = '/file_sync/upload/' # login success redirect to
LOGOUT_REDIRECT_URL = '/accounts/login/' #logout and redirect to 
LOGIN_URL = '/accounts/login/' # 为了logout then login

##其他有用的函数

  1. redirect_to_login(next,login_url=None,redirect_filed_name=‘next’)
    ####Required arguments
  • 必要的参数 next ,成功登陆后跳转的页面
    ####Optionaal arguments
  • login_url : 登录界面的url,如果没给,默认为None,会自动加载setting里面设置的LOGIN_URL
  • redirect_filed_name : The name of a GET field containing the URL to redirect to after log out,Overrides next if the given GET parameter is passed.

页面需要登录查看的处理方法

方法一,手写验证

如果某个view需要登录或者验证才能使用,则用以下语法

if request.user.is_authenticated:
    # Do something for authenticated users.
    ...
else:
    # Do something for anonymous users.

方法二:使用修饰器 @ 对view进行接入限制

from django.contrib.auth.decorators import login_required
@login_required
def my_view(request):
    ...
login_required(redirect_field_name=‘next’, login_url=None)[source]

login_reqired() 做了如下

  • 如果用户没有登录,重定向去 settiong.LOGIN_URL, 并切把当前的绝对路传过去。
  • 如果用户登录了,这个view就可以使用了
    默认情况下,成功验证时用户应重定向到的路径存储在名为“next”的查询字符串参数中。如果您希望为此参数使用其他名称,则login_required()将使用可选的redirect_field_name参数,next将变成my_redirect_field:
from django.contrib.auth.decorators import login_required
@login_required(redirect_field_name='my_redirect_field')
def my_view(request):
    ...

举例2,提供登录的url

from django.contrib.auth.decorators import login_required
@login_required(login_url='/accounts/login/')
def my_view(request):
    ...

当使用类 view中,可以使用LoginRequiredMixin,用法:

from django.contrib.auth.mixins import LoginRequiredMixin
class MyView(LoginRequiredMixin, View):
    login_url = '/login/'
    redirect_field_name = 'redirect_to'

这个类的所有函数,对于未登录的用户都将重定向到登录界面或者403禁止进面

用户通过测试

例如,只有邮箱结尾是‘@example.com’的用户才有权限进入
直接使用:

from django.shortcuts import redirect
def my_view(request):
    if not request.user.email.endswith('@example.com'):
        return redirect('/login/?next=%s' % request.path)
    # ...

使用装饰器:

from django.contrib.auth.decorators import user_passes_test
def email_check(user):
    return user.email.endswith('@example.com')
@user_passes_test(email_check)
def my_view(request):
    ...

user_passes_test(*, login_url,redirect_filed_name)

Note user_passer_test 不会自动检测用户是匿名用户

对于类 UserPassesTestMixin
test_func()

在该类中需要重写test_func()方法提供检测

from django.contrib.auth.mixins import UserPassesTestMixin
class MyView(UserPassesTestMixin, View):
    def test_func(self):
        return self.request.user.email.endswith('@example.com')
get_test_func()

你也可以重写get_test_func()方法,以使mixin对其检查使用不同名称的函数(而不是test_func())。
具体见官网文档

  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是一个简单的示例,用于在前台显示Django用户登录界面: 1. 创建Django项目并设置好数据库。 2. 在settings.py文件中设置好AUTHENTICATION_BACKENDS,并确保Django的默认认证后端已启用。 3. 在项目根目录下,创建一个名为“templates”的文件夹,并在其中创建一个名为“login.html”的HTML模板文件。 4. 在login.html模板文件中,添加以下代码: ``` <!DOCTYPE html> <html> <head> <title>Login Page</title> </head> <body> <h2>Login</h2> <form method="post"> {% csrf_token %} <label for="username">Username:</label> <input type="text" name="username" id="username"><br><br> <label for="password">Password:</label> <input type="password" name="password" id="password"><br><br> <input type="submit" value="Login"> </form> </body> </html> ``` 5. 创建一个名为“views.py”的文件,添加以下代码: ``` from django.shortcuts import render, redirect from django.contrib.auth import authenticate, login def login_view(request): if request.method == 'POST': username = request.POST['username'] password = request.POST['password'] user = authenticate(request, username=username, password=password) if user is not None: login(request, user) return redirect('home') return render(request, 'login.html') ``` 6. 在登录应用程序的urls.py文件中添加以下代码: ``` from django.urls import path from . import views urlpatterns = [ path('login/', views.login_view, name='login'), ] ``` 7. 在项目根urls.py文件中添加以下代码: ``` from django.contrib import admin from django.urls import path, include urlpatterns = [ path('', include('login.urls')), path('admin/', admin.site.urls), ] ``` 8. 在settings.py文件中设置好LOGIN_REDIRECT_URL,以确保在用户成功登录后重定向到正确的页面。 9. 运行Django项目,并访问http://localhost:8000/login/即可在前台显示Django用户登录界面
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值