zoukankan      html  css  js  c++  java
  • 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

    步骤四

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

  • 相关阅读:
    JSP(7)—EL和JSTL
    JSP(6)—JavaBean及案例
    JSP(5)—Session的创建以及简单使用
    JSP(4)—Cookie创建及简单案例(自动登录)
    JSP(3)—Cookie和Session
    JSP(2)—绝对路径与相对路径、配置Servlet与Servlet注解
    JSP(1)—基础知识
    Dockerfile RUN mkdir xxx 的时候报了Permission denied
    摘抄:Solr和ElasticSearch的区别
    POST请求反向代理设置
  • 原文地址:https://www.cnblogs.com/Evan-fanfan/p/12751934.html
Copyright © 2011-2022 走看看