天天看點

Session認證機制

Session認證機制

  1. 狀态保持
    • 浏覽器請求伺服器是無狀态的。
    • 無狀态:指一次使用者請求時,浏覽器、伺服器無法知道之前這個使用者做過什麼,每次請求都是一次新的請求。
    • 無狀态原因:浏覽器與伺服器是使用Socket套接字進行通信的,伺服器将請求結果傳回給浏覽器之後,會關閉目前的Socket連接配接,而且伺服器也會在處理頁面完畢之後銷毀頁面對象。
    • 有時需要保持下來使用者浏覽的狀态,比如使用者是否登入過,浏覽過哪些商品等
    • 實作狀态保持主要有兩種方式:
      • 在用戶端存儲資訊使用

        Cookie

      • 在伺服器端存儲資訊使用

        Session

  2. Cookie

    Cookie,有時也用其複數形式Cookies,指某些網站為了辨識使用者身份、進行session跟蹤而儲存在使用者本地終端上的資料(通常經過加密)。Cookie最早是網景公司的前雇員Lou Montulli在1993年3月的發明。Cookie是由伺服器端生成,發送給User-Agent(一般是浏覽器),浏覽器會将Cookie的key/value儲存到某個目錄下的文本檔案内,下次請求同一網站時就發送該Cookie給伺服器(前提是浏覽器設定為啟用cookie)。Cookie名稱和值可以由伺服器端開發自己定義,這樣伺服器可以知道該使用者是否是合法使用者以及是否需要重新登入等。伺服器可以利用Cookies包含資訊的任意性來篩選并經常性維護這些資訊,以判斷在HTTP傳輸中的狀态。Cookies最典型記住使用者名。

    Cookie是存儲在浏覽器中的一段純文字資訊,建議不要存儲敏感資訊如密碼,因為電腦上的浏覽器可能被其它人使用。

    Cookie的特點
    • Cookie以鍵值對的格式進行資訊的存儲。
    • Cookie基于域名安全,不同域名的Cookie是不能互相通路的,如通路itcast.cn時向浏覽器中寫了Cookie資訊,使用同一浏覽器通路baidu.com時,無法通路到itcast.cn寫的Cookie資訊。
    • 當浏覽器請求某網站時,會将浏覽器存儲的跟網站相關的所有Cookie資訊送出給網站伺服器。
    1. 設定Cookie:可以通過HttpResponse對象中的set_cookie方法來設定cookie。
      # HttpResponse.set_cookie(cookie名, value=cookie值, max_age=cookie有效期)
      # max_age機關為秒,預設為None 。如果是臨時cookie,可将max_age設定為None。
      # 示例:
      def cookie(request):
          response = HttpResponse('ok')
          response.set_cookie('xlz', 'python1')  # 臨時cookie
          response.set_cookie('xlz', 'python2', max_age=3600)  # 有效期一小時
          return response
                 
    2. 讀取Cookie:可以通過HttpResponse對象的COOKIES屬性來讀取本次請求攜帶的cookie值。request.COOKIES為字典類型。
      def cookie(request):
          cookie1 = request.COOKIES.get('xlz')
          print(cookie1)
          return HttpResponse('OK')
                 
    3. 删除Cookie:可以通過HttpResponse對象中的delete_cookie方法來删除。
  3. Session
    1. 啟用Session,Django項目預設啟用Session。可以在settings.py檔案中檢視
      MIDDLEWARE = [
          'corsheaders.middleware.CorsMiddleware',
          'django.middleware.security.SecurityMiddleware',
          # 啟用Session
          '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',
      ]
                 
    2. MIDDLEWARE = [
          'corsheaders.middleware.CorsMiddleware',
          'django.middleware.security.SecurityMiddleware',
          # 啟用Session
          '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',
          # 注冊中間件 判斷cookie資訊
          # 'users.middleware.username_cookie_middleware',
                 
    3. 存儲方式

      在settings.py檔案中,可以設定session資料的存儲方式,可以儲存在資料庫、本地緩存等

      1. 如果存儲在資料庫中,需要在項INSTALLED_APPS中安裝Session應用,操作Session包括三個資料:鍵,值,過期時間。

        存儲在資料庫中,如下設定可以寫,也可以不寫,這是預設存儲方式。

        INSTALLED_APPS = [
            'django.contrib.admin',
            'django.contrib.auth',
            'django.contrib.contenttypes',
            # 安裝Session應用
            'django.contrib.sessions',
            'django.contrib.messages',
            'django.contrib.staticfiles',
            ]
                   
      2. 本地緩存,存儲在本機記憶體中,如果丢失則不能找回,比資料庫的方式讀寫更快。
      3. 混合存儲, 優先從本機記憶體中存取,如果沒有則從資料庫中存取。
      4. Redis,在redis中儲存session,需要引入第三方擴充,我們可以使用django-redis來解決。

        1) 安裝擴充

        pip install django-redis
                   

        2)配置

        在settings.py檔案中做如下設定

        CACHES = {
            'default': {
                'BACKEND': 'django_redis.cache.RedisCache',
                'LOCATION': 'redis://127.0.0.1:6379/1',
                'OPTIONS': {
                    'CLIENT_CLASS': 'django_redis.client.DefaultClient',
                }
            }
        }
        SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
        SESSION_CACHE_ALIAS = 'default'
                   
        注意:如果redis的ip位址不是本地回環127.0.0.1,而是其他位址,通路Django時,可能出現Redis連接配接錯誤,如下:
        Session認證機制

        解決方法:

        修改redis的配置檔案,添加特定ip位址。

        sudo vim /etc/redis/redis.conf
                   
        Session認證機制
        重新啟動redis服務
        sudo service redis-server restart
                   
    4. Session操作

      通過HttpRequest對象的session屬性進行會話的讀寫操作。

      1) 以鍵值對的格式寫session。

      request.session['鍵']=值
                 
      2)根據鍵讀取值。
      request.session.get('鍵',預設值)
                 
      3)清除所有session,在存儲中删除值部分。
      request.session.clear()
                 
      4)清除session資料,在存儲中删除session的整條資料。
      request.session.flush()
                 
      5)删除session中的指定鍵及值,在存儲中隻删除某個鍵及對應的值。
      del request.session['鍵']
                 
      6)設定session的有效期
      request.session.set_expiry(value)
                 
      • 如果value是一個整數,session将在value秒沒有活動後過期。
      • 如果value為0,那麼使用者session的Cookie将在使用者的浏覽器關閉時過期。
      • 如果value為None,那麼session有效期将采用系統預設值, 預設為兩周,可以通過在settings.py中設定SESSION_COOKIE_AGE來設定全局預設值。
使用者登入執行個體
  1. 使用者登入
    class LoginView(View):
        """使用者名登入"""
        def get(self, request):
            """
            提供登入界面
            :param request: 請求對象
            :return: 登入界面
            """
            return render(request, 'login.html')
        def post(self, request):
            """
            實作登入邏輯
            :param request: 請求對象
            :return: 登入結果
            """
            # 接受參數
            username = request.POST.get('username')
            password = request.POST.get('password')
            remembered = request.POST.get('remembered')
            # 校驗參數
            # 判斷參數是否齊全
            if not all([username, password]):
                return http.HttpResponseForbidden('缺少必傳參數')
            # 判斷使用者名是否是5-20個字元
            if not re.match(r'^[a-zA-Z0-9_-]{5,20}$', username):
                return http.HttpResponseForbidden('請輸入正确的使用者名或手機号')
            # 判斷密碼是否是8-20個數字
            if not re.match(r'^[0-9A-Za-z]{8,20}$', password):
                return http.HttpResponseForbidden('密碼最少8位,最長20位')
            # 認證登入使用者
            user = authenticate(username=username, password=password)
            if user is None:
                return render(request, 'login.html', {'account_errmsg': '使用者名或密碼錯誤'})
            # 實作狀态保持
            login(request, user)
            # 設定狀态保持的周期
            if remembered != 'on':
                # 沒有記住使用者:浏覽器會話結束就過期
                request.session.set_expiry(0)
            else:
                # 記住使用者:None表示兩周後過期
                request.session.set_expiry(None)
            # 響應登入結果
            return redirect(reverse('contents:index'))
               
  2. 登出
    1. 登出:
      • 回顧登入:将通過認證的使用者的唯一辨別資訊,寫入到目前session會話中
      • 登出:正好和登入相反(清理session會話資訊)
    2. logout()方法:
      • Django使用者認證系統提供了

        logout()

        方法
      • 封裝了清理session的操作,幫助我們快速實作登出一個使用者
    3. logout()位置:

      django.contrib.auth.__init__.py

      檔案中
    4. logout()方法使用
      class LogoutView(View):
          """登出"""
      
          def get(self, request):
              """實作登出邏輯"""
              # 清理session
              logout(request)
              # 登出,重定向到登入頁
              response = redirect(reverse('contents:index'))
              # 登出時清除cookie中的username
              response.delete_cookie('username')
      
              return response
                 

繼續閱讀