Django登录并使用LDAP认证

近期在练手Django,前期网站前后端已经搭建得差不多了。

后面打算加入LDAP进行后台数据库登录授权,使用的Django的admin界面。

Django的admin界面还是很开发友好的,省区了很多数据库展示开发的工作,可以搜索“Django二次开发”发现更多的内容。

LDAP知识

LDAP是一个协议,而开源的LDAP和微软的Active Directory都是支持这个协议的。

一般我们Windows会使用AD做域控,LDAP的一些基础概念可以看下如下文章:

LDAP 中 CN, OU, DC 的含义_ba_jie的博客-CSDN博客_ldap ou

了解了这些可以帮助我们配置各大服务的LDAP部分。

一、安装LDAP相关库

虽然很快就能搜到Django LDAP方案代码,但是我发现我为了装ldap相关库,竟然踩了些坑。总结一下,给有需要的同学。

方案:django中ldap验证的三种方式,你需要哪种?_Tian, Yuting的博客-CSDN博客_django ldap

准备参考这篇文章的时候,发现我的django_auth_ldap没有装,需要安装django-auth-ldap,使用pycharm安装时,由于是源码安装,总是报C++的问题。

解决方法:使用whl安装。

下载whl:

Python Extension Packages for Windows - Christoph Gohlke (uci.edu)

1. 先安装pyldap或python_ldap, 我安装的版本是python_ldap-3.4.0-cp37-cp37m-win_amd64.whl,将whl下载并放到Scripts目录下,cd **/Scripts后用pip安装:

C:\Users\XXX\PycharmProjects\djangoProject\venv\Scripts> pip install python_ldap-3.4.0-cp37-cp37m-win_amd64.whl
Processing c:\users\XXX\pycharmprojects\djangoproject\venv\scripts\python_ldap-3.4.0-cp37-cp37m-win_amd64.whl
Requirement already satisfied: pyasn1>=0.3.7 in c:\users\XXX\pycharmprojects\djangoproject\venv\lib\site-packages (from python-ldap==3.4.0) (0.4.8)

Collecting pyasn1-modules>=0.1.5
  Using cached pyasn1_modules-0.2.8-py2.py3-none-any.whl (155 kB)
Installing collected packages: pyasn1-modules, python-ldap
Successfully installed pyasn1-modules-0.2.8 python-ldap-3.4.0

2. 安装:django-ahth-ldap

C:\Users\XXX\PycharmProjects\djangoProject\venv\Scripts> pip install django_auth_ldap-4.1.0-py30-none-any.whl

该安装包地址:https://www.wheelodex.org/projects/django-auth-ldap/wheels/django_auth_ldap-4.1.0-py3-none-any.whl/

下载地址:https://files.pythonhosted.org/packages/d1/34/e519840e68108c452d9ed559fb0ac091dcddf70db860c0d1c808d78c46fc/django_auth_ldap-4.1.0-py3-none-any.whl 

注意我们下载下来的名称要改成本地python兼容tag名称:

输入:pip debug --verbose 查看兼容名称

参考文章:python 安装whl文件_ Marks的博客-CSDN博客_python手动安装whl

C:\Program Files\Python37\Scripts>pip debug --verbose
WARNING: This command is only meant for debugging. Do not use this with automation for parsing and getting these details, since the output and options of this command may change without notice.
pip version: pip 20.1.1 from c:\program files\python37\lib\site-packages\pip (python 3.7)
sys.version: 3.7.9 (tags/v3.7.9:13c94747c7, Aug 17 2020, 18:58:18) [MSC v.1900 64 bit (AMD64)]
sys.executable: c:\program files\python37\python.exe
sys.getdefaultencoding: utf-8
sys.getfilesystemencoding: utf-8
locale.getpreferredencoding: cp936
sys.platform: win32
sys.implementation:
  name: cpython
