07: Django 使用ldap登錄、注銷等


目錄:Django其他篇

01:Django基礎篇

02:Django進階篇

03:Django數據庫操作--->Model

04: Form 驗證用戶數據 & 生成html

05:ModelForm 數據驗證 & 生成html & 數據庫操作

06: Django Admin

07: Django 學習補充

1.1 配置ldap認證

   參考博客:https://www.cnblogs.com/dreamer-fish/p/5474289.html

  官網地址https://pypi.org/project/django-auth-ldap/1.3.0/

  1、django使用ldap認證需要安裝下面兩個模塊(這里是在linux下測試的)

      1.安裝Python-LDAP(python_ldap-2.4.25-cp27-none-win_amd64.whl)pip install python_ldap-2.4.25-cp27-none-win_amd64.whl

      2.安裝django-auth-ldap(django-auth-ldap-1.2.8.tar.gz)(下載:https://pypi.python.org/pypi/django-auth-ldap),Windows下也可以使用 python setup.py install

      3. 安裝成功后運行命令,運行成功表示安裝成功: from django_auth_ldap.config import LDAPSearch, LDAPSearchUnion, GroupOfNamesType 

  2、LDAP用戶驗證基本原理

      1. 每個用戶在LDAP系統中有一個唯一的DN值,例如配置文件中默認的admin用戶在LDAP中的DN值是uid=admin,ou=system,dc=eoncloud,dc=com,

      2. 其中eoncloud.com是域名,system是組名,admin是用戶名,有些LDAP用cn而不是uid來生成DN

      3. 在這種系統中admin的DN看起來像這樣cn=admin,ou=system,dc=eoncloud,dc=com,無論是uid還是cn或是別的前綴,django-ldap-auth都是用dn來驗證用戶和獲取用戶信息的

      4. 假設用戶輸入的帳號及密碼是: test, password,django-auth-ldap有2個方式來獲取用戶的DN

        1)使用AUTH_LDAP_USER_DN_TEMPLATE提供的模板生成DN.如uid=%(user)s,ou=users,dc=eoncloud,dc=com,
             其中%(user)s會被替換成用戶名,這樣最終的DN就是  uid=test,ou=users,dc=eonclooud,dc=com.

        2)使用AUTH_LDAP_GROUP_SEARCH.如果沒有配置AUTH_LDAP_USER_DN_TEMPLATE,那么django-auth-ldap會使用
          AUTH_LDAP_BIND_DN和AUTH_LDAP_BIND_PASSWORD提供的dn與密碼根據AUTH_LDAP_GROUP_SEARCH提供的查詢條件去查找test用戶,
          如果查不到,驗證失敗,如果查到用戶,就使用返回的數據生成test的DN. 

        利用第2步生成DN值與密碼嘗試訪問LDAP系統,如果訪問成功,則驗證共過,否則驗證失敗.

   3、基本配置使用

# -*- coding:utf8 -*-
import ldap
from django_auth_ldap.config import LDAPSearch, PosixGroupType

AUTHENTICATION_BACKENDS = (
    'django_auth_ldap.backend.LDAPBackend',         # 配置為先使用LDAP認證,如通過認證則不再使用后面的認證方式
    'django.contrib.auth.backends.ModelBackend',    # 同時打開本地認證,因為下游系統的權限和組關系需要用到
)

#默認登錄后打開首頁
LOGIN_REDIRECT_URL = '/'
SESSION_EXPIRE_AT_BROWSER_CLOSE = False  # 關閉流量器不清空session
SESSION_COOKIE_AGE = 60*60*8  # 8小時后session認證過期

base_dn = 'dc=cloud,dc=cn'  # 請求的域名后綴為:cloud.cn
AUTH_LDAP_SERVER_URI = 'ldap://ldap-qc.intra.cloud.cn'    #  LDAP系統的地址及端口號
AUTH_LDAP_BIND_DN = 'cn=cloud,ou=admin,dc=ycloud,dc=cn'  #  以admin身份查找用戶及相關信息
AUTH_LDAP_BIND_PASSWORD = 'xxxxx'    # admin賬號的密碼
AUTH_LDAP_USER_SEARCH = LDAPSearch('ou=People,%s' % base_dn, ldap.SCOPE_SUBTREE, "(uid=%(user)s)")
# 第一個參數指定查詢目錄,第三個參數是過濾條件,過濾條件可以很復雜,有需要請查看相關文檔.
AUTH_LDAP_ALWAYS_UPDATE_USER = True
# Default is True,是否登錄后從ldap同步用戶,不進行同步,因為下游的用戶表是什么樣的不能確定,只能確定它也使用郵箱前綴


