当我的启动处于黑暗模式时,我希望除了访问/转到屏幕之外的所有访问权限,用户可以在屏幕上输入代表给他们的密码。我已经提出了以下简单的中间件来执行该任务。需要明确的是,这是为了确保用户在被允许浏览之前同意对网站保密,而不是用作安全系统或.htaccess克隆。然而,我想防止他们在不知道屏蔽程序密码的情况下看到任何公共页面(即那些没有用@login_required装饰的页面)。password_check函数使用Django Auth生成输入密码的哈希,以检查数据库值。
你们能看到什么想法/规避技巧吗?我的一个想法是更改登录功能,将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 建议的Regexes
这是我的解决方案。它使用的不是COOKIES,而是自定义的Auth-Backend。
步骤1
有一个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
设置.py:
INSTALLED_APPS = (
# ...
'key_auth',
)
步骤2
我们需要模型来存储您的代币型号.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)
注意:在我的简单解决方案中,您需要手动创建和同步新用户及其安全密钥。但你可以在未来改进这一点。
步骤3
我们需要一个自定义的中间件,它需要所有页面上所有用户的身份验证(除了少数特殊页面)。这是中间件.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)
该中间件将未经授权的用户重定向到"key_auth_login"页面,其中包含身份验证表单。
步骤4
以下是映射"key_auth_login"视图的urls.py:
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'),
)
正如你所看到的-管理网站已经打开(所以你也可以以管理员身份登录)。
步骤5
以下是我们的视图(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",因为它是一个非常简单的表单模板,没有什么特别之处。但我会展示形式类
步骤6
表单类(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()在这里使用。此方法将尝试使用现有后端对用户进行身份验证。
步骤7
自定义身份验证后端后端.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',
)
第二个是留下来保持管理网站的工作。
简历
就是这样!
- 任何请求都将通过KeyAuthMiddleware
- KeyAuthMiddleware跳过登录、注销和管理URL
- 。。。并将所有未经授权的用户重定向到令牌身份验证登录页面(带有令牌登录表单)
- 此表单通过django.contrib.auth.authenticate()方法验证"key"
- 。。。尝试通过自定义KeyAuthBackend身份验证后端对用户进行身份验证
- 如果身份验证成功且表单有效,则自定义KeyAuthLoginView生成django.contrib.auth.login(用户)并重定向到请求的页面
您还可以免费使用管理站点和登录/注销视图。