我对 很陌生Django
,并且被分配了构建一个对用户进行身份验证的 Web 应用程序的任务,一旦通过身份验证,用户就可以在服务器LDAP
中搜索一个人/组。LDAP
在过去的几周里,我一直在纠结如何设置它并且已经写了一些帖子,但他们没有提出任何建议。我意识到,因为我最初想在我的views.py
. 相反,这些身份验证功能旨在构建为中间件,这为我打开了一个全新的蠕虫罐。
我意识到在任何情况下我都被限制在 中执行整个任务view.py
,因为这阻止了用户切换到新页面并仍然在 LDAP 中保持身份验证(我发现conn
对象的解析有点笨拙,请参见此处)。
无论如何,在阅读并观看了几个信息丰富的视频之后,比如这里和这里,我设法让我的中间件工作的第一步。但是,Django 中发生了一些正在工作的进程,我不完全理解为什么。让我解释一下,但首先是相关代码:
ldap_interface.py
try:
from ldap3 import Server, Connection, ALL, SUBTREE, LDAPBindError, LDAPSocketOpenError, AUTH_SIMPLE, STRATEGY_SYNC, \
MODIFY_ADD, MODIFY_REPLACE, MODIFY_DELETE
except ImportError as e:
raise ImportError("Import of ldap3 module unsuccessful: {0}".format(e))
from django.conf import settings
##########################################
### ERROR HANDLING ###
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)
#Create file handler
handler = logging.FileHandler('C:\\Users\\me\\Desktop\\LDAP_auth.log')
handler.setLevel(logging.DEBUG)
#Create logging format
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
#Add handlers to the logger
logger.addHandler(handler)
##########################################
class LDAP_Auth_Backend:
def __init__(self, get_response, un=None, pw=None):
print("A:{0}".format(get_response))
self.get_response = get_response
print("B:{0}".format(self.get_response))
def __call__(self, request):
response = self.get_response(request)
print("D:{0}".format(response))
return response
"""
def process_request(self, request):
print ("Middleware executed")
"""
def ldap_connect(self, un=None, pw=None):
try:
# Define the server
server = Server(settings.LDAP_SERVER, get_info=ALL)
# Connection and Bind operation
conn = Connection(server, user=un, password=pw, \
auto_bind=True,check_names=True)
conn.start_tls() # Session now on a secure channel.
return conn
except LDAPBindError as e:
print ("LDAPBindError, credentials incorrect: {0}".format(e))
logger.debug("LDAPBindError, credentials incorrect: {0}".format(e))
return HttpResponse('Invalid login')
except LDAPSocketOpenError as e:
print ("LDAPSocketOpenError, LDAP Server connection error: {0}".format(e))
logger.debug("LDAPSocketOpenError, LDAP Server connection error: {0}".format(e))
sys.exit(1)
设置.py
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'UserAuth.Middleware.ldap_interface.LDAP_Auth_Backend',
]
视图.py
def ldap_authentication(request):
if request.POST:
username = request.POST['username']
LDAP_MODIFY_PASS = request.POST['password']
searchFilter = request.POST['searchUser']
LDAP_AUTH_SEARCH_DN = '{}\\{}'.format(DOMAIN_NAME, username) # Should be the same as conn.extend.standard.who_am_i()
conn = LDAP_Auth_Backend.ldap_connect(request, un=LDAP_AUTH_SEARCH_DN, pw=LDAP_MODIFY_PASS)
print ("C: {0}".format(conn))
conn.search(
search_base=LDAP_AUTH_SEARCH_BASE,
search_filter= '(cn={})'.format(searchFilter), # This is the user being searched for
search_scope=SUBTREE # Other parameters are BASE & LEVEL
)
entry = conn.entries[0]
dn = entry._dn
split_dn = dn.split(",")
request.session.set_expiry(10)
return render(request, 'search_page.html', {'dn':split_dn})
return render(request, 'login.html')
网址.py
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^$', ldap_authentication, name='index'),
]
如前所述,在进入日志页面、输入正确的凭据和搜索名称后,LDAP 搜索会在单独的页面上返回有关 cn、dc 等的信息。这是迄今为止的意图,并将在适当的时候扩大。
安慰
System check identified no issues (0 silenced).
August 02, 2017 - 15:44:30
Django version 1.11, using settings 'UserAuth.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.
A:<function BaseHandler._get_response at 0x000000B93CE89C80>
B:<function BaseHandler._get_response at 0x000000B93CE89C80>
A:<function BaseHandler._get_response at 0x000000B93B863378>
B:<function BaseHandler._get_response at 0x000000B93B863378>
C: ldap://an_ip:389 - cleartext - user: random_name - bound - open - <local: another_ip:55135 - remote: etc> - tls started - listening - SyncStrategy
D:<HttpResponse status_code=200, "text/html; charset=utf-8">
[02/Aug/2017 15:44:41] "POST / HTTP/1.1" 200 1867
[02/Aug/2017 15:44:41] "GET /static/bourbon HTTP/1.1" 404 1634
我通过在我的代码中放置打印语句来测试正在发生的事情,例如你可以看到的地方"A", "B", "C", "D"
。
问题:
- 运行命令后,在登录之前,在
runserver
运行中间件脚本时调用“A”、“B”打印语句,但正如您所见,它们不是被调用一次,而是被调用两次。为什么? - 接下来打印“C”语句。在
views.py
文件中,conn
通过访问中间件类(使用用户名和密码)创建对象。在这个类中是__call__
方法,“D”语句所在的位置。我希望这个“D”首先被打印出来,然后是“C”。但这种情况并非如此。为什么先C后D? - 经过多次试验和错误后,我了解到开发中间件类需要
__init__
和方法。__call__
这些方法是否绝对必须包含在此中间件身份验证类中?到目前为止,我在阅读过的任何文档中都没有遇到过这个特定的说明,因此必须包含这两种方法。