'''一些其他配置'''
# 下游系統不從ldap同步group staff/superuser相關,但需要從ldap驗證用戶是否離職
# AUTH_LDAP_GROUP_SEARCH = LDAPSearch('ou=Group,dc=ldap,dc=ssotest,dc=net', ldap.SCOPE_SUBTREE, "(objectClass=posixGroup)")
# AUTH_LDAP_GROUP_TYPE = PosixGroupType(name_attr="cn")
# AUTH_LDAP_REQUIRE_GROUP = u"cn=員工,ou=Group,dc=ldap,dc=ssotest,dc=net"
# AUTH_LDAP_DENY_GROUP = u"cn=黑名單,ou=Group,dc=ldap,dc=ssotest,dc=net"
# AUTH_LDAP_FIND_GROUP_PERMS = True  # django從ldap的組權限中獲取權限,這種方式,django自身不創建組,每次請求都調用ldap,下游子系統,我們並不需要讓他同步ldap里的"員工","管理員"這種表,所以不用mirror_groups
# AUTH_LDAP_CACHE_GROUPS = True  # 如打開FIND_GROUP_PERMS后,才生效,對組關系進行緩存,不用每次請求都調用ldap
# AUTH_LDAP_GROUP_CACHE_TIMEOUT = 600
# ### ldap 配置部分END ### #
settings.py中配置ldap
from django.conf.urls import url
from django.contrib import admin
from app01 import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^login/', views.Login.as_view()),
    url(r'^home/', views.home, name='home'),
app01/urls.py
<!DOCTYPE html>
<html>
<head>
    <meta charset=utf-8">
    <title>登錄</title>
    <link rel="stylesheet" href="/static/AdminLTE/bootstrap/css/bootstrap.css">
    <link rel="stylesheet" href="/static/AdminLTE/fonts/font-awesome.min.css">
    <link rel="stylesheet" href="/static/AdminLTE/ionicons/ionicons.css">
    <link rel="stylesheet" href="/static/AdminLTE/dist/css/AdminLTE.css">
    <style>
        .errorlist {
            color: red;
        }
    </style>
</head>

<body class="hold-transition login-page">
<div class="login-box">
    <div class="login-logo">
        <b>運維工單·平台</b>
    </div>
    <div class="login-box-body">
        {% if form.errors %}
            <p class="errorlist">你輸入的用戶名密碼不正確!!</p>
        {% endif %}
        <form action="" method="POST">{% csrf_token %}
            <div class="form-group has-feedback">
                <input type="text" class="form-control" name="username" placeholder="用戶名" required>
                <span class="glyphicon glyphicon-user form-control-feedback"></span>
            </div>
            <div class="form-group has-feedback">
                <input type="password" class="form-control" name="password" placeholder="密碼" required>
                <span class="glyphicon glyphicon-lock form-control-feedback"></span>
            </div>
                    <button class="btn btn-primary btn-block btn-flat" type="submit">登陸</button>
        </form>
        <br>

    </div>
</div>
</body>
</html>
login.html

 1.2 在django項目中使用

# -*- coding:utf8 -*-
import ldap
from django_auth_ldap.config import LDAPSearch, PosixGroupType

AUTHENTICATION_BACKENDS = (
    'django_auth_ldap.backend.LDAPBackend',         # 配置為先使用LDAP認證,如通過認證則不再使用后面的認證方式
    'django.contrib.auth.backends.ModelBackend',    # 同時打開本地認證,因為下游系統的權限和組關系需要用到
)

#默認登錄后打開首頁
LOGIN_REDIRECT_URL = '/'
SESSION_EXPIRE_AT_BROWSER_CLOSE = False  # 關閉流量器不清空session
SESSION_COOKIE_AGE = 60*60*8  # 8小時后session認證過期

