Django開發文檔-域用戶集成登錄


項目概述:

一般在企業中,用戶以WINDOWS的域用戶統一的管理,所以以Django快速開發的應用,不得不集成AD域登錄。

網上一般采用django-python3-ldap的庫來做集成登錄,但是本方案中需要同時使用域用戶登錄以及站點用戶登錄的功能。所以我們直接改寫django的ModelBackend類以及User類來實現。

實現功能

User表中增加一個 是否是域用戶的字段,如果登錄用戶是域用戶則采用ldap認證,如果不是域用戶還采用Django本身的驗證。

實現分析:

一、User表中如何增加字段

Django的auth_user表的字段是由django.contrib.auth.models中的User類控制的。

#Django源碼
class User(AbstractUser):
    """
    Users within the Django authentication system are represented by this
    model.

    Username and password are required. Other fields are optional.
    """
    class Meta(AbstractUser.Meta):
        swappable = 'AUTH_USER_MODEL'

我們需要對User類進行改寫來實現增加字段的功能

步驟一

首先我們需要新建一個my_user_auth的app

python manage.py startapp my_user_auth

步驟二

在my_user_auth的models文件中對User進行重新定義。里面增加了一個is_ad_account的字段用來標識是否是域用戶。

from django.contrib.auth.models import AbstractUser


class User(AbstractUser):
    """
    Users within the Django authentication system are represented by this
    model.
    Username and password are required. Other fields are optional.
    """
    is_ad_account=models.BooleanField('啟用域用戶登錄', default=False)
    cn_name = models.CharField(('中文名'), max_length=30, blank=True)
    en_name = models.CharField(('英文名'), max_length=150, blank=True)

    def full_name(self):  # 計算字段要顯示在修改頁面中只能定義在只讀字段中
        return self.cn_name+'#'+self.en_name

    class Meta(AbstractUser.Meta):
        swappable = 'AUTH_USER_MODEL'

步驟三

在admin中注冊自定義的User類

from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import User

class User_exAdmin(UserAdmin): 
    #查詢字段
    search_fields = ('username', 'first_name', 'last_name', 'email')
    #編輯顯示字段,我們在其中添加我們剛才創建的'cn_name', 'en_name', 'is_ad_account
    fieldsets = (
        (None, {'fields': ('username', 'password')}),
        (('Personal info'), {'fields': ('cn_name', 'en_name', 'email','is_ad_account')}),
        (('Permissions'), {
            'fields': ('is_active', 'is_staff', 'is_superuser', 'groups', 'user_permissions'),
        }),
        (('Important dates'), {'fields': ('last_login', 'date_joined')}),
    )
    add_fieldsets = (
        (None, {
            'classes': ('wide',),
            'fields': ('username', 'password1', 'password2'),
        }),
    )
    #顯示字段
    list_display = ('username', 'email', 'cn_name', 'en_name', 'is_staff')


admin.site.register(User, User_exAdmin)

步驟四

修改setting文件中

1、添加INSTALLED_APPS 

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
     #你自定義登錄的app名
     'my_user_auth',
]

2、添加AUTH_USER_MODEL,將系統的User類替換為你寫的User類。

AUTH_USER_MODEL = 'my_user_auth.User'

3、運行makemigrations、migrate。

但是首先要確保是你的Django項目還沒有運行任何的makemigrations、migrate。那會導致系統的錯誤。

4、完成后打開數據庫,可以看到my_user_auth_user的表數據表。那么恭喜你,自定義User已經成功了。

 

 二、修改控制登錄邏輯的ModelBackend類

User類修改完成后,只需要將登錄邏輯修改完成,那么我們的功能也就完成了

先來研究下Django中ModelBackend的源碼

 

 步驟一

我們在剛剛新建的app【my_user_auth】中創建一個【backends.py】

from django.contrib.auth.backends import ModelBackend
from django.contrib.auth.backends import UserModel
from my_user_auth.ad_auth import ldap_auth

class UserBackend(ModelBackend):
    def authenticate(self, request, username=None, password=None, **kwargs):
        if username is None:
            username = kwargs.get(UserModel.USERNAME_FIELD)
        if username is None or password is None:
            return
        try:
            user = UserModel._default_manager.get_by_natural_key(username)
        except UserModel.DoesNotExist:
            # Run the default password hasher once to reduce the timing
            # difference between an existing and a nonexistent user (#20760).
            UserModel().set_password(password)
        else:
            if user.is_ad_account:
                if ldap_auth(user.username,password) and self.user_can_authenticate(user):
                    print("域用戶登陸成功",user.username)
                    return user
            else: 
                if user.check_password(password) and self.user_can_authenticate(user):
                    print("網站賬號登陸成功",user.username)
                    return user     

步驟二

修改setting文件中AUTHENTICATION_BACKENDS將'django.contrib.auth.backends.ModelBackend'修改為'my_user_auth.backends.UserBackend'

AUTHENTICATION_BACKENDS = ['my_user_auth.backends.UserBackend']

步驟三

基於ldap3來ldap認證的代碼

from ldap3 import Server, Connection, ALL, SUBTREE, ServerPool
#域服務器IP,輔域就行了
LDAP_SERVER_POOL = ["192.168.3.2"]
#LDAP服務端口
LDAP_SERVER_PORT = 389

def ldap_auth(username, password):
    ldap_server_pool = ServerPool(LDAP_SERVER_POOL)
    #用戶以user@abc.net的形式錄入
    ad_user=f"""{username}@abc.net"""
    conn = Connection(ldap_server_pool, user=ad_user, password=password, check_names=True, lazy=False, raise_exceptions=False)
    
    conn.open()
    conn.bind()
    if conn.result["result"]==0:
        conn.unbind()
        return True
    else:
        conn.unbind()
        return False

步驟四

完成后請在用戶維護界面勾選啟用域用戶登錄,那么這個用戶就可以用域用戶進行認證了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM