給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 等可獲取相關技術文章和資料,同時有任何問題均可以在公衆號後臺留言~

相關文章
相關標籤/搜索