天天看點

Django 實作單點登入(SSO)

點選上方 "程式設計技術圈"關注, 星标或置頂一起成長

Django 實作單點登入(SSO)

背景回複“大禮包”有驚喜禮包!

每日英文

Do not deliberately pursue certain things, falling leaves, belongs to me, it'll always be back.

不去刻意追求某些東西,落葉歸根,屬于我的,它總會回來。

每日掏心話

風還是一樣的吹,花還是一樣地開,我相信所謂的命運不過是一個人的生理,心理,情感,性格等等因素所造成的一個人行動的最終結果。

責編:樂樂 | 來自:Python開發者 | 連結:qiguanjie.blog.csdn.net/
           

程式設計技術圈(ID:study_tech)第 1198 次推文

往日回顧:推薦一個高仿微信的項目 有點屌!!

   正文   

SSO簡介單點登入(Single Sign On)功能是一個非常常用的功能,尤其是我們在多個系統之間需要登入同步的時候,例如我們在登入QQ空間後,再去QQ的其他網站,都是預設登入的狀态,這就是單點登入。單點登入有很多種實作方法,這裡介紹一個通過共享session的實作方法。實作共享session要做的就是要讓多個不同應用共用同一個session,但是session預設的是每個應用一個獨立的session和cookie的,是以這裡要對session的存儲進行配置。除了預設的session存儲,我也可以設定讓session存儲在檔案、緩存或者資料庫中。如果我們讓session存儲在一個固定位置或者資料庫中,然後我們設定各個應用cookie的domain為父域位址即可實作各個cookie的相同,進而時候各個cookie中存儲的sessionID一緻。搭建測試環境下面我們來建立兩個空的Django項目來進行示範,SSO1和SSO2,這裡采用pycharm直接建立兩個Django項目,也可以在指令行中使用django-admin startproject sso來建立,其中sso是建立的項目名稱。這裡也可以使用兩個完全相同的項目,在不同位址啟動,但是為了示範效果,這裡建立了2個。建立好兩個項目後,我們要給項目寫一個模拟的登入,登出的功能。在templates檔案夾下建立檔案login.html檔案。這裡直接使用之前寫過的登入頁面的代碼,樣式就不加了,在SSO1和SSO2中都加入login.html,具體代碼為:<!DOCTYPE html>
<html >
<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檔案夾建立一個view.py檔案,用來存放視圖函數。(這裡僅為示範SSO,就不分子產品了。)建立檔案後的檔案目錄為:(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
插入一個小BUGmacbook運作環境,pycharm建立的Django應用有時候初始化有個bug,缺少os庫,會報錯:Traceback (most recent call last):
  File "/Users/qiguan/Documents/develop_files/python_files/SSO1/manage.py", line 22, in <module>
    main()
  File "/Users/qiguan/Documents/develop_files/python_files/SSO1/manage.py", line 18, in 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 401, in 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 345, in execute
    settings.INSTALLED_APPS
  File "/Users/qiguan/Documents/develop_files/python_files/SSO1/venv/lib/python3.7/site-packages/django/conf/__init__.py", line 82, in __getattr__
    self._setup(name)
  File "/Users/qiguan/Documents/develop_files/python_files/SSO1/venv/lib/python3.7/site-packages/django/conf/__init__.py", line 69, in _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 170, in __init__
    mod = importlib.import_module(self.SETTINGS_MODULE)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1006, in _gcd_import
  File "<frozen importlib._bootstrap>", line 983, in _find_and_load
  File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 677, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 728, in exec_module
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File "/Users/qiguan/Documents/develop_files/python_files/SSO1/SSO1/settings.py", line 57, in <module>
    'DIRS': [os.path.join(BASE_DIR, 'templates')]
NameError: name 'os' is not defined
如果有這個報錯的話,在setting.py中導入os即可:import os然後我們在兩個項目的view.py中寫入登入和登出函數: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預設配置了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/'

然後分别為兩個項目做資料庫遷移,建立一些Django項目的基礎庫:python3 manage.py migrate兩個項目都是同樣的配置,這樣我們目前兩個測試的項目就搭建好了,然後我們分别啟動他們在不同的端口。這裡我們就直接手動啟動了,分别啟動在5000和6000端口。搜尋公衆号後端架構師背景回複“架構整潔”,擷取一份驚喜禮包。python3 manage.py runserver 127.0.0.1:5000
python3 manage.py runserver 127.0.0.1:7000啟動兩個項目:現在我們分别在浏覽器中打開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/,發現這個應用中,顯示的還是之前的頁面,登入沒有同步。下面我們來實作我們的SSO,這裡的實作方法非常的簡單,這裡提供2中實作方法:将session固定存儲在同一個檔案中,将session存儲在Redis中将session存儲在同一個檔案中實作SSO我們在SSO2檔案下建立了一個session檔案夾,這個檔案夾位置任意,寫絕對路徑即可。然後我們在兩個項目的settings.py中對cookie和session進行配置# 設定cookie的domain為父域domain,
# 如果是使用域名,以百度為例,主域名為`www.baidu.com`,旗下各個應用為:'asd.baidu.com'
# 則這裡設定為:`.baidu.com`
SESSION_COOKIE_DOMAIN = '127.0.0.1'

# 設定session存儲在檔案中
SESSION_ENGINE = 'django.contrib.sessions.backends.file'
# 設定存儲位置,這裡設為絕對路徑
SESSION_FILE_PATH = '/Users/qiguan/Documents/develop_files/python_files/SSO2/session'

注意一下,這裡配置的都是一樣的,但是如果兩個項目名稱不一樣的話,是不能直接将完整的settings.py直接複制到另一個的,因為裡面有一些項目的配置,例如ROOT_URLCONF = 'SSO1.urls'、WSGI_APPLICATION = 'SSO1.wsgi.application'這些前面的都是項目名,需要主要區分。
此時我們在打開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/,我們直接通路,而不用登入,發現顯示同樣的内容,即我們使用的是同樣的内容,實作了SSO。使用Redis實作SSO使用檔案系統上實作共享session在小并發系統上不會出現問題,但是并發量大的話,會出現一些問題,是以我們這裡再介紹一下使用Redis的實作。需要自行安裝Redis,并且在兩個項目使用的Python中安裝Django-redis:
pip3 install django-redis在做好這些之後,修改settings.py檔案,将使用檔案存儲session的配置注釋掉,修改為:
# # 設定session存儲在檔案中
# SESSION_ENGINE = 'django.contrib.sessions.backends.file'
# # 設定存儲位置,這裡設為絕對路徑
# 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

此時我們再來測試一下兩個應用,這時我們先通路一下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也可以正常實作。
好了,本文就先到這裡,大家如有需要,可以根據具體的業務進行實作,這裡就不贅述了。等以後有空再寫一些Django相關的開發部落格。

PS:歡迎在留言區留下你的觀點,一起讨論提高。如果今天的文章讓你有新的啟發,歡迎轉發分享給更多人。版權申明:内容來源網絡,版權歸原創者所有。除非無法确認,我們都會标明作者及出處,如有侵權煩請告知,我們會立即删除并表示歉意。謝謝!

歡迎加入後端架構師交流群,在背景回複“學習”即可。

在這裡,我為大家準備了一份2021年最新最全BAT等大廠Java面試經驗總結
别找了,想擷取史上最簡單的Java大廠面試題學習資料
掃下方二維碼回複「手冊」就好了


猜你還想看
阿裡、騰訊、百度、華為、京東最新面試題彙集
HashMap 面試二十一問!看它就夠了!

新版Win10來了!網友:醜哭了

面試這樣回答Java調優,至少加1000塊!!!

嘿,你在看嗎?

           

繼續閱讀