首页 > 解决方案 > 维护用户会话而不将用户保存在 django 身份验证系统中

问题描述

我有一个小型 Django 应用程序,其中用户需要通过安装在 Apache 上的 Webgate 插件进行外部身份验证。Webgate 将使用托管在 Intranet 上的其他企业身份验证系统来对进入我的 django 站点的用户进行身份验证。一旦企业身份验证系统对用户进行身份验证,它将使用标头 REMOTE-USER 将他们重定向到我们的站点。此标头将包含用户名。我只需要确保该标头中提到的用户能够访问该站点,即使它在我的站点上不存在,相信他已经通过身份验证。为此,我正在使用

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'django.contrib.auth.middleware.RemoteUserMiddleware',
]
AUTHENTICATION_BACKENDS = (
    'django.contrib.auth.backends.RemoteUserBackend',
)

这行得通。但它会在网站中创建用户。要求是用户不得存在于我们的数据库中。它们可以存在于内存中。他们需要有一个会话 这在 Django 中是否可行?如果是的话,我怎么能做到这一点?我尝试将 AllowAllUsersRemoteUserBackend 子类化如下,并覆盖身份验证方法以返回仅在内存中而不是在数据库中的用户。

class AllowAllUsersRemoteUserBackendWithoutCreatingUnknownUsers(AllowAllUsersRemoteUserBackend):

    create_unknown_user = False

    def authenticate(self, request, remote_user):
        return User(username = remote_user)

AUTHENTICATION_BACKENDS = (
    'polls.middleware.authentication.AllowAllUsersRemoteUserBackendWithoutCreatingUnknownUsers',
)

但是有了这个我得到了一个例外

ValueError at /polls/
Cannot force an update in save() with no primary key.
Request Method: GET
Request URL:    http://localhost:8001/polls/
Django Version: 2.1.7
Exception Type: ValueError
Exception Value:    
Cannot force an update in save() with no primary key.
Exception Location: C:\Users\rizwan_shaikh\Envs\sessiontest\lib\site-packages\django\db\models\base.py in _save_table, line 803
Python Executable:  C:\Users\rizwan_shaikh\Envs\sessiontest\Scripts\python.exe
Python Version: 3.8.1
Python Path:    
['C:\\ApplicationCode\\Kenstar\\sessiontest\\djangosessiontestwithwsgi',
 'C:\\Users\\rizwan_shaikh\\Envs\\sessiontest\\Scripts\\python38.zip',
 'C:\\Users\\rizwan_shaikh\\Envs\\sessiontest\\DLLs',
 'C:\\Users\\rizwan_shaikh\\Envs\\sessiontest\\lib',
 'C:\\Users\\rizwan_shaikh\\Envs\\sessiontest\\Scripts',
 'c:\\softwares\\pythoninstallation\\Lib',
 'c:\\softwares\\pythoninstallation\\DLLs',
 'C:\\Users\\rizwan_shaikh\\Envs\\sessiontest',
 'C:\\Users\\rizwan_shaikh\\Envs\\sessiontest\\lib\\site-packages',
 '/app',
 '/usr/local/lib/python3.7/site-packages']
Server time:    Thu, 30 Jan 2020 08:37:34 +0000

现在我没有在 apache 上运行我的代码,而是在 django 开发服务器上运行。我正在通过另一个中间件手动添加包含用户名的标头。目标是让基本的东西工作,然后将代码部署到 apache。

标签: pythondjangodjango-authentication

解决方案


我能够通过使用以下设置来解决这个问题。

MIDDLEWARE = [
'django.contrib.sessions.middleware.SessionMiddleware',  
'corsheaders.middleware.CorsMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'module.CheckIDMHeaderMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
AUTH_USER_MODEL = 'auth.User'

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.SessionAuthentication',
    ),
    'DEFAULT_PERMISSION_CLASSES': [],
    'UNAUTHENTICATED_USER': None,
}

必须创建我自己的用户类。

class User:
username = ''
user_permissions = []
is_active = True

def get_user_permissions(self):
    return self.user_permissions

def __init__(self, username):
    self.username = username
    self.is_active = True

在 CheckIDMHeaderMiddleware 的调用方法中,我正在读取包含从 webgate 插件获得的用户名的标题。使用该用户名,我创建了一个用户对象并在它的会话中进行设置。

def __call__(self, request):
    # some code skipped to keep the answer simple.
    ....
    username = request.META[header_name]
    user = User(username = username)
    request.user = user
    response = self.get_response(request)
    return response
    ....
    # some code skipped to keep the answer simple.
            

……


推荐阅读