base_dn = 'dc=cloud,dc=cn'  # 請求的域名后綴為:cloud.cn
AUTH_LDAP_SERVER_URI = 'ldap://ldap-qc.intra.cloud.cn'    #  LDAP系統的地址及端口號
AUTH_LDAP_BIND_DN = 'cn=cloud,ou=admin,dc=cloud,dc=cn'  #  以admin身份查找用戶及相關信息
AUTH_LDAP_BIND_PASSWORD = 'xxxxx'    # admin賬號的密碼
AUTH_LDAP_USER_SEARCH = LDAPSearch('ou=People,%s' % base_dn, ldap.SCOPE_SUBTREE, "(uid=%(user)s)")
# 第一個參數指定查詢目錄,第三個參數是過濾條件,過濾條件可以很復雜,有需要請查看相關文檔.
AUTH_LDAP_ALWAYS_UPDATE_USER = True
# Default is True,是否登錄后從ldap同步用戶,不進行同步,因為下游的用戶表是什么樣的不能確定,只能確定它也使用郵箱前綴


'''一些其他配置'''
# 下游系統不從ldap同步group staff/superuser相關,但需要從ldap驗證用戶是否離職
# AUTH_LDAP_GROUP_SEARCH = LDAPSearch('ou=Group,dc=ldap,dc=ssotest,dc=net', ldap.SCOPE_SUBTREE, "(objectClass=posixGroup)")
# AUTH_LDAP_GROUP_TYPE = PosixGroupType(name_attr="cn")
# AUTH_LDAP_REQUIRE_GROUP = u"cn=員工,ou=Group,dc=ldap,dc=ssotest,dc=net"
# AUTH_LDAP_DENY_GROUP = u"cn=黑名單,ou=Group,dc=ldap,dc=ssotest,dc=net"
# AUTH_LDAP_FIND_GROUP_PERMS = True  # django從ldap的組權限中獲取權限,這種方式,django自身不創建組,每次請求都調用ldap,下游子系統,我們並不需要讓他同步ldap里的"員工","管理員"這種表,所以不用mirror_groups
# AUTH_LDAP_CACHE_GROUPS = True  # 如打開FIND_GROUP_PERMS后,才生效,對組關系進行緩存,不用每次請求都調用ldap
# AUTH_LDAP_GROUP_CACHE_TIMEOUT = 600
# ### ldap 配置部分END ### #
settings.py中配置ldap
from django.conf.urls import url
from django.contrib import admin
from app01 import views
from django.contrib.auth.views import login, logout

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^login/', views.Login.as_view()),
    url(r'^home/', views.home, name='home'),
    url(r'^$',views.index),
    url(r'^ac_logout/?$', views.logout_view, name="account_logout"),
    url(r'^change_passwd/?$', views.change_pass, name="change_passwd"),
]
urls.py
# # -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.shortcuts import render,HttpResponse,redirect
from django.contrib.auth.views import LoginView
from django.contrib.auth import login as auth_login
from django.contrib.auth.decorators import login_required
from django.contrib.auth import logout
from django.contrib.auth.forms import PasswordChangeForm

#1、登錄:優先使用ldap認證,settings中配置了
class Login(LoginView):
    template_name = 'login.html'
    def form_valid(self, form):
        auth_login(self.request, form.get_user())
        return super(Login, self).form_valid(form)

    def get_context_data(self, **kwargs):
        context = super(Login,self).get_context_data(**kwargs)
        return context

#2、注銷
def logout_view(request):
    logout(request)
    return redirect('/login')

#3、修改密碼:可以修改本地密碼,不是修改ldap密碼
@login_required(login_url='/login')
def change_pass(request):
    form = PasswordChangeForm(user=request.user)
    if request.method == 'POST':
        form = PasswordChangeForm(request.user, request.POST)
        if form.is_valid():
            form.save()
            return redirect('/')
    return render(request, template_name='change_pass.html', context={'form': form, 'username': request.user.username})

#4、index首頁:登陸后默認返回此頁面
@login_required(login_url='/login')
def index(request):
    return render(request, 'index.html')

#5、home頁面:只有登錄才返回,否則返回到login頁面
@login_required(login_url='/login')
def home(request):
    return HttpResponse('home')
