Django 之login_required的知识点

发布时间 2023-08-19 23:05:48作者: 九尾cat

Django 之login_required的知识点

在进行页面登录验证优化时,想到了用户验证登录和登出及限流功能,在添加用户登录调用@login_required时,访问/login自动跳转到/accounts/login/,这个路由又没有定义就是显示404状态码。

作为一个新入门的学习者首先是排查路由配置、视图、去掉验证@login_required验证发现是@login_required的跳转定义问题,在没有定义的情况下默认跳转路径就是/accounts/login/,这下就破案了。

接下来,就是找解决方案,搜一下@login_required验证失败重定向的配置即可。

路由配置

from django.contrib import admin
from django.urls import path, include
from myapp.views import *

urlpatterns = [
    path('admin/', admin.site.urls),
    path('login/', login_view, name='login'),
    path('logout/', user_logout, name='logout'),
    path('captcha/', include('captcha.urls')),
    path('upload/', upload_file, name='upload'),
]

视图配置

from django.contrib import messages
from captcha.models import CaptchaStore
from captcha.helpers import captcha_image_url
from django.shortcuts import redirect

#添加用户登录视图和注销视图:
from django.contrib.auth.decorators import login_required
from django.contrib.auth import authenticate, login, logout

import paramiko
import tempfile

def login_view(request):
  if request.method == 'POST':
    username = request.POST.get('username')
    password = request.POST.get('password')
    captcha_solution = request.POST.get('captcha_solution')
    captcha_key = request.POST.get('captcha_key')

    # 验证码校验
    if captcha_key and captcha_solution:
      if not CaptchaStore.objects.filter(response=captcha_solution, hashkey=captcha_key).exists():
        messages.error(request, '验证码错误')
        return redirect('login')

    # 身份验证
    user = authenticate(request, username=username, password=password)
    if user:
      login(request, user)
      return redirect('upload')
    else:
      messages.error(request, '用户名或密码错误')
      return redirect('login')

  new_key = CaptchaStore.generate_key()
  image_url = captcha_image_url(new_key)

  return render(request, 'login.html', {'key': new_key, 'image_url': image_url})


@login_required
def user_logout(request):
    logout(request)
    messages.info(request,'退出登录')
    return redirect('login')

#定义限流装饰器
from django.core.cache import cache
from django.http import HttpResponseForbidden

def rate_limit(limit_count):
    def decorator(view_func):
        def wrapper(request, *args, **kwargs):
            # 获取当前用户
            user = request.user

            # 检查该用户的访问次数
            cache_key = f'rate_limit:{user.username}'
            access_count = cache.get(cache_key, 0)

            # 如果访问次数超过限制,返回 403 Forbidden
            if access_count >= limit_count:
                # logging.error('用户 {}  查看上传文件列表失败'.format(request.user.username, datetime.now()))
                return HttpResponseForbidden('访问次数超过限制')

            # 增加访问次数并设置缓存时间为 1 分钟
            cache.set(cache_key, access_count + 1, 60)

            # 继续执行视图函数
            return view_func(request, *args, **kwargs)

        return wrapper

    return decorator

#上传视图
@login_required
def upload_file(request):
    if request.method == 'POST':
        file = request.FILES.get('file')
        if file:
            # 连接远程服务器
            ssh = paramiko.SSHClient()
            ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            # ssh.connect('remote_server_ip', username='username', password='password')
            ssh.connect('10.0.0.127', username='root', password='123456')


            try:
                # 创建临时文件
                with tempfile.NamedTemporaryFile(delete=False) as temp_file:
                    # 将上传的文件内容写入临时文件
                    for chunk in file.chunks():
                        temp_file.write(chunk)
                    temp_file.seek(0)  # 将文件指针移动到文件开头

                    # 上传临时文件到远程服务器的/data目录
                    sftp = ssh.open_sftp()
                    #使用用户密码/秘钥连接
                    sftp.putfo(temp_file, '/home/yunwei/apache-jmeter-5.5/ProCase/scrpit/' + file.name)

                    sftp.close()
                    ssh.close()

                messages.success(request, '文件上传成功')
                return redirect('upload')  # 重定向到上传页面
            except Exception as e:
                messages.error(request, '文件上传失败:{}'.format(str(e)))
        else:
            messages.error(request, '请选择要上传的文件')

    return render(request, 'upload.html')

 

 

解决方案

在Django中,可以使用login_required装饰器来对视图函数进行登录验证。当用户没有登录时,装饰器会将用户重定向到默认的登录页面或者自定义的登录页面。

默认情况下,Django的login_required装饰器会将用户重定向到名为/accounts/login/的URL。如果你希望自定义登录跳转的URL,你可以在项目中进行相关配置。

首先,你需要在项目的URL配置文件(通常是urls.py)中定义一个URL来处理登录验证失败重定向的请求

from django.urls import path

from django.contrib.auth.views import LoginView

urlpatterns = [
    path('my-login/', LoginView.as_view(), name='my_login'),
    # other URLs
]

my-login/路由将被用于处理登录验证失败的跳转请求。LoginView是Django内置的登录视图,它会自动渲染一个登录页面。

接下来,你需要告诉Django在登录验证失败时应该重定向到哪个URL。你可以在项目的设置文件(通常是settings.py)中添加以下配置:

LOGIN_URL = '/my-login/'

在这个配置中,LOGIN_URL设置为/my-login/,即登录验证失败时应该重定向到my-login/路由。

通过以上配置,当使用login_required装饰器的视图函数登录验证失败时,用户将被重定向到my-login/路由,即自定义的登录页面。

请注意,login_required装饰器需要和Django的认证系统一起工作。你需要在项目中启用认证系统并配置相关认证后端和用户模型。