在一个公司内部的局域网上,存在着各种不需要显式登录的 Web 应用程序。用户只需要登录 Windows 即可完成身份验证。用户希望了解这种身份验证是如何实现的,以及如何在 Python 和 Django 中使用 Windows 登录信息对用户进行身份验证。该过程需要考虑安全性和实现方式的限制,例如浏览器要求、应用程序和公司内部网后端的位置等。
2、解决方案
方法一:NTLM 身份验证
在早期,Internet Explorer 支持 NTLM 身份验证。这种方式类似于基本身份验证,但它会将缓存的凭据发送到服务器,服务器可以利用域控制器进行验证。如果不需要关心太多安全性,并且不需要符合现代浏览器标准,可以使用这种方式实现单点登录。但需要注意的是,NTLM 身份验证存在安全漏洞,不适合用于公开的互联网环境。
方法二:Active Directory 后端
对于现代的 Python 和 Django 应用来说,可以使用 Active Directory 后端来实现 Windows 凭据的身份验证。这里提供了一个代码示例:
# settings.py
AD_DNS_NAME = 'example.com'
AD_LDAP_PORT = 389
AD_SEARCH_DN = 'CN=Users,dc=example,dc=com'
AD_NT4_DOMAIN = 'EXAMPLE'
AD_SEARCH_FIELDS = ['mail','givenName','sn','sAMAccountName']
AD_LDAP_URL = 'ldap://%s:%s' % (AD_DNS_NAME,AD_LDAP_PORT)
# auth.py
from django.contrib.auth.models import User
from django.conf import settings
import ldap
class ActiveDirectoryBackend:
def authenticate(self,username=None,password=None):
if not self.is_valid(username,password):
return None
try:
user = User.objects.get(username=username)
except User.DoesNotExist:
l = ldap.initialize(settings.AD_LDAP_URL)
l.simple_bind_s(username,password)
result = l.search_ext_s(settings.AD_SEARCH_DN,ldap.SCOPE_SUBTREE,
"sAMAccountName=%s" % username,settings.AD_SEARCH_FIELDS)[0][1]
l.unbind_s()
# givenName == First Name
if result.has_key('givenName'):
first_name = result['givenName'][0]
else:
first_name = None
# sn == Last Name (Surname)
if result.has_key('sn'):
last_name = result['sn'][0]
else:
last_name = None
# mail == Email Address
if result.has_key('mail'):
email = result['mail'][0]
else:
email = None
user = User(username=username,first_name=first_name,last_name=last_name,email=email)
user.is_staff = False
user.is_superuser = False
user.set_password(password)
user.save()
return user
def get_user(self,user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
def is_valid (self,username=None,password=None):
## Disallowing null or blank string as password
## as per comment: http://www.djangosnippets.org/snippets/501/#c868
if password == None or password == '':
return False
binddn = "%s@%s" % (username,settings.AD_NT4_DOMAIN)
try:
l = ldap.initialize(settings.AD_LDAP_URL)
l.simple_bind_s(binddn,password)
l.unbind_s()
return True
except ldap.LDAPError:
return False
这种方式需要在 Django 项目中配置 Active Directory 后端,并且需要确保 Active Directory 服务在公司内部网中正常运行。
值得注意的是,无论使用哪种方法,都需要考虑安全性和实现方式的限制。例如,对于方法一,需要确保网络连接是安全的,并且需要在 Intranet 中使用。对于方法二,需要确保 Active Directory 服务的安全性,并且需要确保应用程序和公司内部网后端之间的通信是安全的。