Nachdem ich mich damals tot gesucht habe, um die Puzzleteile zusammen zu suchen, die ich für eine Authentifizierung bei meiner Django-Webanwendung mittels Windows Domainkennung realisieren wollte ist hier eine generische Version meiner Umsetzung.
Eine Windowsdomain-Authentifizierung kann relativ einfach über LDAP (= Lightweight Directory Access Protocol) realisiert werden.
Alternativ wäre noch Kerberos als eine weitere der 4 Hauptkomponenten des AD (= Active Directory) zu überlegen. Vor- & Nachteile sind individuell für jedes Projekt abzuwägen.
Hier das minimalistische How-To:
LDAP Python 64 Bit installieren “python –version“ checken
Download: http:// https://www.lfd.uci.edu/~gohlke/pythonlibs/#python-ldap
Navigieren in das Verzeichnis vom Download auf der Konsole (ggf. die env vorher öffnen) “\yourProject\\env\Scripts\activate.bat“
Dann im Verzeichnis ausführen:
pip install --only-binary :all: python_ldap-3.1.1-cp37-cp37m-win_amd64.whl
Test mit: “import ldap“
# views.py
from django.shortcuts import render, redirect
from django.contrib.auth.forms import AuthenticationForm
from my-project.WinDomainAuthBackend import WinDomainAuthBackend # todo !!
from django.contrib.auth import logout
from django.contrib.auth import login as auth_login
def login_view(request):
"""
User gets logged in.
"""
if not request.user.is_authenticated:
if request.method == 'POST':
# get user input from login-form
login_form = AuthenticationForm(data=request.POST)
username = login_form.data['username']
# change here
domain_name = "@my.awesome.company"
if domain_name not in username:
username+= domain_name
password = login_form.data['password']
# authenticate domain-user
authenticator = WinDomainAuthBackend(request)
user = authenticator.authenticate(username=username, password=password)
# login
if user:
user.backend = 'django.contrib.auth.backends.ModelBackend'
auth_login(request, user)
return redirect('index')
else:
messages.add_message(request, messages.ERROR, "Login failed. Try again.")
return redirect('login')
else:
# Django default form for login
login_form = AuthenticationForm()
return render(request, 'login.html', {"form": login_form})
else:
# if user already logged in --> redirect to index
return redirect("index")
def logout_view(request):
"""
User gets logged out.
"""
logout(request)
return redirect('index')
# WinDomainAuthBackend.py
from django.conf import settings
from django.contrib.auth.models import User
import ldap
from django.contrib import messages
class WinDomainAuthBackend(object):
"""
Authenticate user on company's win-domain server via LDAP.
"""
def __init__(self, request):
self.request = request
def authenticate(self, username=None, password=None):
"""
Mandatory authenticate method for backends.
https://docs.djangoproject.com/en/2.1/topics/auth/customizing/
"""
# establish LDAP connection
# change here
conn = ldap.initialize('LDAP://your-amazing-ldap-server')
conn.protocol_version = 3
conn.set_option(ldap.OPT_REFERRALS, 0)
user = None
try:
# try to authenticate
result = conn.simple_bind_s(username, password)
try:
# get current user
user = User.objects.get(username=username)
except User.DoesNotExist:
# create user
user = User(username=username, password=password)
user.save()
except ldap.INVALID_CREDENTIALS:
messages.add_message(self.request, messages.ERROR, "Invalid credentials.")
except ldap.SERVER_DOWN:
messages.add_message(self.request, messages.ERROR, "LDAP Server not available.")
except ldap.LDAPError as e:
messages.add_message(self.request, messages.ERROR, e.message)
finally:
# disconnect LDAP
conn.unbind_s()
return user
# login.html
<div class="content-container">
<div class="centered-content">
<h2>Login</h2>
</div>
<div class="login-container">
<form method="post" action="">
{% csrf_token %}
<!-- Create username, password login form -->
{{ form }}
<button class="btn btn-success" type="submit">Login</button>
</form>
</div>
</div>
# settings.py
INSTALLED_APPS = [
# [...]
# Add messages
'django.contrib.messages',
]
# Colorful messages to inform user
MESSAGE_TAGS = {
messages.DEBUG: 'alert-info',
messages.INFO: 'alert-info',
messages.SUCCESS: 'alert-success',
messages.WARNING: 'alert-warning',
messages.ERROR: 'alert-danger',
}
# For Windows Domain Authentification
AUTHENTICATION_BACKENDS = (
'path_to.backends.WinDomainAuthBackend',
'django.contrib.auth.backends.ModelBackend',)
MIDDLEWARE = [
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.messages.middleware.MessageMiddleware', # messages
'django.contrib.auth.middleware.AuthenticationMiddleware', # <------
]
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth', # <----
'django.contrib.messages.context_processors.messages', # <----
],
},
},
]
# base.html
<ul class="navbar-nav">
<!--- Greet only authenticated users -->
{% if request.user.is_authenticated %}
<li class="nav-item nav-link active">
Hello, {{ request.user.username }}!
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'logout' %}">Login</a>
</li>
{% else %}
<li class="nav-item">
<a class="nav-link" href="{% url 'login' %}">Logout</a>
</li>
{% endif %}
</ul>
# urls.py
urlpatterns = [
path('', views.index, name='index'),
# [...]
path('login', views.login_view, name='login'),
path('logout', views.logout_view, name='logout'),
]

6 Kommentare
Thanks! Great blog post!
Keep goin‘ girl!
Thanks!😊
Sehr cooles Beispiel, vielen Dank fürs teilen! Die Informatik braucht mehr tolle Frauen wie Dich 😀 Und ich hoffe, dass meine Tochter eines Tages sich auch für Nullen und Einsen begeistern kann! LG
Sehr gern! 😀
Das freut mich, Dankeschön! 🙂
Ich hab mich ebenfalls fast tot gesucht… Aber eben nur fast, weil ich dann gerade so rechtzeitig endlich diesen Post von dir gefunden habe 😀
Danke dir vielmals! 🙂
Sehr gern Hendrik! 😊😉