1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        Django 實現(xiàn)單點登錄(SSO)

        共 18617字,需瀏覽 38分鐘

         ·

        2021-03-26 18:38

        SSO簡介

        單點登錄(Single Sign On)功能是一個非常常用的功能,尤其是我們在多個系統(tǒng)之間需要登錄同步的時候,例如我們在登錄QQ空間后,再去QQ的其他網(wǎng)站,都是默認(rèn)登錄的狀態(tài),這就是單點登錄。
        單點登錄有很多種實現(xiàn)方法,這里介紹一個通過共享session的實現(xiàn)方法。實現(xiàn)共享session要做的就是要讓多個不同應(yīng)用共用同一個session,但是session默認(rèn)的是每個應(yīng)用一個獨立的session和cookie的,所以這里要對session的存儲進行配置。
        除了默認(rèn)的session存儲,我也可以設(shè)置讓session存儲在文件、緩存或者數(shù)據(jù)庫中。
        如果我們讓session存儲在一個固定位置或者數(shù)據(jù)庫中,然后我們設(shè)置各個應(yīng)用cookie的domain為父域地址即可實現(xiàn)各個cookie的相同,從而時候各個cookie中存儲的sessionID一致。

        搭建測試環(huán)境

        下面我們來創(chuàng)建兩個空的Django項目來進行演示,SSO1和SSO2,這里采用pycharm直接創(chuàng)建兩個Django項目,也可以在命令行中使用django-admin startproject sso來創(chuàng)建,其中sso是創(chuàng)建的項目名稱。這里也可以使用兩個完全相同的項目,在不同地址啟動,但是為了演示效果,這里創(chuàng)建了2個。
        創(chuàng)建好兩個項目后,我們要給項目寫一個模擬的登錄,注銷的功能。
        templates文件夾下創(chuàng)建文件login.html文件。這里直接使用之前寫過的登錄頁面的代碼,樣式就不加了,在SSO1和SSO2中都加入login.html,具體代碼為:
        <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <title>Title</title>
        </head>
        <body>
        <div class="login_content">
            <div class="page-header" id="page_header">
              <h1>登錄<small>Login</small></h1>
            </div>
            <div id="login_form">
                <form method="post">
                  <div class="form-group">
                    <label for="exampleInputEmail1">Email address</label>
                    <input type="input" class="form-control" name="usr" id="exampleInputEmail1" placeholder="username">
                  </div>
                  <div class="form-group">
                    <label for="exampleInputPassword1">密碼</label>
                    <input type="password" class="form-control" name="password" id="exampleInputPassword1" placeholder="密碼">
                  </div>
                  <div id="login_butt">
                      <button type="submit" class="btn btn-default">登錄</button>
                      <button type="button" class="btn btn-default" onclick="">注冊</button>
                  </div>
                </form>
            </div>
        </div>
        </body>
        </html>
        然后在SSO1文件夾創(chuàng)建一個view.py文件,用來存放視圖函數(shù)。(這里僅為演示SSO,就不分模塊了。)
        創(chuàng)建文件后的文件目錄為:(SSO2項目一樣)
        .
        ├── SSO1
        │   ├── __init__.py
        │   ├── asgi.py
        │   ├── settings.py
        │   ├── urls.py
        │   ├── view.py
        │   └── wsgi.py
        ├── manage.py
        ├── templates
        │   └── login.html
        └── venv
            ├── bin
            ├── include
            ├── lib
            └── pyvenv.cfg

        插入一個小BUG

        macbook運行環(huán)境,pycharm創(chuàng)建的Django應(yīng)用有時候初始化有個bug,缺少os庫,會報錯:
        Traceback (most recent call last):
          File "/Users/qiguan/Documents/develop_files/python_files/SSO1/manage.py", line 22in <module>
            main()
          File "/Users/qiguan/Documents/develop_files/python_files/SSO1/manage.py", line 18in main
            execute_from_command_line(sys.argv)
          File "/Users/qiguan/Documents/develop_files/python_files/SSO1/venv/lib/python3.7/site-packages/django/core/management/__init__.py", line 401in execute_from_command_line
            utility.execute()
          File "/Users/qiguan/Documents/develop_files/python_files/SSO1/venv/lib/python3.7/site-packages/django/core/management/__init__.py", line 345in execute
            settings.INSTALLED_APPS
          File "/Users/qiguan/Documents/develop_files/python_files/SSO1/venv/lib/python3.7/site-packages/django/conf/__init__.py", line 82in __getattr__
            self._setup(name)
          File "/Users/qiguan/Documents/develop_files/python_files/SSO1/venv/lib/python3.7/site-packages/django/conf/__init__.py", line 69in _setup
            self._wrapped = Settings(settings_module)
          File "/Users/qiguan/Documents/develop_files/python_files/SSO1/venv/lib/python3.7/site-packages/django/conf/__init__.py", line 170in __init__
            mod = importlib.import_module(self.SETTINGS_MODULE)
          File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/importlib/__init__.py", line 127in import_module
            return _bootstrap._gcd_import(name[level:], packagelevel)
          File "<frozen importlib._bootstrap>", line 1006in _gcd_import
          File "<frozen importlib._bootstrap>", line 983in _find_and_load
          File "<frozen importlib._bootstrap>", line 967in _find_and_load_unlocked
          File "<frozen importlib._bootstrap>", line 677in _load_unlocked
          File "<frozen importlib._bootstrap_external>", line 728in exec_module
          File "<frozen importlib._bootstrap>", line 219in _call_with_frames_removed
          File "/Users/qiguan/Documents/develop_files/python_files/SSO1/SSO1/settings.py", line 57in <module>
            'DIRS': [os.path.join(BASE_DIR, 'templates')]
        NameError: name 'os' is not defined
        如果有這個報錯的話,在setting.py中導(dǎo)入os即可:import os
        然后我們在兩個項目的view.py中寫入登錄和注銷函數(shù):
        from django.http import HttpResponse
        from django.shortcuts import render, redirect


        def login(request):
            if request.method == 'GET':
                if 'usr' in request.session:
                    # 如果session中已有信息,則顯示
                    usr = request.session['usr']
                    password = request.session['password']
                    return HttpResponse("usr:{},password:{},sessionid:{},cookie:{}".format(usr,password,request.session.session_key,request.COOKIES))
                return render(request,'login.html')
            if request.method == 'POST':
                usr = request.POST['usr']
                password = request.POST['password']
                request.session['usr'] = usr
                request.session['password'] = password
                return HttpResponse(
                    "usr:{},password:{},sessionid:{},cookie:{}".format(usr, password, request.session.session_key,
                                                                       request.COOKIES))


        def logout(request):
            request.session.clear()
            return redirect('/login')

        url.py中添加路由信息:

        """SSO1 URL Configuration

        The `urlpatterns` list routes URLs to views. For more information please see:
            https://docs.djangoproject.com/en/3.1/topics/http/urls/
        Examples:
        Function views
            1. Add an import:  from my_app import views
            2. Add a URL to urlpatterns:  path('', views.home, name='home')
        Class-based views
            1. Add an import:  from other_app.views import Home
            2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
        Including another URLconf
            1. Import the include() function: from django.urls import include, path
            2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
        """

        from django.contrib import admin
        from django.urls import path
        from . import view
        urlpatterns = [
            path('admin/', admin.site.urls),
            path('login/',view.login),
            path('logout/',view.logout),
        ]

        Django默認(rèn)配置了csrf,需要將它注釋掉,在settings.py文件中搜csrf,然后注釋掉。
        修改后的settings.py文件為:
        """
        Django settings for SSO1 project.

        Generated by 'django-admin startproject' using Django 3.1.7.

        For more information on this file, see
        https://docs.djangoproject.com/en/3.1/topics/settings/

        For the full list of settings and their values, see
        https://docs.djangoproject.com/en/3.1/ref/settings/
        """


        from pathlib import Path
        import os

        # Build paths inside the project like this: BASE_DIR / 'subdir'.
        BASE_DIR = Path(__file__).resolve().parent.parent


        # Quick-start development settings - unsuitable for production
        # See https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/

        # SECURITY WARNING: keep the secret key used in production secret!
        SECRET_KEY = 'o=blc^vzeb1&g*b!si(wtxe44_=i5cv(3jqm2*u2u&7vgj%&=%'

        # SECURITY WARNING: don't run with debug turned on in production!
        DEBUG = True

        ALLOWED_HOSTS = []


        # Application definition

        INSTALLED_APPS = [
            'django.contrib.admin',
            'django.contrib.auth',
            'django.contrib.contenttypes',
            'django.contrib.sessions',
            'django.contrib.messages',
            'django.contrib.staticfiles',
        ]

        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',
        ]

        ROOT_URLCONF = 'SSO1.urls'

        TEMPLATES = [
            {
                'BACKEND''django.template.backends.django.DjangoTemplates',
                'DIRS': [os.path.join(BASE_DIR, 'templates')]
                ,
                'APP_DIRS'True,
                'OPTIONS': {
                    'context_processors': [
                        'django.template.context_processors.debug',
                        'django.template.context_processors.request',
                        'django.contrib.auth.context_processors.auth',
                        'django.contrib.messages.context_processors.messages',
                    ],
                },
            },
        ]

        WSGI_APPLICATION = 'SSO1.wsgi.application'


        # Database
        # https://docs.djangoproject.com/en/3.1/ref/settings/#databases

        DATABASES = {
            'default': {
                'ENGINE''django.db.backends.sqlite3',
                'NAME': BASE_DIR / 'db.sqlite3',
            }
        }


        # Password validation
        # https://docs.djangoproject.com/en/3.1/ref/settings/#auth-password-validators

        AUTH_PASSWORD_VALIDATORS = [
            {
                'NAME''django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
            },
            {
                'NAME''django.contrib.auth.password_validation.MinimumLengthValidator',
            },
            {
                'NAME''django.contrib.auth.password_validation.CommonPasswordValidator',
            },
            {
                'NAME''django.contrib.auth.password_validation.NumericPasswordValidator',
            },
        ]


        # Internationalization
        # https://docs.djangoproject.com/en/3.1/topics/i18n/

        LANGUAGE_CODE = 'en-us'

        TIME_ZONE = 'UTC'

        USE_I18N = True

        USE_L10N = True

        USE_TZ = True


        # Static files (CSS, JavaScript, Images)
        # https://docs.djangoproject.com/en/3.1/howto/static-files/

        STATIC_URL = '/static/'

        然后分別為兩個項目做數(shù)據(jù)庫遷移,創(chuàng)建一些Django項目的基礎(chǔ)庫:python3 manage.py migrate
        兩個項目都是同樣的配置,這樣我們目前兩個測試的項目就搭建好了,然后我們分別啟動他們在不同的端口。這里我們就直接手動啟動了,分別啟動在5000和6000端口。
        python3 manage.py runserver 127.0.0.1:5000
        python3 manage.py runserver 127.0.0.1:7000
        啟動兩個項目:
        現(xiàn)在我們分別在瀏覽器中打開http://127.0.0.1:5000/login/http://127.0.0.1:7000/login/,顯示的頁面都是登錄頁面,顯示如下:
        這時我們在http://127.0.0.1:5000/login/隨意輸入賬戶密碼點擊登錄,顯示:
        usr:123,password:123,sessionid:None,cookie:{'csrftoken''8YPzJbY03sHJUZH6kdFZzr9TkDtdVTKflgDDeIn0wgGC6cAeudcrkXLyIxXBEnzG'}
        此時我們進入http://127.0.0.1:7000/login/,發(fā)現(xiàn)這個應(yīng)用中,顯示的還是之前的頁面,登錄沒有同步。下面我們來實現(xiàn)我們的SSO,這里的實現(xiàn)方法非常的簡單,這里提供2中實現(xiàn)方法:
        • 將session固定存儲在同一個文件中,
        • 將session存儲在Redis中

        將session存儲在同一個文件中實現(xiàn)SSO

        我們在SSO2文件下創(chuàng)建了一個session文件夾,這個文件夾位置任意,寫絕對路徑即可。
        然后我們在兩個項目的settings.py中對cookie和session進行配置
        # 設(shè)置cookie的domain為父域domain,
        # 如果是使用域名,以百度為例,主域名為`www.baidu.com`,旗下各個應(yīng)用為:'asd.baidu.com'
        # 則這里設(shè)置為:`.baidu.com`
        SESSION_COOKIE_DOMAIN = '127.0.0.1'

        # 設(shè)置session存儲在文件中
        SESSION_ENGINE = 'django.contrib.sessions.backends.file'
        # 設(shè)置存儲位置,這里設(shè)為絕對路徑
        SESSION_FILE_PATH = '/Users/qiguan/Documents/develop_files/python_files/SSO2/session'


        注意一下,這里配置的都是一樣的,但是如果兩個項目名稱不一樣的話,是不能直接將完整的settings.py直接復(fù)制到另一個的,因為里面有一些項目的配置,例如ROOT_URLCONF = 'SSO1.urls'、WSGI_APPLICATION = 'SSO1.wsgi.application'這些前面的都是項目名,需要主要區(qū)分。
        此時我們在打開
        http://127.0.0.1:5000/login/,輸入賬號密碼,此頁面顯示:
        usr:123,password:123,sessionid:2bs2nx2iq879epxu7au7o1zq63o095v7,cookie:{'sessionid''2bs2nx2iq879epxu7au7o1zq63o095v7''csrftoken''8YPzJbY03sHJUZH6kdFZzr9TkDtdVTKflgDDeIn0wgGC6cAeudcrkXLyIxXBEnzG'}
        此時我們在打開http://127.0.0.1:7000/login/,我們直接訪問,而不用登錄,發(fā)現(xiàn)顯示同樣的內(nèi)容,即我們使用的是同樣的內(nèi)容,實現(xiàn)了SSO。

        使用Redis實現(xiàn)SSO

        使用文件系統(tǒng)上實現(xiàn)共享session在小并發(fā)系統(tǒng)上不會出現(xiàn)問題,但是并發(fā)量大的話,會出現(xiàn)一些問題,所以我們這里再介紹一下使用Redis的實現(xiàn)。
        需要自行安裝Redis,并且在兩個項目使用的Python中安裝Django-redis:
        pip3 install django-redis
        在做好這些之后,修改settings.py文件,將使用文件存儲session的配置注釋掉,修改為:

        # # 設(shè)置session存儲在文件中
        # SESSION_ENGINE = 'django.contrib.sessions.backends.file'
        # # 設(shè)置存儲位置,這里設(shè)為絕對路徑
        # SESSION_FILE_PATH = '/Users/qiguan/Documents/develop_files/python_files/SSO2/session'

        # 使用Redis存儲session
        CACHES = {
            "default": {
                "BACKEND""django_redis.cache.RedisCache",
                "LOCATION""redis://127.0.0.1:6379",
                "OPTIONS": {
                    "CLIENT_CLASS""django_redis.client.DefaultClient",
                    "CONNECTION_POOL_KWARGS": {"max_connections": 100}
                    # "PASSWORD": "123",
                }
            }
        }

        SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
        SESSION_CACHE_ALIAS = 'default'
        SESSION_COOKIE_AGE = 60 * 5

        此時我們再來測試一下兩個應(yīng)用,這時我們先訪問一下logout,將session清空,然后訪問:http://127.0.0.1:5000/login/,輸入賬戶密碼后顯示:
        usr:123,password:123,sessionid:None,cookie:{'csrftoken''8YPzJbY03sHJUZH6kdFZzr9TkDtdVTKflgDDeIn0wgGC6cAeudcrkXLyIxXBEnzG'}

        此時我們訪問http://127.0.0.1:7000/login/(不登錄),顯示同樣的usr和password信息。

        此時我們的SSO也可以正常實現(xiàn)。

        好了,本文就先到這里,大家如有需要,可以根據(jù)具體的業(yè)務(wù)進行實現(xiàn),這里就不贅述了。等以后有空再寫一些Django相關(guān)的開發(fā)博客。

        原文來源:https://qiguanjie.blog.csdn.net/   

        文章轉(zhuǎn)自:Python開發(fā)者


        瀏覽 36
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            a级大片在线观看 | 久久99久久99久久99人受 | 欧美日韩成人在线视频 | 操极品| 五月天开心成人网 | 办公室女职员交换性bd | 成人激情深爱网 | 国产精品福利导航 | 高潮小说h | 16—17女人毛片毛片国内 |