app01/views.py
<!DOCTYPE html>
<html>
<head>
    <meta charset=utf-8">
    <title>登錄</title>
    <link rel="stylesheet" href="/static/AdminLTE/bootstrap/css/bootstrap.css">
    <link rel="stylesheet" href="/static/AdminLTE/fonts/font-awesome.min.css">
    <link rel="stylesheet" href="/static/AdminLTE/ionicons/ionicons.css">
    <link rel="stylesheet" href="/static/AdminLTE/dist/css/AdminLTE.css">
    <style>
        .errorlist {
            color: red;
        }
    </style>
</head>

<body class="hold-transition login-page">
<div class="login-box">
    <div class="login-logo">
        <b>運維工單·平台</b>
    </div>
    <div class="login-box-body">
        {% if form.errors %}
            <p class="errorlist">你輸入的用戶名密碼不正確!!</p>
        {% endif %}
        <form action="" method="POST">{% csrf_token %}
            <div class="form-group has-feedback">
                <input type="text" class="form-control" name="username" placeholder="用戶名" required>
                <span class="glyphicon glyphicon-user form-control-feedback"></span>
            </div>
            <div class="form-group has-feedback">
                <input type="password" class="form-control" name="password" placeholder="密碼" required>
                <span class="glyphicon glyphicon-lock form-control-feedback"></span>
            </div>
                    <button class="btn btn-primary btn-block btn-flat" type="submit">登陸</button>
        </form>
        <br>

    </div>
</div>
</body>
</html>
login.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="x-ua-compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Title</title>
</head>
<body>
    <h1>index</h1>
    <p><a href="{% url 'account_logout' %}">注銷</a></p>
    <p><a href="{% url 'home' %}">home頁面</a></p>
    <p><a href="{% url 'change_passwd' %}">修改密碼</a></p>

    <div>
        <h2>展示用戶額外信息</h2>
        <p>{{ request.user }}</p>
        <p>{{ request.user.userprofile.zhname }}</p>
    </div>
</body>
</html>
index.html
<h1>更改密碼</h1>

{% block main_content %}
    <div class="col-md-6">
        <div class="box box-info">
            <div class="box-header with-border">
                <h3 class="box-title">{{ request.user.username }}修改密碼</h3>
            </div>

            <form class="form-horizontal" action="" method="post">
                 {% csrf_token %}
                <div class="box-body">
                    <div class="form-group">
                        <label for="id_old_password" class="col-sm-3 control-label">舊密碼:</label>

                        <div class="col-sm-9">
                            {{ form.old_password.errors }}
                            {{ form.old_password }}
                        </div>
                    </div>
                    <div class="form-group">
                        <label for="id_new_password1" class="col-sm-3 control-label">新密碼:</label>

                        <div class="col-sm-9">
                            {{ form.new_password1.errors }}
                            {{ form.new_password1 }}
                        </div>
                    </div>
                    <div class="form-group">
                        <label for="id_new_password2" class="col-sm-3 control-label">新密碼確認:</label>

                        <div class="col-sm-9">
                            {{ form.new_password2.errors }}
                            {{ form.new_password2 }}
                        </div>
                    </div>

                </div>
                <!-- /.box-body -->
                <div class="box-footer">
                    <button type="submit" class="btn btn-default">提交</button>
                    <button type="reset" class="btn btn-info pull-right">重置</button>
                </div>
                <!-- /.box-footer -->
            </form>
        </div>
    </div>
{% endblock %}
change_pass.html
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models
from django.contrib.auth.models import User

class UserProfile(models.Model):
    user = models.OneToOneField(User,verbose_name='用戶名')
    zhname = models.CharField(max_length=50,verbose_name='姓名',blank=True,null=True)
app01/models.py 中使用UserProfile表為User表添加額外信息

   1、頁面效果

     

  2、說明

      1. 我們只需要在settings中配置使用ldap認證后,django就可以利用ldap進行認證了

      2、然后我們利用django內置模塊 LoginView 定義登錄界面視圖函數 Login(LoginView) 來驗證ldap身份

      3、需要身份認證的視圖函數僅需使用django的 login_required 模塊進行裝飾即可:@login_required(login_url='/login')

 


免責聲明!

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



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