当我的启动处于黑暗模式时,我希望除访问/之外的所有访问都进入筛选页面,用户可以输入代表给他们的密码。我想出了以下简单的中间件来执行任务。需要明确的是,这是为了确保用户同意在允许网站浏览之前保密网站,而不是用作安全系统或.htaccess克隆。但是我想在不知道screener密码的情况下阻止他们看到任何公共页面(即那些没有用@login_required修饰的页面)。 password_check函数使用Django Auth生成输入密码的哈希,以检查db值。
你们可以看到的任何想法/规避技巧?我的一个想法是更改登录功能以将LicenceKey推送到新登录的用户会话,而不是为登录用户提供豁免。但是,由于他们只能通过登录创建一个新会话,并且登录需要同意筛选器,这似乎是多余的。
反馈意见。
中间件看起来像这样:
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
import re
class LicenceScreener(object):
SCREENER_PATH = reverse("licence")
INDEX_PATH = reverse("index")
LICENCE_KEY = "commercial_licence"
def process_request(self, request):
""" Redirect any access not to the index page to a commercial access screener page
When the screener form is submitted, request.session[LICENCE_KEY] is set.
"""
if not LicenceScreener.LICENCE_KEY in request.session \
and not request.user.is_authenticated() \
and LicenceScreener.SCREENER_PATH != request.path\
and LicenceScreener.INDEX_PATH != request.path:
return HttpResponseRedirect(self.SCREENER_PATH)
视图如下:
def licence(request):
c = RequestContext(request, {} )
if request.method == 'POST':
form = LicenceAgreementForm(request.POST)
if form.is_valid():
if password_check(form.cleaned_data["password"]):
request.session[LicenceScreener.LICENCE_KEY] = True
return HttpResponseRedirect(reverse("real-index"))
else:
form._errors["password"] = form.error_class([_("Sorry that password is incorrect")])
else:
form = LicenceAgreementForm()
c["form"] = form
return render_to_response('licence.html',c)
编辑1.按照Tobu的建议删除正则表达式
答案 0 :(得分:1)
这是我的解决方案。它不是使用COOKIES而是使用自定义Auth Backend。
最好有一个 Django应用程序:
key_auth/
templates/
key_auth_form.html # very simple form template
__init__.py
models.py
urls.py
views.py
forms.py
middleware.py
backend.py
settings.py :
INSTALLED_APPS = (
# ...
'key_auth',
)
我们需要模型来存储您的令牌。 models.py :
from django.db import models
from django.contrib.auth.models import User
class SecurityKey(models.Model):
key = models.CharField(max_length=32, unique=True)
user = models.OneToOneField(User)
注意:在我的简单解决方案中,您需要手动创建和同步新用户及其SecurityKeys。但是你将来可以改进这一点。
我们需要一个自定义中间件,需要所有用户在所有页面上进行身份验证(少数特殊页面除外)。这是 middleware.py :
from django.contrib.auth.decorators import login_required
from django.core.urlresolvers import reverse
class KeyAuthMiddleware(object):
def process_view(self, request, view_func, view_args, view_kwargs):
login_url = reverse('key_auth_login') # your custom named view
# Exceptional pages
login_page = request.path.find(login_url) == 0
logout_page = request.path.find(reverse('logout')) == 0
admin_page = request.path.find(reverse('admin:index')) == 0 # I've excluded Admin Site urls
if not login_page and not logout_page and not admin_page:
view_func = login_required(view_func, login_url=login_url)
return view_func(request, *view_args, **view_kwargs)
此中间件会将未经授权的用户重定向到带有auth表单的“key_auth_login”页面。
以下是 urls.py ,它们映射了'key_auth_login'视图:
from django.conf.urls.defaults import patterns, url
urlpatterns = patterns('key_auth.views',
url(r'^$', 'login_view', name='key_auth_login'),
)
全球项目的 urls.py :
from django.contrib import admin
from django.conf.urls.defaults import patterns, include, url
admin.autodiscover()
urlpatterns = patterns('',
url(r'^key_auth/$', include('key_auth.urls')),
url(r'^logout/$', 'django.contrib.auth.views.logout', {'next_page': '/'}, name='logout'),
url(r'^admin/', include(admin.site.urls)),
url(r'^$', 'views.home_page'),
)
正如您所见 - 管理站点已启用(因此您也可以以管理员身份登录)。
以下是我们的观点( views.py ):
from django.contrib.auth import login
from django.views.generic.edit import FormView
from key_auth.forms import KeyAuthenticationForm
class KeyAuthLoginView(FormView):
form_class = KeyAuthenticationForm
template_name = 'key_auth_form.html'
def form_valid(self, form):
login(self.request, form.user)
return super(KeyAuthLoginView, self).form_valid(form)
def get_success_url(self):
return self.request.REQUEST.get('next', '/')
login_view = KeyAuthLoginView.as_view()
我不会显示'key_auth_form.html'因为它是非常简单的表单模板,没什么特别的。但我会展示表格类
表单类( forms.py ):
from django import forms
from django.contrib.auth import authenticate
class KeyAuthenticationForm(forms.Form):
key = forms.CharField('Key', help_text='Enter your invite/authorization security key')
user = None
def clean_key(self):
key = self.cleaned_data['key']
self.user = authenticate(key=key)
if not self.user:
raise forms.ValidationError('Please, enter valid security key!')
return key
正如我们所见,authenticate()在这里使用。此方法将尝试使用现有后端对用户进行身份验证。
自定义身份验证后端。 backend.py :
from django.contrib.auth.models import User
from key_auth.models import SecurityKey
class KeyAuthBackend(object):
def authenticate(self, key=None):
try:
return SecurityKey.objects.get(key=key).user
except SecurityKey.DoesNotExist:
return None
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
这很简单!只需检查密钥(令牌)即可。 这是它的安装( settings.py ):
AUTHENTICATION_BACKENDS = (
'key_auth.backends.KeyAuthBackend',
'django.contrib.auth.backends.ModelBackend',
)
留下第二个用于保持管理站点正常工作。
就是这样!
您还可以使用免费的key_auth ckeck管理站点和登录/注销视图。