<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Django 實(shí)現(xiàn)單點(diǎn)登錄(SSO)

          共 18617字,需瀏覽 38分鐘

           ·

          2021-03-26 18:38

          SSO簡(jiǎn)介

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

          搭建測(cè)試環(huán)境

          下面我們來(lái)創(chuàng)建兩個(gè)空的Django項(xiàng)目來(lái)進(jìn)行演示,SSO1和SSO2,這里采用pycharm直接創(chuàng)建兩個(gè)Django項(xiàng)目,也可以在命令行中使用django-admin startproject sso來(lái)創(chuàng)建,其中sso是創(chuàng)建的項(xiàng)目名稱。這里也可以使用兩個(gè)完全相同的項(xiàng)目,在不同地址啟動(dòng),但是為了演示效果,這里創(chuàng)建了2個(gè)。
          創(chuàng)建好兩個(gè)項(xiàng)目后,我們要給項(xiàng)目寫(xiě)一個(gè)模擬的登錄,注銷的功能。
          templates文件夾下創(chuàng)建文件login.html文件。這里直接使用之前寫(xiě)過(guò)的登錄頁(yè)面的代碼,樣式就不加了,在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="">注冊(cè)</button>
                    </div>
                  </form>
              </div>
          </div>
          </body>
          </html>
          然后在SSO1文件夾創(chuàng)建一個(gè)view.py文件,用來(lái)存放視圖函數(shù)。(這里僅為演示SSO,就不分模塊了。)
          創(chuàng)建文件后的文件目錄為:(SSO2項(xiàng)目一樣)
          .
          ├── SSO1
          │   ├── __init__.py
          │   ├── asgi.py
          │   ├── settings.py
          │   ├── urls.py
          │   ├── view.py
          │   └── wsgi.py
          ├── manage.py
          ├── templates
          │   └── login.html
          └── venv
              ├── bin
              ├── include
              ├── lib
              └── pyvenv.cfg

          插入一個(gè)小BUG

          macbook運(yùn)行環(huán)境,pycharm創(chuàng)建的Django應(yīng)用有時(shí)候初始化有個(gè)bug,缺少os庫(kù),會(huì)報(bào)錯(cuò):
          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
          如果有這個(gè)報(bào)錯(cuò)的話,在setting.py中導(dǎo)入os即可:import os
          然后我們?cè)趦蓚€(gè)項(xiàng)目的view.py中寫(xiě)入登錄和注銷函數(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/'

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

          將session存儲(chǔ)在同一個(gè)文件中實(shí)現(xiàn)SSO

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

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


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

          使用Redis實(shí)現(xiàn)SSO

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

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

          # 使用Redis存儲(chǔ)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

          此時(shí)我們?cè)賮?lái)測(cè)試一下兩個(gè)應(yīng)用,這時(shí)我們先訪問(wèn)一下logout,將session清空,然后訪問(wèn):http://127.0.0.1:5000/login/,輸入賬戶密碼后顯示:
          usr:123,password:123,sessionid:None,cookie:{'csrftoken''8YPzJbY03sHJUZH6kdFZzr9TkDtdVTKflgDDeIn0wgGC6cAeudcrkXLyIxXBEnzG'}

          此時(shí)我們?cè)L問(wèn)http://127.0.0.1:7000/login/(不登錄),顯示同樣的usr和password信息。

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

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

          原文來(lái)源:https://qiguanjie.blog.csdn.net/   

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


          瀏覽 36
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  AAA国产欧美日产无码免费网站 | 亚洲第一中文字幕 | 黄色成人在线免费播放 | 18操逼毛片 | 骚逼被操无码专区 |