给Django添加登录拦截器和登录验证码

前一篇文章里写了如何做登录、登出界面,看上去效果好像很不错,但是却有一个致命的漏洞:如果有人直接在地址栏里输入对应的url,那么就可以跳过登录验证直接访问!

这种情况我们需要做一个登录拦截器,这个拦截器的作用就是通过session来判断,如果在没有session的前提下登录网站内部url就会强制跳转到首页,让访问的人登录。

自建的登陆拦截器

首先是在APP的目录里(我的project叫Kubernetes)新建一个叫middleware.py的文件,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from django.shortcuts import HttpResponseRedirect
from django.utils.deprecation import MiddlewareMixin

#强制登录
class SimpleMiddleware(MiddlewareMixin):
def process_request(self, request):
if request.path != '' and request.path != '/login/': #判断请求的地址不是首页和/login/
if request.session.get('user',None): #如果session里不存在
pass
else:
return HttpResponseRedirect('/login/') #自动跳回到登录页面

#多次访问IP拉黑
class BlockedIpMiddleware(object):
def process_request(self, request):
if request.META['REMOTE_ADDR'] in getattr(settings, "BLOCKED_IPS", []): #如果有IP短时间内多次访问
return http.HttpResponseForbidden('<h1>Forbidden</h1>') #针对此IP给予403

然后在APP的目录里(我的project叫Kubernetes)的setting.py里把这两个中间件加进去。如下:

1
2
3
4
5
6
7
8
9
10
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'Kubernetes.middleware.SimpleMiddleware', #这个就是新加的
]

系统自动重启之后,来验证一下效果,是否在不登录的前提下成功拦截直接访问的url。

Django自带的登陆拦截器

上面那个方法逻辑上来说比较简单,能实现功能但是并不是很强力,Django也自带一个“强制登录”的功能,效果比那个强一丢丢。

首先我们先把APP目录里setting.py刚刚新加的'Kubernetes.middleware.SimpleMiddleware'注释掉。在文件末尾添加一句:

1
2
#登录路径
LOGIN_URL = '/login/'

然后返回到views.py,给需要登陆才能访问的页面添加一个装饰器:

1
2
3
4
5
6
7
8
9
10
11
from django.contrib.auth.decorators import login_required
@login_required #这个页面需要登陆
def tt(request):
name = ['james','wade','bosh','yaoming']
return render_to_response('test111.html',{'names':name})

def ttt(request): #这个页面就不需要了,公共读
cpu = 9.66
mem = 66.6
disk = 16.88
return render_to_response('test222.html',{'CPU':cpu,'MEMORY':mem,'DISKUSED':disk})

我在views.py里设定,访问tt这个函数(urls.py里配置的域名是/k8s/test111)的时候需要强制登陆,访问ttt这个函数(urls.py里配置的域名是/k8s/test222)就可以直接打开。系统重启django之后,我们试一下效果:
akb48

可见当访问到/k8s/test111的时候,浏览器会自动跳转到/login/?next=/k8s/test111/ 让你登录,登陆完毕之后才能顺利访问。而/k8s/test222就可以直接访问了。这个方法就是可以更加对受保护的网页有针对性配置,而不是上一个方法统一都跳转到登录面去。

测试的时候出现TypeError: object() takes no parameters报错,看一下是否是post方法请求的,因为get方法是产生一个tcp包,而post是两个。

登录验证码

为了防止机器人暴力破解密码,我们往往增加验证码来阻挡一下。市面上开源的比较高级的验证码是google recaptcha2,但是由于国内政策,大陆内的网站往往打不开这个界面。所以用Django Simple Captcha这个比较大众的验证码方式。

首先pip install django-simple-captha,然后在setting.py里把captha加入到INSTALL_APPS里。

然后是执行python manage.py makemigrationspython manage.pymigrate,再打开url.py,添加一句

1
2
3
4
5
6
7
8
9
10
11
12
from django.contrib import admin
from django.urls import path,include
from . import views

urlpatterns = [
path('',views.login,name='login'), #登录页
path('homepage.html',views.home,name='home'), #首页
path('admin/',admin.site.urls),
path('captcha/',include('captcha.urls')), #这句是新加的,验证码专用
path('k8s/',include('createyaml.urls')), #工具平台分支
path('ag/',include('accessgateway.urls')), #堡垒机分支
]

修改一下views.py,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
from django.contrib import auth
from django import forms
from captcha.fields import CaptchaField

class CaptchaForm(forms.Form): #引入一个类
captcha = CaptchaField()

#登陆
def login(request):
if request.POST:
form = CaptchaForm(request.POST) #将类实例化
username = request.POST.get('username', '')
password = request.POST.get('password', '')
user = auth.authenticate(username=username, password=password)
if form.is_valid(): #如果form合法
human = True #判断是人操作,而不是机器人
if user is not None:
auth.login(request, user) # 登录
#request.session['user'] = username # 记录session信息
response = HttpResponseRedirect('homepage.html')
response.set_cookie('username',username,3600) #将username写入cookie,超时时间是10分钟
return response
else:
return render(request,'index.html', {'error': '账号密码有误,请联系管理员!','login_form':form})
else:
return render(request,'index.html', {'error': '验证码有误,请重新输入!','login_form':form})
else:
form = CaptchaTestForm() # 否者要求重新输入
return render_to_response('index.html',{'login_form':form})

#其他部分略

最后修改对应的html页面,在对应的地方加入即可:

1
2
3
4
<div>
<font color='yellow'>验证码(看不清请刷新页面):</font>
{{ login_form.captcha }}
</div>

保存之后,系统重新启动django,在浏览器输入网址,就能看到效果了:
akb48

这个页面还没有完美,应该再加入一个ajax,实现“点击验证码,刷新页面”的功能就更完美了。

登录验证码的方式还有很多,除了这个django-simple-captha,还有像https://pypi.org/project/django_click_captcha/ 点击倒字的登录方法,甚至还有手机短信的登陆方法,这些高级的方法以后再研究吧。

参考资料

https://code.ziqiangxuetang.com/django/django-middleware.html
https://www.jianshu.com/p/1a95808faed9
https://blog.csdn.net/xxm524/article/details/48370337
http://www.calmkart.com/?p=332
https://fanquqi.github.io/2018/03/30/Django%E7%99%BB%E5%BD%95%E9%AA%8C%E8%AF%81/
https://blog.csdn.net/teavamc/article/details/77566781
https://blog.51cto.com/syklinux/2052484

感谢您请我喝咖啡~O(∩_∩)O,如果要联系请直接发我邮箱chenx1242@163.com,我会回复你的
-------------本文结束感谢您的阅读-------------