Django 和 Yubikey 集成

Django and Yubikey integrate

我想将 Yubikey 与我的 Django 应用程序集成。每当我尝试添加 2FA Yubikey: localhost:8080/account/two_factor/setup/ 时,我都会收到 403 HTTP Forbidden 错误。我如何在Django中实现Yubikey,因为当我使用这些教程时,实现失败。

当我按照示例 here 做同样的事情时,我得到 Server Error 500

我遵循了这些教程:

这是我所做的:

pip install django-two-factor-auth
pip install django-otp-yubikey
pip install django-otp

我使用 Python 3.7.3 和 Django 3.0.8

在我的 settings.py 我添加了:

INSTALLED_APPS = [
    ...
    # OTP
    'django_otp',
    'django_otp.plugins.otp_static',
    'django_otp.plugins.otp_totp',
    'two_factor',
    'otp_yubikey',
    ...
]

MIDDLEWARE = [
    ...
    'django_otp.middleware.OTPMiddleware',
    ...
]

LOGIN_URL = 'two_factor:login'

TWO_FACTOR_PATCH_ADMIN = True

在我的 urls.py 我添加了:

from two_factor.urls import urlpatterns as tf_urls
from django_otp.views import LoginView
...

urlpatterns = [
    ...
    # OTP
    path('', include(tf_urls)),
    ...
]

并且在我的 views.py 中添加了:

from django_otp.decorators import otp_required

@otp_required
def home_view(request):
    return render(request, 'home.html', {'result': 'test')

我的home.html很简单:

<html>
    <head></head>
    <body><p>test</p></body>
</html>

堆栈跟踪:

ERROR 2020-07-20 14:14:24,571 log 35773 123145342668800 Internal Server Error: /account/two_factor/setup/
Traceback (most recent call last):
File "/Users/user_anon/work_folder/home_dir/venv/lib/python3.7/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "/Users/user_anon/work_folder/home_dir/venv/lib/python3.7/site-packages/django/core/handlers/base.py", line 115, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/Users/user_anon/work_folder/home_dir/venv/lib/python3.7/site-packages/django/core/handlers/base.py", line 113, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/Users/user_anon/work_folder/home_dir/venv/lib/python3.7/site-packages/django/views/generic/base.py", line 71, in view
return self.dispatch(request, *args, **kwargs)
File "/Users/user_anon/work_folder/home_dir/venv/lib/python3.7/site-packages/django/utils/decorators.py", line 43, in _wrapper
return bound_method(*args, **kwargs)
File "/Users/user_anon/work_folder/home_dir/venv/lib/python3.7/site-packages/django/views/decorators/cache.py", line 44, in _wrapped_view_func
response = view_func(request, *args, **kwargs)
File "/Users/user_anon/work_folder/home_dir/venv/lib/python3.7/site-packages/django/utils/decorators.py", line 43, in _wrapper
return bound_method(*args, **kwargs)
File "/Users/user_anon/work_folder/home_dir/venv/lib/python3.7/site-packages/django/contrib/auth/decorators.py", line 21, in _wrapped_view
return view_func(request, *args, **kwargs)
File "/Users/user_anon/work_folder/home_dir/venv/lib/python3.7/site-packages/formtools/wizard/views.py", line 244, in dispatch
response = super().dispatch(request, *args, **kwargs)
File "/Users/user_anon/work_folder/home_dir/venv/lib/python3.7/site-packages/django/views/generic/base.py", line 97, in dispatch
return handler(request, *args, **kwargs)
File "/Users/user_anon/work_folder/home_dir/venv/lib/python3.7/site-packages/two_factor/views/utils.py", line 156, in post
return super().post(*args, **kwargs)
File "/Users/user_anon/work_folder/home_dir/venv/lib/python3.7/site-packages/formtools/wizard/views.py", line 294, in post
if form.is_valid():
File "/Users/user_anon/work_folder/home_dir/venv/lib/python3.7/site-packages/django/forms/forms.py", line 180, in is_valid
return self.is_bound and not self.errors
File "/Users/user_anon/work_folder/home_dir/venv/lib/python3.7/site-packages/django/forms/forms.py", line 175, in errors
self.full_clean()
File "/Users/user_anon/work_folder/home_dir/venv/lib/python3.7/site-packages/django/forms/forms.py", line 376, in full_clean
self._clean_fields()
File "/Users/user_anon/work_folder/home_dir/venv/lib/python3.7/site-packages/django/forms/forms.py", line 397, in _clean_fields
value = getattr(self, 'clean_%s' % name)()
File "/Users/user_anon/work_folder/home_dir/venv/lib/python3.7/site-packages/two_factor/forms.py", line 84, in clean_token
return super().clean_token()
File "/Users/user_anon/work_folder/home_dir/venv/lib/python3.7/site-packages/two_factor/forms.py", line 70, in clean_token
if not self.device.verify_token(token):
File "/Users/user_anon/work_folder/home_dir/venv/lib/python3.7/site-packages/otp_yubikey/models.py", line 280, in verify_token
response = client.verify(token)
File "/Users/user_anon/work_folder/home_dir/venv/lib/python3.7/site-packages/yubiotp/client.py", line 48, in verify
stream = urlopen(url)
File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.7/lib/python3.7/urllib/request.py", line 222, in urlopen
return opener.open(url, data, timeout)
File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.7/lib/python3.7/urllib/request.py", line 531, in open
response = meth(req, response)
File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.7/lib/python3.7/urllib/request.py", line 641, in http_response
'http', request, response, code, msg, hdrs)
File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.7/lib/python3.7/urllib/request.py", line 569, in error
return self._call_chain(*args)
File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.7/lib/python3.7/urllib/request.py", line 503, in _call_chain
result = func(*args)
File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.7/lib/python3.7/urllib/request.py", line 649, in http_error_default
raise HTTPError(req.full_url, code, msg, hdrs, fp)
urllib.error.HTTPError: HTTP Error 403: Forbidden

唉,好吧,所以我编辑了 yubiotp 中的 client.py,因此可以完全控制 urlopen

中使用的 URL

已替换

stream = urlopen(url)

from app import views as v_yow
...
stream = v_yow.test(url)

views.py:

from six.moves import xrange
from six.moves.urllib.parse import urlencode
from six.moves.urllib.request import urlopen

import urllib


def test(url):
    """
    """
    print('Testing 123')
    print(url)
    url_without_http = url[4:]
    url_with_https = 'https' + url_without_http

    stream = urlopen(url_with_https)
    return stream

而且效果很好。所以这里的问题是请求的 URL 是 HTTP url 而不是 HTTPS url。 HTTP url 重定向到 HTTPS 但无法写入库 urlopen(url).

因此,为了在没有这种奇怪的“修复”的情况下完成这项工作,请确保在 :

中将 use_ssl 设置为 True
classotp_yubikey.models.ValidationService(*args, **kwargs)[source]