'cert' config value: Not specified
REQUESTS_CA_BUNDLE: None
CURL_CA_BUNDLE: None
pip._vendor.certifi.where(): c:\program files\python37\lib\site-packages\pip\_vendor\certifi\cacert.pem
pip._vendor.DEBUNDLED: False
vendored library versions:
  appdirs==1.4.3
  CacheControl==0.12.6
  colorama==0.4.3
  contextlib2==0.6.0.post1 (Unable to locate actual module version, using vendor.txt specified version)
  distlib==0.3.0
  distro==1.5.0 (Unable to locate actual module version, using vendor.txt specified version)
  html5lib==1.0.1
  ipaddress==1.0.23
  msgpack==1.0.0 (Unable to locate actual module version, using vendor.txt specified version)
  packaging==20.3
  pep517==0.8.2
  progress==1.5
  pyparsing==2.4.7
  requests==2.23.0
  certifi==2020.04.05.1
  chardet==3.0.4
  idna==2.9
  urllib3==1.25.8
  resolvelib==0.3.0
  retrying==1.3.3 (Unable to locate actual module version, using vendor.txt specified version)
  setuptools==44.0.0 (Unable to locate actual module version, using vendor.txt specified version)
  six==1.14.0
  toml==0.10.0
  webencodings==0.5.1 (Unable to locate actual module version, using vendor.txt specified version)
Compatible tags: 27
  cp37-cp37m-win_amd64
  cp37-abi3-win_amd64
  cp37-none-win_amd64
  cp36-abi3-win_amd64
  cp35-abi3-win_amd64
  cp34-abi3-win_amd64
  cp33-abi3-win_amd64
  cp32-abi3-win_amd64
  py37-none-win_amd64
  py3-none-win_amd64
  py36-none-win_amd64
  py35-none-win_amd64
  py34-none-win_amd64
  py33-none-win_amd64
  py32-none-win_amd64
  py31-none-win_amd64
  py30-none-win_amd64
  cp37-none-any
  py37-none-any
  py3-none-any
  py36-none-any
  py35-none-any
  py34-none-any
  py33-none-any
  py32-none-any
  py31-none-any
  py30-none-any

这样django-auth-ldap就安装好啦。

Linux上安装很简单:

  • 安装依赖库:

    sudo yum install python-devel

    sudo yum install openldap-devel

安装django-auth-ldap

    pip install django-auth-ldap

 二、LDAP授权功能调试

修改settings.py文件:

笔者参考的这篇文档:Django-auth-ldap 配置方法 - 云+社区 - 腾讯云

注意要加入一个超级用户的用户名和密码,参考文档:Authentication — django-auth-ldap 4.0.1.dev12+g6dfdec9.d20220510 documentation
​​​​​​​AUTH_LDAP_BIND_DN = ""
AUTH_LDAP_BIND_PASSWORD = ""

以下是我测试可用的代码:

#Django-auth-ldap 配置部分

import ldap
from django_auth_ldap.config import LDAPSearch, GroupOfNamesType
#修改Django认证先走ldap,再走本地认证

AUTHENTICATION_BACKENDS = [
   'django_auth_ldap.backend.LDAPBackend',
   'django.contrib.auth.backends.ModelBackend',
]
#ldap的连接基础配置
AUTH_LDAP_SERVER_URI = "ldap://****:389" 
AUTH_LDAP_BIND_DN = "***"
AUTH_LDAP_BIND_PASSWORD = "*****"
AUTH_LDAP_USER_SEARCH = LDAPSearch("OU=group1,DC=company,DC=com",
                                  ldap.SCOPE_SUBTREE, "(sAMAccountName=%(user)s)")
#通过组进行权限控制
AUTH_LDAP_GROUP_SEARCH = LDAPSearch("OU=group2,OU=group1,DC=company,DC=com",
   ldap.SCOPE_SUBTREE, "(objectClass=groupOfNames)")
