[原創]django+ldap實現統一認證部分一(django-auth-ldap實踐)

前言

接以前個人文章,django+ldap+memcache實現單點登陸+統一認證ldap部署相關,ldap雙機\LAM配置管理\ldap備份還原,目前來講,咱們已經有了高可用性的ldap環境了,裏邊也有了一些用戶信息,後邊要說一說經過django調用ldap的實現方式,裏邊主要涉及3個模塊,django-auth-ldap:用於從ldap同步帳戶、登陸驗證,它和ldap結合的很好,但它不能反向直接操做ldap,只能進行從ldap向下遊系統的同步,因此還須要python-ldap模塊,以便實現反向對ldap的增刪改查,我這邊的具體需求就是註冊用戶、重置密碼等,另外還須要一個python-memcached,用於把生成的session放到mc中
查了網上大量的關於django+ldap實現統一認證的文章,大部分都是隻寫了django-auth-ldap或者python-ldap來實現,可是若是要實現一套完整的統一認證系統,實際上這2個模塊都是須要的html

django-auth-ldap

這個模塊,基本在settings.py經過配置就能夠拿來用了,基本不須要對代碼作什麼修改。用於從ldap裏拿到信息傳給sso系統作後續處理,但經過它沒法讓sso系統反向操做ldap,不管django的前臺和admin都適用
官方文檔: https://pythonhosted.org/django-auth-ldap/authentication.html
中文翻譯: https://darkcooking.gitbooks.io/django-auth-ldap/content/chapter9.html
不過這個翻譯版是個簡化版本,有的東西不全,不過基本也夠用了,而且網站打開很慢,我把它的pdf放在這裏,能夠自行查看 http://files.cnblogs.com/files/caseast/django-auth-ldap.pdf
django官網(session部分):https://docs.djangoproject.com/en/1.10/topics/http/sessions/
ok!直接上代碼吧,具體的配置說明,不明確的還請參考官方文檔,裏邊我把log模塊和session這部分配置也寫一下順道,不單獨開篇描述了
---settings.py---python

SESSION_ENGINE = "django.contrib.sessions.backends.cache" # 另外還有個cached_db,這兩個的區別是,cache只寫緩存,cached_db除了寫緩存還同時寫數據庫,若是對於session的安全性要求高能夠選擇cached_db
SESSION_COOKIE_AGE = 86400  # 設置session有效期爲一天,默認兩週
SESSION_COOKIE_DOMAIN = ".ssotest.net"  # 此配置不能解決跨域問題,可是能解決a.ssotest.net與b.ssotest.net的session共享問題,不加此屬性,跨站(非跨域)時,沒法傳遞session
CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': [  # 鏈接的是2個mc,python-memcached自己有監活,掛一個mc會自動將請求分配到好的mc上
            'ldap1.prod.bj1.ssotest.net:11211',
            'ldap2.prod.bj1.ssotest.net:11211',
        ],
        'TIMEOUT': 30,
        'OPTIONS': {
            'MAX_ENTRIES': 3000
        }
    }
}

LOGIN_URL = "/account/login/"

# ### ldap 配置部分BEGIN ### #
import ldap
from django_auth_ldap.config import LDAPSearch, PosixGroupType

AUTHENTICATION_BACKENDS = (
    'django_auth_ldap.backend.LDAPBackend',  # 配置爲先使用LDAP認證,如經過認證則再也不使用後面的認證方式
    'django.contrib.auth.backends.ModelBackend', # sso系統中手動建立的用戶也可以使用,優先級靠後。注意這2行的順序
)

base_dn = 'dc=ldap,dc=ssotest,dc=net'
AUTH_LDAP_SERVER_URI = 'ldap://ldap.ssotest.net'
AUTH_LDAP_BIND_DN = 'uid=ssoadmin,ou=People,dc=ldap,dc=ssotest,dc=net'
AUTH_LDAP_BIND_PASSWORD = 'ssotest@123'
AUTH_LDAP_USER_SEARCH = LDAPSearch('ou=People,%s' % base_dn, ldap.SCOPE_SUBTREE, "(uid=%(user)s)") # 用戶的DN是uid=caojun,ou=People,dc=ldap,dc=ssotest,dc=net,因此用uid
AUTH_LDAP_ALWAYS_UPDATE_USER = True  # This is the default, but I like to be explicit.

AUTH_LDAP_USER_ATTR_MAP = {  # key爲數據庫字段名,value爲ldap中字段名,此字典解決django model與ldap字段名可能出現的不一致問題
    "username": "uid",
    "name": "cn",
    "email": "mail"
}

# 組權限管理 #
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") # 組的DN是cn=員工,ou=Group,dc=ldap,dc=ssotest,dc=net,因此type是cn
AUTH_LDAP_USER_FLAGS_BY_GROUP = { # django admin的is_staff|superuser屬性映射爲ldap的管理員
    "is_staff": u"cn=管理員,ou=Group,dc=ldap,dc=ssotest,dc=net",
    "is_superuser": u"cn=管理員,ou=Group,dc=ldap,dc=ssotest,dc=net"
}
AUTH_LDAP_REQUIRE_GROUP = u"cn=員工,ou=Group,dc=ldap,dc=ssotest,dc=net"  # 只有此group可用ldap進行認證
AUTH_LDAP_DENY_GROUP = u"cn=黑名單,ou=Group,dc=ldap,dc=ssotest,dc=net"  # 此group不能使用ldap進行認證,直接deny掉,不會後續往django建立信息
AUTH_LDAP_MIRROR_GROUPS = True  # 直接把ldap的組複製到django一份,和AUTH_LDAP_FIND_GROUP_PERMS互斥.用戶每次登陸會根據ldap來更新數據庫的組關係
# AUTH_LDAP_FIND_GROUP_PERMS = True  # django從ldap的組權限中獲取權限,這種方式,django自身不建立組,每次請求都調用ldap
# AUTH_LDAP_CACHE_GROUPS = True  # 如打開FIND_GROUP_PERMS後,此配置生效,對組關係進行緩存,不用每次請求都調用ldap
# AUTH_LDAP_GROUP_CACHE_TIMEOUT = 600  # 緩存時間
# ### ldap 配置部分END ### #

