如何在Django中实现两个不同的用户模型?

时间:2016-05-11 10:05:46

标签: python django authentication cas

我的Django应用程序有两种类型的用户,每种用户都有自己的身份验证机制:普通用户使用用户名和密码登录,员工使用django-cas-client通过公司的SSO服务器登录。< / p>

为此,我需要两个用户表:一个用于普通用户,一个用于员工。单个表不会删除它,因为用户名可能会重叠。也就是说,用户名对于普通用户来说是唯一的,对于员工来说是唯一的,但普通用户和员工可能具有相同的用户名。

类似问题,例如this onethis onethis one并不适用于我的情况,因为在我的情况下,不同的用户类型可以使用相同的用户名,同时仍然是不同的用户。不幸的是,我对CAS服务器返回的用户名没有任何影响。

这是我到目前为止所做的:

我创建了两个配置文件模型,而不是创建两个用户模型,通过OneToOneField链接到用户模型:

from django.conf import settings

class RegularUser(models.Model)
    user = models.OneToOneField(settings.AUTH_USER_MODEL, related_name='regular_user')
    nickname = models.CharField(max_length=255, blank=True)

class Employee(models.Model):
    user = models.OneToOneField(settings.AUTH_USER_MODEL, related_name='employee')
    first_name = models.CharField(max_length=255, blank=True)
    full_name = models.CharField(max_length=255, blank=True)
    NR = models.CharField(max_length=255, blank=True)
    email = models.CharField(max_length=255, blank=True)

然后我使用django-cas-client CAS Response Callback自动使用通过LDAP检索的employee_number填充新创建的CAS用户:

from django.contrib.auth import get_user_model
from .models import Employee

def callback(tree):
    username = tree[0][0].text
    user, created = get_user_model().objects.get_or_create(username=username)
    employee, created = Employee.objects.get_or_create(user=user)

    try:
        (
            employee.first_name,
            employee.full_name,
            employee.NR,
            employee.email
        ) = search_ldap(username)
        employee.save()

    except LDAPError:
        pass

对于那些感兴趣的人,这是search_ldap()函数的实现:

def search_ldap(username):
    result = ()
    baseDN = "o=Our Organization Name,c=NL"
    searchFilter = '(uid={})'.format(username)
    attributes = ['givenName', 'cn', 'employeeNumber', 'mail']

    try:
        server = Server('ldap.example.com', use_ssl=True)
        conn = Connection(server, auto_bind=True)
        conn.search(baseDN, searchFilter, attributes=attributes)
        for a in attributes:
            result += (conn.response[0]['attributes'][a][0], )
    except Exception:
        raise LDAPError('Error in LDAP query')

    return result

最终结果是只有通过CAS服务器登录的用户才拥有employee属性。我还没有自动创建常规用户,但当然只有他们才会拥有regular_user属性。要记录用户,我在urls.py中定义了两个单独的登录页面:

import cas.views
import django.contrib.auth.views
from django.conf.urls import include, url
from .views import login, logout

urlpatterns = [
    url(r'^login/regular/$', django.contrib.auth.views.login, name='login_regular'),
    url(r'^logout/regular/$', django.contrib.auth.views.logout, name='logout_regular'),
    url(r'^login/sso/$',cas.views.login, name='login_sso'),
    url(r'^logout/sso/$',cas.views.logout, name='logout_sso'),
    url(r'^login/$', login, name='login'),
    url(r'^logout/$', logout, name='logout'),
]

如您所见,还有一般的loginlogout网址。我已经实现了以下这些观点:

from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required

def login(request):
    param = request.META['QUERY_STRING']
    return render(request, 'login.html', {
        'param': param,
    })

@login_required
def logout(request):
    if hasattr(request.user, 'employee'):
        return redirect('logout_sso')
    else:
        return redirect('logout_regular')

常规登录模板只显示指向login_sso网址和login_regular网址的链接。 logout视图始终返回重定向到正确的注销网址。

此代码完美且按预期工作,有一个主要问题:有一天,CAS服务器可能会返回一个员工用户名,通过纯粹的coincedence,与现有的普通用户相同。 CAS响应回调将很乐意检索现有用户并启动employee个人资料。最终结果是此用户现在同时具有regular_user属性和employee属性。更糟糕的是,原始普通用户的帐户现在已被具有相同用户名的员工劫持。我想让普通用户和具有相同用户名的员工和平共处。我怎么能做到这一点?

0 个答案:

没有答案