给Django Admin添加验证码和屡次登陆尝试限制

Django自带的Admin很好用,可是放到生产环境总还差了点什么= =html

看看admin的介绍:java

Django奉行Python的内置电池哲学。它自带了一系列在Web开发中用于解决常见问题或需求的额外的、可选工具。这些工具和插件,例如django.contrib.redirects都必须在settings中的INSTALLED_APPS处进行注册,有的还须要执行manage.py migrate命令,在数据库中建立一些数据表。python

Admin站点是Django有别于其它Web框架最重要的一点,而且很是受欢迎,简直是出门旅游xxxx的必备。无论你是写个小demo仍是作个大项目都用得上。admin(下文中将Admin管理后台简称为admin)经过读取你的模型数据,快速构造出一个能够对实际数据进行管理的Web站点,经常使用于开发测试,简单管理等场合,适用于部门内部为工做方便的场合,但不建议在生产环境中使用。linux

为何不建议在生产环境使用呢,由于Admin缺了验证码和登陆限制这种安全方面的功能!等会被人随便暴力破解就进后台了,那咱们的系统安全性还怎么保障?android

可是别急,我已经经过魔改的方式实现了验证码和登陆限制了,如今能够愉快使用admin系统了。git

先看看效果

效果仍是nice的,登陆尝试次数能够本身设定,我这里就不演示了,输那么屡次错误密码太麻烦了。github

验证码

验证码我是用了django-simple-captcha这个库,配合multi_captcha_admin来生成验证码form,很是方便。redis

首先是pip安装这两个库,你们都懂的,再也不赘述。数据库

配置一下 settings.pydjango

INSTALLED_APPS = [
    'multi_captcha_admin',
]

# 验证码配置
MULTI_CAPTCHA_ADMIN = {
    'engine': 'simple-captcha',
}

配置 urls.py

# 添加这一项
path('captcha/', include('captcha.urls')),

到了这步就好啦,若是用的是Django官方的Admin就直接能显示出登陆的验证码了,不过我用的是第三方的Admin,因此须要手动添加form。

方法很简单,找到login.html,在登陆的表单里面添加这一项就行了。

{{ form.captcha }}

默认生成的验证码和输入框是原生样式,比较丑~ 咱们能够优化一下。我是用js把生成的图片和验证码输入框替换成elementUI的样式,有须要的小伙伴能够参考一下。

var row = document.querySelector('#captcha_group');

var captcha_img = document.querySelector('img.captcha');
var col_8 = document.createElement('el-col');
col_8.setAttribute(':span', '8');
col_8.appendChild(captcha_img);

var captcha_input = document.querySelector('#id_captcha_1');
var el_input = document.createElement('el-input');
var col_16 = document.createElement('el-col');
col_16.setAttribute(':span', '16');
el_input.setAttribute('name', captcha_input.getAttribute('name'));
el_input.setAttribute('v-model', 'captcha');
el_input.setAttribute('required', 'required');
el_input.setAttribute('placeholder', '请输入验证码');
col_16.appendChild(el_input);

captcha_input.parentNode.removeChild(captcha_input);

row.appendChild(col_8);
row.appendChild(col_16);

登陆限流

这个也不复杂,不过我一开始作仍是花了比较长时间,查不到什么有用的资料,后面我去读了Django Admin的代码,一下就想出解决方法了哈哈~

经过admin的代码,我发现处理登陆是admin.site.login(request, extra_context)这个方法,那问题就变得很简单了,给他加一个装饰器就行了,不过咱们不能去修改框架的代码,因此本身写一个新的view,以下:

# 覆盖默认的admin登陆方法实现登陆限流
@ratelimit(key='ip', rate='5/m', block=True)
def extend_admin_login(request, extra_context=None):
    return admin.site.login(request, extra_context)

而后在urls.py里配置一下,记得要放在admin的前面:

urlpatterns = [
    path('admin/login/', views.extend_admin_login),
    path('admin/', admin.site.urls),
]

这样就能够实现限流了,这里要介绍一下ratelimit这个装饰器,这是django-ratelimit这个包提供的,为了使用这个包,须要配置redis缓存,附上配置代码:

# 配置redis缓存
CACHES = {
    'default': {
        'BACKEND': 'django_redis.cache.RedisCache',  # 缓存后端 Redis
        # 链接Redis数据库(服务器地址)
        # 一主带多从(能够配置个Redis,写走第一台,读走其余的机器)
        'LOCATION': [
            'redis://localhost:6379/0',
        ],
        'KEY_PREFIX': 'milky',  # 项目名当作文件前缀
        'OPTIONS': {
            'CLIENT_CLASS': 'django_redis.client.DefaultClient',  # 链接选项(默认,不改)
            'CONNECTION_POOL_KWARGS': {
                'max_connections': 512,  # 链接池的链接(最大链接)
            },
        }
    }
}

@ratelimit(key='ip', rate='5/m', block=True)key=ip表示根据ip来区分,rate=5/m表示一分钟最多请求这个接口5次,block=true表示超过这个限制就直接拦截,若是没有设置block参数的话,超过限制也不会拦截,可是能够在ratelimit计数器里面看到请求的次数。

更多用法能够看官方文档:https://django-ratelimit.readthedocs.io/en/stable/index.html

参考资料

欢迎交流

我整理了一系列的技术文章和资料,在公众号「程序设计实验室」后台回复 linux、flutter、c#、netcore、android、java、python 等可获取相关技术文章和资料,同时有任何问题均可以在公众号后台留言~

相关文章
相关标签/搜索