# ### log 配置部分BEGIN ### #
LDAP_LOGS = os.path.join(BASE_DIR, 'logs/ldap.log')
stamdard_format = '[%(asctime)s][%(threadName)s:%(thread)d]' + \
                  '[task_id:%(name)s][%(filename)s:%(lineno)d] ' + \
                  '[%(levelname)s]- %(message)s'
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'standard': {  # 詳細
            'format': stamdard_format
        },
    },
    'handlers': {
        'default': {
            'level': 'DEBUG',
            'class': 'logging.handlers.RotatingFileHandler',
            'filename': LDAP_LOGS,
            'maxBytes': 1024 * 1024 * 100,  # 5 MB
            'backupCount': 5,
            'formatter': 'standard',
        },
        'console': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',
        }
    },
    'loggers': {
        '': {  # default日誌,存放於log中
            'handlers': ['default'],
            'level': 'DEBUG',
        },
        'django_auth_ldap': {  # django_auth_ldap模塊相關日誌打印到console
            'handlers': ['console'],
            'level': 'DEBUG',
            'propagate': False,  # 選擇關閉繼承,否則這個logger繼承自默認,日誌就會被記錄2次了(''一次,本身一次)
        },
        # 'django.db.backends': {  # 數據庫相關執行過程log打印到console
        #     'handlers': ['console'],
        #     'level': 'DEBUG',
        # },
    }
}

# ### log 配置部分END ### #

logging模塊的說明,能夠參考這篇文章 http://www.jianshu.com/p/d615bf01e37b ,這個配置能夠配置到settings.py中,這樣django項目都會自動調用,或者單獨寫入一個log_config文件中,須要時手動調用,例子以下
log_config.pygit

import logging
from logging.config import dictConfig
logging_config={
........
}
dictConfig(logging_config)    #註冊一下配置

調用方法:數據庫

import logging
logger = logging.getLogger()
logger.error('ldap conn失敗,緣由爲: %s' % str(e))

額外說一點,以上配置是在sso系統進行,若是下游系統接入到sso系統的話,順序就是ldap--> sso --> 項目A,默認接入後,項目A的前臺帳戶就可使用ldap進行管理,但項目A若是使用了django admin的話(由於前臺的登陸動做會強制轉到sso上,而admin若是不改源碼作不到這點),django admin是會走本地的帳戶的,這樣就會出現,一個下游系統的管理員用戶,前臺一個密碼,後臺一個密碼,因此咱們須要給下游系統的settings.py作必定配置,讓下游的admin帳戶也從ldap中同步,下游一樣須要開篇說的3個python模塊
項目A的settings.pydjango

# ### ldap 配置部分BEGIN (If use Django-admin,configure it!) ### #
'''just for admin,前臺認證統一走認證平臺,因此下游系統不保存密碼,致使下游沒法登陸admin(如使用),因此admin添加ldap認證,只用ldap只讀帳戶便可'''
import ldap
from django_auth_ldap.config import LDAPSearch, PosixGroupType

AUTHENTICATION_BACKENDS = (
    'django_auth_ldap.backend.LDAPBackend',  # 配置爲先使用LDAP認證,如經過認證則再也不使用後面的認證方式
    'django.contrib.auth.backends.ModelBackend',  # 同時打開本地認證,由於下游系統的權限和組關係須要用到
)

base_dn = 'dc=ldap,dc=ssotest,dc=net'
AUTH_LDAP_SERVER_URI = 'ldap://ldap.ssotest.net'
AUTH_LDAP_BIND_DN = 'uid=ssoread,ou=People,dc=ldap,dc=ssotest,dc=net'  # read only ldap user
AUTH_LDAP_BIND_PASSWORD = 'ssotest@123'
AUTH_LDAP_USER_SEARCH = LDAPSearch('ou=People,%s' % base_dn, ldap.SCOPE_SUBTREE, "(uid=%(user)s)")
AUTH_LDAP_ALWAYS_UPDATE_USER = False  # 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 ### #

以上,咱們經過配置,就能夠完成django對於ldap的調用了,咱們能夠經過ldap來管理咱們的前臺和admin中的帳戶和密碼,可是這個動做是向下進行的,若是想經過咱們的單點登陸系統來操做ldap,這個django-auth-ldap是沒有這個功能的。這就須要後邊的python-ldap了.跨域

篇幅限制,python-ldap請參考個人這篇文章[原創]django+ldap實現統一認證部分二(python-ldap實踐)緩存

參考資料

https://pythonhosted.org/django-auth-ldap/authentication.html
https://darkcooking.gitbooks.io/django-auth-ldap/content/chapter9.html
https://docs.djangoproject.com/en/1.10/topics/http/sessions/
http://www.jianshu.com/p/d615bf01e37b安全

相關文章
相關標籤/搜索