AUTH_LDAP_GROUP_TYPE = GroupOfNamesType()
#is_staff:这个组里的成员可以登录;is_superuser:组成员是django admin的超级管理员;is_active:组成员可以登录django admin后台,但是无权限查看后台内容
AUTH_LDAP_USER_FLAGS_BY_GROUP = {
    "is_staff": "CN=group_account,OU=group2,OU=group1,DC=company,DC=com",
    "is_superuser": "CN=group_account,OU=group2,OU=group1,DC=company,DC=com",
}#通过组进行权限控制end

#如果ldap服务器是Windows的AD,需要配置上如下选项

AUTH_LDAP_CONNECTION_OPTIONS = {
   ldap.OPT_DEBUG_LEVEL: 1,
   ldap.OPT_REFERRALS: 0,
}
#当ldap用户登录时,从ldap的用户属性对应写到django的user数据库,键为django的属性,值为ldap用户的属性

AUTH_LDAP_USER_ATTR_MAP = {
                            "first_name": "givenName",
                            "last_name": "sn",
                            "email": "mail"}

完成以上修改后,http://localhost/admin  界面就可以通过LDAP授权登录了。

凡是在LDAP群组里的用户均可登录该界面。但是我想要的是前端自己开发的界面也通过LDAP授权。

 三、登录界面开发

Django开发有很多隐藏功能,但是好处是资料很多,在网上搜集了一番后,得出自己的前端开发程序。

首先,找一个好看的html页面,我用的是AdminLTE-2.3.0的模板。

html页面中的form如下:

  <body class="hold-transition login-page">
    <div class="login-box">
      <div class="login-logo">
        <a href="../../index.html">Name</a>
      </div><!-- /.login-logo -->
      <div class="login-box-body">
        <p class="login-box-msg">Sign in to start your session</p>
        <form action="/login" method="post">
          {% if message %}
            <div class="alert alert-warning">{{ message }}</div>
          {% endif %}
          {% csrf_token %}
          <div class="form-group has-feedback">
            <input type="text" name="username" class="form-control" placeholder="username">
            <span class="glyphicon glyphicon-envelope form-control-feedback"></span>
          </div>
          <div class="form-group has-feedback">
            <input type="password" name="password" class="form-control" placeholder="password">
            <span class="glyphicon glyphicon-lock form-control-feedback"></span>
          </div>
          <div class="row">
            <div class="col-xs-8">
              <div class="checkbox icheck">
                <label>
                  <input type="checkbox"> Remember Me
                </label>
              </div>
            </div><!-- /.col -->
            <div style="display: none;">
              <input id="next" type="text" name="next_url" value="{{ next_url }}" />
            </div>
            <div class="col-xs-4">
              <button type="submit" class="btn btn-primary btn-block btn-flat">Sign In</button>
            </div><!-- /.col -->
          </div>
        </form>

        <a href="change_password">change password</a><br>
        <a href="register" class="text-center">Register a new membership</a>

      </div><!-- /.login-box-body -->
    </div><!-- /.login-box -->

配合的还需要修改 app中的urls.py和views.py

urls.py:

urlpatterns = [
    path('', views.index, name='index'),
    path('index.html', views.index, name='index'),
    path('login', views.login_view, name='login'),

]

views.py

def login_view(request):
    """entry function of login page"""
    if request.method == "POST":
        username = request.POST.get('username')
        password = request.POST.get('password')
        next_url = request.POST.get("next_url")
        message = '请检查填写的内容!'
        if username.strip() and password:
            if authenticate(username=username, password=password):
                user = authenticate(username=username, password=password)
                if next_url and next_url != "logout":
                    response = redirect(next_url)
                    login(request, user)
                else:
                    # response = redirect("index.html")
                    login(request, user)
                    response = redirect("index.html")
                # return redirect('index.html')
                return response
            else:
                message = '用户名或密码不正确!'
                return render(request, 'dashboard/pages/login/login.html', {'message': message})
        else:
            return render(request, 'dashboard/pages/login/login.html', {'message': message})

    next_url = request.GET.get("next", '')

    return render(request, 'dashboard/pages/login/login.html', {'next_url': next_url})

这样通过authenticate(username=username, password=password),我们自己的登录界面走的就是LDAP验证了。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值