欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Django开发文档-域用户集成登录

程序员文章站 2022-07-09 19:51:00
项目概述: 一般在企业中,用户以WINDOWS的域用户统一的管理,所以以Django快速开发的应用,不得不集成AD域登录。 网上一般采用django-python3-ldap的库来做集成登录,但是本方案中需要同时使用域用户登录以及站点用户登录的功能。所以我们直接改写django的ModelBacke ......

项目概述:

一般在企业中,用户以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已经成功了。

Django开发文档-域用户集成登录

 

 二、修改控制登录逻辑的modelbackend类

user类修改完成后,只需要将登录逻辑修改完成,那么我们的功能也就完成了

先来研究下django中modelbackend的源码

Django开发文档-域用户集成登录

 

 步骤一

我们在刚刚新建的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

步骤四

完成后请在用户维护界面勾选启用域用户登录Django开发文档-域用户集成登录,那么这个用户就可以用域用户进行认证了。