3atv精品不卡视频,97人人超碰国产精品最新,中文字幕av一区二区三区人妻少妇,久久久精品波多野结衣,日韩一区二区三区精品

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > python >内容正文

python

Python计算机视觉:第八章 图像类容分类

發(fā)布時(shí)間:2025/3/21 python 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Python计算机视觉:第八章 图像类容分类 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

第八章 圖像類容分類

  • 8.1 K最近鄰
  • 8.1.1 一個(gè)簡單的二維例子
  • 8.1.2 圖像稠密(dense)sift特征)
  • 8.1.3 圖像分類——手勢識別
  • 8.1 session 和登錄失敗
  • 8.1.1 Sessions 控制器
  • 8.1.2 測試登錄功能
  • 8.1.3 登錄表單
  • 8.1.4 分析表單提交
  • 8.1.5 顯示 Flash 消息
  • 8.2 登錄成功
  • 8.2.1 “記住我”
  • 8.2.2 定義 sign_in 方法
  • 8.2.3 獲取當(dāng)前用戶
  • 8.2.4 改變導(dǎo)航鏈接
  • 8.2.5 注冊后直接登錄
  • 8.2.6 退出
  • 8.3 Cucumber 簡介(選讀)
  • 8.3.1 安裝和設(shè)置
  • 8.3.2 功能和步驟定義
  • 8.3.3 小技巧:自定義 RSpec 匹配器
  • 8.4 小結(jié)
  • 8.5 練習(xí)
  • 8.1 K最近鄰

    K最近鄰是分類中最簡單且常用的方法之一。

    8.1.1 一個(gè)簡單的二維例子

    # -*- coding: utf-8 -*- from numpy.random import randn import pickle from pylab import *# create sample data of 2D points n = 200 # two normal distributions class_1 = 0.6 * randn(n,2) class_2 = 1.2 * randn(n,2) + array([5,1]) labels = hstack((ones(n),-ones(n))) # save with Pickle #with open('points_normal.pkl', 'w') as f: with open('points_normal_test.pkl', 'w') as f:pickle.dump(class_1,f)pickle.dump(class_2,f)pickle.dump(labels,f) # normal distribution and ring around it class_1 = 0.6 * randn(n,2) r = 0.8 * randn(n,1) + 5 angle = 2*pi * randn(n,1) class_2 = hstack((r*cos(angle),r*sin(angle))) labels = hstack((ones(n),-ones(n))) # save with Pickle #with open('points_ring.pkl', 'w') as f: with open('points_ring_test.pkl', 'w') as f:pickle.dump(class_1,f)pickle.dump(class_2,f)pickle.dump(labels,f) # -*- coding: utf-8 -*- import pickle from pylab import * from PCV.classifiers import knn from PCV.tools import imtoolspklist=['points_normal.pkl','points_ring.pkl']figure()# load 2D points using Pickle for i, pklfile in enumerate(pklist):with open(pklfile, 'r') as f:class_1 = pickle.load(f)class_2 = pickle.load(f)labels = pickle.load(f)# load test data using Picklewith open(pklfile[:-4]+'_test.pkl', 'r') as f:class_1 = pickle.load(f)class_2 = pickle.load(f)labels = pickle.load(f)model = knn.KnnClassifier(labels,vstack((class_1,class_2)))# test on the first pointprint model.classify(class_1[0])#define function for plottingdef classify(x,y,model=model):return array([model.classify([xx,yy]) for (xx,yy) in zip(x,y)])# lot the classification boundarysubplot(1,2,i+1)imtools.plot_2D_boundary([-6,6,-6,6],[class_1,class_2],classify,[1,-1])titlename=pklfile[:-4]title(titlename) show()

    8.1.2 圖像稠密(dense)sift特征)

    # -*- coding: utf-8 -*- from PCV.localdescriptors import sift, dsift from pylab import * from PIL import Imagedsift.process_image_dsift('../data/empire.jpg','empire.dsift',90,40,True) l,d = sift.read_features_from_file('empire.dsift') im = array(Image.open('../data/empire.jpg')) sift.plot_features(im,l,True) title('dense SIFT') show()

    8.1.3 圖像分類——手勢識別

    # -*- coding: utf-8 -*- import os from PCV.localdescriptors import sift, dsift from pylab import * from PIL import Imageimlist=['../data/gesture/train/A-uniform01.ppm','../data/gesture/train/B-uniform01.ppm','../data/gesture/train/C-uniform01.ppm','../data/gesture/train/Five-uniform01.ppm','../data/gesture/train/Point-uniform01.ppm','../data/gesture/train/V-uniform01.ppm']figure() for i, im in enumerate(imlist):dsift.process_image_dsift(im,im[:-3]+'.dsift',90,40,True)l,d = sift.read_features_from_file(im[:-3]+'dsift')dirpath, filename=os.path.split(im)im = array(Image.open(im))#顯示手勢含義titletitlename=filename[:-14]subplot(2,3,i+1)sift.plot_features(im,l,True)title(titlename) show()

    # -*- coding: utf-8 -*- from PCV.localdescriptors import dsift import os from PCV.localdescriptors import sift from pylab import * from PCV.classifiers import knndef get_imagelist(path):""" Returns a list of filenames for all jpg images in a directory. """return [os.path.join(path,f) for f in os.listdir(path) if f.endswith('.ppm')]def read_gesture_features_labels(path):# create list of all files ending in .dsiftfeatlist = [os.path.join(path,f) for f in os.listdir(path) if f.endswith('.dsift')]# read the featuresfeatures = []for featfile in featlist:l,d = sift.read_features_from_file(featfile)features.append(d.flatten())features = array(features)# create labelslabels = [featfile.split('/')[-1][0] for featfile in featlist]return features,array(labels)def print_confusion(res,labels,classnames):n = len(classnames)# confusion matrixclass_ind = dict([(classnames[i],i) for i in range(n)])confuse = zeros((n,n))for i in range(len(test_labels)):confuse[class_ind[res[i]],class_ind[test_labels[i]]] += 1print 'Confusion matrix for'print classnamesprint confusefilelist_train = get_imagelist('../data/gesture/train') filelist_test = get_imagelist('../data/gesture/test') imlist=filelist_train+filelist_test# process images at fixed size (50,50) for filename in imlist:featfile = filename[:-3]+'dsift'dsift.process_image_dsift(filename,featfile,10,5,resize=(50,50))features,labels = read_gesture_features_labels('../data/gesture/train/') test_features,test_labels = read_gesture_features_labels('../data/gesture/test/') classnames = unique(labels)# test kNN k = 1 knn_classifier = knn.KnnClassifier(labels,features) res = array([knn_classifier.classify(test_features[i],k) for i in range(len(test_labels))]) # accuracy acc = sum(1.0*(res==test_labels)) / len(test_labels) print 'Accuracy:', accprint_confusion(res,test_labels,classnames) Accuracy: 0.813471502591 Confusion matrix for ['A' 'B' 'C' 'F' 'P' 'V'] [[ 26. 0. 2. 0. 1. 1.][ 0. 26. 0. 1. 1. 1.][ 0. 0. 26. 0. 0. 1.][ 0. 3. 0. 37. 0. 0.][ 0. 1. 2. 0. 17. 1.][ 3. 1. 3. 0. 14. 25.]]

    第七章已經(jīng)實(shí)現(xiàn)了注冊新用戶的功能,本章我們要為已注冊的用戶提供登錄和退出功能。實(shí)現(xiàn)登錄功能之后,就可以根據(jù)登錄狀態(tài)和當(dāng)前用戶的身份定制網(wǎng)站的內(nèi)容了。例如,本章我們會更新網(wǎng)站的頭部,顯示“登錄”或“退出”鏈接,以及到個(gè)人資料頁面的鏈接;在第十章中,會根據(jù)當(dāng)前登錄用戶的 id 創(chuàng)建關(guān)聯(lián)到這個(gè)用戶的微博;在第十一章,我們會實(shí)現(xiàn)當(dāng)前登錄用戶關(guān)注其他用戶的功能,實(shí)現(xiàn)之后,在首頁就可以顯示被關(guān)注用戶發(fā)表的微博了。

    實(shí)現(xiàn)登錄功能之后,還可以實(shí)現(xiàn)一種安全機(jī)制,即根據(jù)用戶的身份限制可以訪問的頁面,例如,在第九章中會介紹如何實(shí)現(xiàn)只有登入的用戶才能訪問編輯用戶資料的頁面。登錄系統(tǒng)還可以賦予管理員級別的用戶特別的權(quán)限,例如刪除用戶(也會在第九章中實(shí)現(xiàn))等。

    實(shí)現(xiàn)驗(yàn)證系統(tǒng)的核心功能之后,我們會簡要的介紹一下 Cucumber 這個(gè)流行的行為驅(qū)動開發(fā)(Behavior-driven Development, BDD)系統(tǒng),使用 Cucumber 重新實(shí)現(xiàn)之前的一些 RSpec 集成測試,看一下這兩種方式有何不同。

    和之前的章節(jié)一樣,我們會在一個(gè)新的從分支中工作,本章結(jié)束后再將其合并到主分支中:

    $ git checkout -b sign-in-out

    8.1 session 和登錄失敗

    [session](http://en.wikipedia.org/wiki/Session(computerscience)) 是兩臺電腦(例如運(yùn)行有網(wǎng)頁瀏覽器的客戶端電腦和運(yùn)行 Rails 的服務(wù)器)之間的半永久性連接,我們就是利用它來實(shí)現(xiàn)“登錄”這一功能的。網(wǎng)絡(luò)中常見的 session 處理方式有好幾種:可以在用戶關(guān)閉瀏覽器后清除 session;也可以提供一個(gè)“記住我”單選框讓用戶選擇永遠(yuǎn)保存,直到用戶退出后 session 才會失效。1?在示例程序中我們選擇使用第二種處理方式,即用戶登錄后,會永久的記住登錄狀態(tài),直到用戶點(diǎn)擊“退出”鏈接之后才清除 session。(在?8.2.1 節(jié)中會介紹“永久”到底有多久。)

    很顯然,我們可以把 session 視作一個(gè)符合 REST 架構(gòu)的資源,在登錄頁面中準(zhǔn)備一個(gè)新的 session,登錄后創(chuàng)建這個(gè) session,退出則會銷毀 session。不過 session 和 Users 資源有所不同,Users 資源使用數(shù)據(jù)庫(通過 User 模型)持久的存儲數(shù)據(jù),而 Sessions 資源是利用?cookie?來存儲數(shù)據(jù)的。cookie 是存儲在瀏覽器中的簡單文本。實(shí)現(xiàn)登錄功能基本上就是在實(shí)現(xiàn)基于 cookie 的驗(yàn)證機(jī)制。在本節(jié)及接下來的一節(jié)中,我們會構(gòu)建 Sessions 控制器,創(chuàng)建登錄表單,還會實(shí)現(xiàn)控制器中相關(guān)的動作。在?8.2 節(jié)中會加入處理 cookie 所需的代碼。

    8.1.1 Sessions 控制器

    登錄和退出功能其實(shí)是由 Sessions 控制器中相應(yīng)的動作處理的,登錄表單在?new?動作中處理(本節(jié)的內(nèi)容),登錄的過程就是向?create?動作發(fā)送?POST?請求(8.1 節(jié)和?8.2 節(jié)),退出則是向?destroy?動作發(fā)送?DELETE?請求(8.2.6 節(jié))。(HTTP 請求和 REST 動作之間的對應(yīng)關(guān)系可以查看表格 7.1。)首先,我們要生成 Sessions 控制器,以及驗(yàn)證系統(tǒng)所需的集成測試:

    $ rails generate controller Sessions --no-test-framework $ rails generate integration_test authentication_pages

    參照?7.2 節(jié)中的“注冊”頁面,我們要創(chuàng)建一個(gè)登錄表單,用來生成新的 session。注冊表單的構(gòu)思圖如圖 8.1 所示。

    “登錄”頁面的地址由?signin_path(稍后定義)獲取,和之前一樣,我們要先編寫相應(yīng)的測試,如代碼 8.1 所示。(可以和代碼 7.6 中對“注冊”頁面的測試比較一下。)

    圖 8.1:注冊表單的構(gòu)思圖

    代碼 8.1?對?new?動作和對應(yīng)視圖的測試
    spec/requests/authentication_pages_spec.rb

    require 'spec_helper'describe "Authentication" dosubject { page }describe "signin page" dobefore { visit signin_path }it { should have_selector('h1', text: 'Sign in') }it { should have_selector('title', text: 'Sign in') }end end

    現(xiàn)在測試是失敗的:

    $ bundle exec rspec spec/

    要讓代碼 8.1 中的測試通過,首先,我們要為 Sessions 資源設(shè)置路由,還要修改“登錄”頁面具名路由的名稱,將其映射到 Sessions 控制器的?new?動作上。和 Users 資源一樣,我們可以使用?resources?方法設(shè)置標(biāo)準(zhǔn)的 REST 動作:

    resources :sessions, only: [:new, :create, :destroy]

    因?yàn)槲覀儧]必要顯示或編輯 session,所以我們對動作的種類做了限制,為?resources?方法指定了?:only?選項(xiàng),只創(chuàng)建new、create?和?destroy?動作。最終的結(jié)果,包括登錄和退出具名路由的設(shè)置,如代碼 8.2 所示。

    代碼 8.2?設(shè)置 session 相關(guān)的路由
    config/routes.rb

    SampleApp::Application.routes.draw doresources :usersresources :sessions, only: [:new, :create, :destroy]match '/signup', to: 'users#new'match '/signin', to: 'sessions#new'match '/signout', to: 'sessions#destroy', via: :delete... end

    注意,設(shè)置退出路由那行使用了?via :delete,這個(gè)參數(shù)指明?destroy?動作要使用?DELETE?請求。

    代碼 8.2 中的路由設(shè)置會生成類似表格 7.1?所示的URI 地址和動作的對應(yīng)關(guān)系,如表格 8.1?所示。注意,我們修改了登錄和退出具名路由,而創(chuàng)建 session 的路由還是使用默認(rèn)值。

    HTTP 請求URI 地址具名路由動作目的
    GET/signinsignin_pathnew創(chuàng)建新 session 的頁面(登錄)
    POST/sessionssessions_pathcreate創(chuàng)建 session
    DELETE/signoutsignout_pathdestroy刪除 session(退出)

    表格 8.1:代碼 8.2 中的設(shè)置生成的符合 REST 架構(gòu)的路由關(guān)系

    為了讓代碼 8.1 中的測試通過,我們還要在 Sessions 控制器中加入?new?動作,相應(yīng)的代碼如代碼 8.3 所示(同時(shí)也定義了create?和?destroy?動作)。

    代碼 8.3?沒什么內(nèi)容的 Sessions 控制器
    app/controllers/sessions_controller.rb

    class SessionsController < ApplicationControllerdef newenddef createenddef destroyend end

    接下來還要創(chuàng)建“登錄”頁面的視圖,因?yàn)椤暗卿洝表撁娴哪康氖莿?chuàng)建新 session,所以創(chuàng)建的視圖位于app/views/sessions/new.html.erb。在視圖中我們要顯示網(wǎng)頁的標(biāo)題和一個(gè)一級標(biāo)頭,如代碼 8.4 所示。

    代碼 8.4?“登錄”頁面的視圖
    app/views/sessions/new.html.erb

    <% provide(:title, "Sign in") %> <h1>Sign in</h1>

    現(xiàn)在代碼 8.1 中的測試應(yīng)該可以通過了,接下來我們要編寫登錄表單。

    $ bundle exec rspec spec/

    8.1.2 測試登錄功能

    對比圖 8.1 和圖 7.11 之后,我們發(fā)現(xiàn)登錄表單和注冊表單外觀上差不多,只是少了兩個(gè)字段,只有 Email 地址和密碼字段。和注冊表單一樣,我們可以使用 Capybara 填寫表單,再點(diǎn)擊按鈕進(jìn)行測試。

    在測試的過程中,我們不得不向程序中加入相應(yīng)的功能,這也正是 TDD 帶來的好處之一。我們先來測試填寫不合法數(shù)據(jù)的登錄過程,構(gòu)思圖如圖 8.2 所示。

    圖 8.2:注冊失敗頁面的構(gòu)思圖

    從圖 8.2 我們可以看出,如果提交的數(shù)據(jù)不正確,我們會重新渲染“注冊”頁面,還會顯示一個(gè)錯(cuò)誤提示消息。這個(gè)錯(cuò)誤提示是 Flash 消息,我們可以通過下面的測試驗(yàn)證:

    it { should have_selector('div.alert.alert-error', text: 'Invalid') }

    (在第七章練習(xí)中的代碼 7.32 中出現(xiàn)過類似的代碼。)我們要查找的元素是:

    div.alert.alert-error

    前面介紹過,這里的點(diǎn)號代表 CSS 中的 class(參見?5.1.2 節(jié)),你也許猜到了,這里我們要查找的是同時(shí)具有?alert?和alert-error?class 的?div?元素。而且我們還檢測了錯(cuò)誤提示消息中是否包含了?"Invalid"?這個(gè)詞。所以,上述測試是檢測頁面中是否有下面這個(gè)元素的:

    <div class="alert alert-error">Invalid...</div>

    代碼 8.5 是針對標(biāo)題和 Flash 消息的測試。我們可以看出,這些代碼缺少了一個(gè)很重要的部分,會在?8.1.5 節(jié)中說明。

    代碼 8.5?登錄失敗時(shí)的測試
    spec/requests/authentication_pages_spec.rb

    require 'spec_helper'describe "Authentication" do...describe "signin" dobefore { visit signin_path }describe "with invalid information" dobefore { click_button "Sign in" }it { should have_selector('title', text: 'Sign in') }it { should have_selector('div.alert.alert-error', text: 'Invalid') }endend end

    測試了登錄失敗的情況,下面我們要測試登錄成功的情況了。我們要測試登錄成功后是否轉(zhuǎn)向了用戶資料頁面(從頁面的標(biāo)題判斷,標(biāo)題中應(yīng)該包含用戶的名字),還要測試網(wǎng)站的導(dǎo)航中是否有以下三個(gè)變化:

  • 出現(xiàn)了指向用戶資料頁面的鏈接
  • 出現(xiàn)了“退出”鏈接
  • “登錄”鏈接消失了
  • (對“設(shè)置(Settings)”鏈接的測試會在?9.1 節(jié)中實(shí)現(xiàn),對“所有用戶(Users)”鏈接的測試會在?9.3 節(jié)中實(shí)現(xiàn)。)如上變化的構(gòu)思圖如圖 8.3 所示。2注意,“退出”和“個(gè)人資料”鏈接位于“賬戶(Account)”下拉菜單中。在?8.2.4 節(jié)中會介紹如何通過 Bootstrap 實(shí)現(xiàn)這種下拉菜單。

    圖 8.3:登錄成功后顯示的用戶資料頁面構(gòu)思圖

    對登錄成功時(shí)的測試如代碼 8.6 所示。

    代碼 8.6?登錄成功時(shí)的測試
    spec/requests/authentication_pages_spec.rb

    require 'spec_helper'describe "Authentication" do...describe "signin" dobefore { visit signin_path }...describe "with valid information" dolet(:user) { FactoryGirl.create(:user) }before dofill_in "Email", with: user.emailfill_in "Password", with: user.passwordclick_button "Sign in"endit { should have_selector('title', text: user.name) }it { should have_link('Profile', href: user_path(user)) }it { should have_link('Sign out', href: signout_path) }it { should_not have_link('Sign in', href: signin_path) }endend end

    在代碼 8.6 中用到了?have_link?方法,它的第一參數(shù)是鏈接文本,第二個(gè)參數(shù)是可選的?:href,指定鏈接的地址,因此如下的代碼

    it { should have_link('Profile', href: user_path(user)) }

    確保了頁面中有一個(gè)?a?元素,鏈接到指定的 URI 地址。這里我們要檢測的是一個(gè)指向用戶資料頁面的鏈接。

    8.1.3 登錄表單

    寫完測試之后,我們就可以創(chuàng)建登錄表單了。在代碼 7.17 中,注冊表單使用了?form_for?幫助函數(shù),并指定其參數(shù)為?@user變量:

    <%= form_for(@user) do |f| %> . . . <% end %>

    注冊表單和登錄表單的區(qū)別在于,程序中沒有 Session 模型,因此也就沒有類似?@user?的變量。也就是說,在構(gòu)建登錄表單時(shí),我們要給?form_for?提供更多的信息。一般來說,如下的代碼

    form_for(@user)

    Rails 會自動向 /users 地址發(fā)送?POST?請求。對于登錄表單,我們則要明確的指定資源的名稱以及相應(yīng)的 URI 地址:

    form_for(:session, url: sessions_path)

    (創(chuàng)建表單還有另一種方法,不用?form_for,而用?form_tag。form_tag?也是 Rails 程序常用的方法,不過換用?form_tag?之后就和注冊表單有很多不同之處了,我現(xiàn)在是想使用相似的代碼構(gòu)建登錄表單。使用?form_tag?構(gòu)建登錄表單會留作練習(xí)(參見?8.5 節(jié))。)

    使用上述這種?form_for?形式,參照代碼 7.17 中的注冊表單,很容易的就能編寫一個(gè)符合圖 8.1 的登錄表單,如代碼 8.7 所示。

    代碼 8.7?注冊表單的代碼
    app/views/sessions/new.html.erb

    <% provide(:title, "Sign in") %> <h1>Sign in</h1><div class="row"> <div class="span6 offset3"> <%= form_for(:session, url: sessions_path) do |f| %> <%= f.label :email %> <%= f.text_field :email %> <%= f.label :password %> <%= f.password_field :password %> <%= f.submit "Sign in", class: "btn btn-large btn-primary" %> <% end %> <p>New user? <%= link_to "Sign up now!", signup_path %></p> </div> </div>

    注意,為了訪客的便利,我們還加入了到“注冊”頁面的鏈接。代碼 8.7 中的登錄表單效果如圖 8.4 所示。

    圖 8.4:登錄表單(/signup)

    用的多了你就不會老是查看 Rails 生成的 HTML(你會完全信任所用的幫助函數(shù)可以正確的完成任務(wù)),不過現(xiàn)在還是來看一下登錄表單的 HTML 吧(如代碼 8.8 所示)。

    代碼 8.8?代碼 8.7 中登錄表單生成的 HTML

    <form accept-charset="UTF-8" action="/sessions" method="post"><div><label for="session_email">Email</label><input id="session_email" name="session[email]" size="30" type="text" /></div><div><label for="session_password">Password</label><input id="session_password" name="session[password]" size="30"type="password" /></div><input class="btn btn-large btn-primary" name="commit" type="submit"value="Sign in" /> </form>

    你可以對比一下代碼 8.8 和代碼 7.20。你可能已經(jīng)猜到了,提交登錄表單后會生成一個(gè)?params?Hash,其中params[:session][:email]?和?params[:session][:password]?分別對應(yīng)了 Email 和密碼字段。

    8.1.4 分析表單提交

    和創(chuàng)建用戶類似,創(chuàng)建 session 時(shí)先要處理提交不合法數(shù)據(jù)的情況。我們已經(jīng)編寫了對提交不合法數(shù)據(jù)的測試(參見代碼 8.5),也添加了有幾處難理解但還算簡單的代碼讓測試通過了。下面我們就來分析一下表單提交的過程,然后為登錄失敗添加失敗提示信息(如圖 8.2)。最后,以此為基礎(chǔ),驗(yàn)證提交的 Email 和密碼,處理登錄成功的情況(參見?8.2 節(jié))。

    首先,我們來編寫 Sessions 控制器的?create?動作,如代碼 8.9 所示,現(xiàn)在只是直接渲染登錄頁面。在瀏覽器中訪問 /sessions/new,然后提交空表單,顯示的頁面如圖 8.5 所示。

    代碼 8.9?Sessions 控制器中?create?動作的初始版本
    app/controllers/sessions_controller.rb

    class SessionsController < ApplicationController...def createrender 'new'end... end

    圖 8.5:代碼 8.9 中的?create?動作顯示的登錄失敗后的頁面

    仔細(xì)看一下圖 8.5 中顯示的調(diào)試信息,你會發(fā)現(xiàn),如在?8.1.3 節(jié)末尾說過的,表單提交后會生成?params?Hash,Email 和密碼都在?:session?鍵中:

    --- session:email: ''password: '' commit: Sign in action: create controller: sessions

    和注冊表單類似,這些參數(shù)是一個(gè)嵌套的 Hash,在代碼 4.6 中見過。params?包含了如下的嵌套 Hash:

    { session: { password: "", email: "" } }

    也就是說

    params[:session]

    本身就是一個(gè) Hash:

    { password: "", email: "" }

    所以,

    params[:session][:email]

    就是提交的 Email 地址,而

    params[:session][:password]

    就是提交的密碼。

    也就是說,在?create?動作中,params?包含了使用 Email 和密碼驗(yàn)證用戶身份所需的全部數(shù)據(jù)。幸運(yùn)的是,我們已經(jīng)定義了身份驗(yàn)證過程中所需的兩個(gè)方法,即由 Active Record 提供的?User.find_by_email(參見?6.1.4 節(jié)),以及由has_secure_password?提供的?authenticate?方法(參見?6.3.3 節(jié))。我們之前介紹過,如果提交的數(shù)據(jù)不合法,authenticate?方法會返回?false。基于以上的分析,我們計(jì)劃按照如下的方式實(shí)現(xiàn)用戶登錄功能:

    def createuser = User.find_by_email(params[:session][:email].downcase)if user && user.authenticate(params[:session][:password])# Sign the user in and redirect to the user's show page.else# Create an error message and re-render the signin form.end end

    create?動作的第一行,使用提交的 Email 地址從數(shù)據(jù)庫中取出相應(yīng)的用戶。第二行是 Ruby 中經(jīng)常使用的語句形式:

    user && user.authenticate(params[:session][:password])

    我們使用?&&(邏輯與)檢測獲取的用戶是否合法。因?yàn)槌?nil?和?false?之外的所有對象都被視作?true,上面這個(gè)語句可能出現(xiàn)的結(jié)果如表格 8.2所示。我們可以從表格 8.2 中看出,當(dāng)且僅當(dāng)數(shù)據(jù)庫中存在提交的 Email 并提交了對應(yīng)的密碼時(shí),這個(gè)語句才會返回?true。

    用戶密碼a && b
    不存在任意值nil && [anything] == false
    存在錯(cuò)誤的密碼true && false == false
    存在正確的密碼true && true == true

    表格 8.2:user && user.authenticate(...)?可能出現(xiàn)的結(jié)果

    8.1.5 顯示 Flash 消息

    在?7.3.2 節(jié)中,我們使用 User 模型的數(shù)據(jù)驗(yàn)證信息來顯示注冊失敗時(shí)的提示信息。這些錯(cuò)誤提示信息是關(guān)聯(lián)在某個(gè) Active Record 對象上的,不過這種方式不可以用在 session 上,因?yàn)?session 不是 Active Record 模型。我們要采取的方法是,在登錄失敗時(shí),把錯(cuò)誤提示信息賦值給 Flash 消息。代碼 8.10 顯示的是我們首次嘗試實(shí)現(xiàn)這種方法所用的代碼,其中有個(gè)小小的錯(cuò)誤。

    代碼 8.10?嘗試處理登錄失敗(有個(gè)小小的錯(cuò)誤)
    app/controllers/sessions_controller.rb

    class SessionsController < ApplicationControllerdef newenddef createuser = User.find_by_email(params[:session][:email].downcase)if user && user.authenticate(params[:session][:password])# Sign the user in and redirect to the user's show page.elseflash[:error] = 'Invalid email/password combination' # Not quite right!render 'new'endenddef destroyend end

    布局中已經(jīng)加入了顯示 Flash 消息的局部視圖,所以無需其他修改,上述 Flash 錯(cuò)誤提示消息就會顯示出來,而且因?yàn)槭褂昧?Bootstrap,這個(gè)錯(cuò)誤消息的樣式也很美觀(如圖 8.6)。

    圖 8.6:登錄失敗后顯示的 Flash 消息

    不過,就像代碼 8.10 中的注釋所說,這些代碼還有問題。顯示的頁面看起來很正常啊,那么,問題出現(xiàn)在哪兒呢?問題的關(guān)鍵在于,Flash 消息在一個(gè)請求的生命周期內(nèi)是持續(xù)存在的,而重新渲染頁面(使用?render?方法)和代碼 7.27 中的轉(zhuǎn)向不同,它不算新的請求,你會發(fā)現(xiàn)這個(gè) Flash 消息存在的時(shí)間比設(shè)想的要長很多。例如,我們提交了不合法的登錄信息,Flash 消息生成了,然后在登錄頁面中顯示出來(如圖 8.6),這時(shí)如果我們點(diǎn)擊鏈接轉(zhuǎn)到其他頁面(例如“首頁”),這只算是表單提交后的第一次請求,所以頁面中還是會顯示 Flash 消息(如圖 8.7)。

    圖 8.7:仍然顯示有 Flash 消息的頁面

    Flash 消息沒有按預(yù)期消失算是程序的一個(gè) bug,在修正之前,我們最好編寫一個(gè)測試來捕獲這個(gè)錯(cuò)誤。現(xiàn)在,登錄失敗時(shí)的測試是可以通過的:

    $ bundle exec rspec spec/requests/authentication_pages_spec.rb \ > -e "signin with invalid information"

    不過程序中有錯(cuò)誤,測試應(yīng)該是失敗的,所以我們要編寫一個(gè)能夠捕獲這種錯(cuò)誤的測試。幸好,捕獲這種錯(cuò)誤正是集成測試的拿手好戲,所用的代碼如下:

    describe "after visiting another page" dobefore { click_link "Home" }it { should_not have_selector('div.alert.alert-error') } end

    提交不合法的登錄信息之后,這個(gè)測試用例會點(diǎn)擊網(wǎng)站中的“首頁”鏈接,期望顯示的頁面中沒有 Flash 錯(cuò)誤消息。添加上述測試用例的測試文件如代碼 8.11 所示。

    代碼 8.11?登錄失敗時(shí)的合理測試
    spec/requests/authentication_pages_spec.rb

    require 'spec_helper'describe "Authentication" do...describe "signin" dobefore { visit signin_path }describe "with invalid information" dobefore { click_button "Sign in" }it { should have_selector('title', text: 'Sign in') }it { should have_selector('div.alert.alert-error', text: 'Invalid') }describe "after visiting another page" dobefore { click_link "Home" }it { should_not have_selector('div.alert.alert-error') }endend...end end

    新添加的測試和預(yù)期一致,是失敗的:

    $ bundle exec rspec spec/requests/authentication_pages_spec.rb \ > -e "signin with invalid information"

    要讓這個(gè)測試通過,我們要用?flash.now?替換?flash。flash.now?就是專門用來在重新渲染的頁面中顯示 Flash 消息的,在發(fā)送新的請求之后,Flash 消息便會消失。正確的?create?動作代碼如代碼 8.12 所示。

    代碼 8.12?處理登錄失敗所需的正確代碼
    app/controllers/sessions_controller.rb

    class SessionsController < ApplicationControllerdef newenddef createuser = User.find_by_email(params[:session][:email].downcase)if user && user.authenticate(params[:session][:password])# Sign the user in and redirect to the user's show page.elseflash.now[:error] = 'Invalid email/password combination'render 'new'endenddef destroyend end

    現(xiàn)在登錄失敗時(shí)的所有測試應(yīng)該都可以通過了:

    $ bundle exec rspec spec/requests/authentication_pages_spec.rb \ > -e "with invalid information"

    8.2 登錄成功

    上一節(jié)處理了登錄失敗的情況,這一節(jié)我們要處理登錄成功的情況了。實(shí)現(xiàn)用戶登錄的過程是本書目前為止最考驗(yàn) Ruby 編程能力的部分,你要堅(jiān)持讀完本節(jié),做好心理準(zhǔn)備,付出大量的腦力勞動。幸好,第一步還算是簡單的,完成 Sessions 控制器的?create?動作沒什么難的,不過還是需要一點(diǎn)小技巧。

    我們需要把代碼 8.12 中處理登錄成功分支中的注釋換成具體的代碼,使用?sign_in?方法實(shí)現(xiàn)登錄操作,然后轉(zhuǎn)向用戶的資料頁面,如代碼 8.13 所示。這就是我們使用的技巧,使用還沒定義的方法?sign_in。本節(jié)后面的內(nèi)容會定義這個(gè)方法。

    代碼 8.13?完整的?create?動作代碼(還不能正常使用)
    app/controllers/sessions_controller.rb

    class SessionsController < ApplicationController...def createuser = User.find_by_email(params[:session][:email].downcase)if user && user.authenticate(params[:session][:password])sign_in userredirect_to userelseflash.now[:error] = 'Invalid email/password combination'render 'new'endend... end

    8.2.1 “記住我”

    現(xiàn)在我們要開始實(shí)現(xiàn)登錄功能了,第一步是實(shí)現(xiàn)“記住我”這個(gè)功能,即用戶登錄的狀態(tài)會被“永遠(yuǎn)”記住,直到用戶點(diǎn)擊“退出”鏈接為止。實(shí)現(xiàn)登錄功能用到的函數(shù)已經(jīng)超越了傳統(tǒng)的 MVC 架構(gòu),其中一些函數(shù)要同時(shí)在控制器和視圖中使用。在4.2.5 節(jié)中介紹過,Ruby 支持模塊(module)功能,打包一系列函數(shù),在不同的地方引入。我們會利用模塊來打包用戶身份驗(yàn)證相關(guān)的函數(shù)。我們當(dāng)然可以創(chuàng)建一個(gè)新的模塊,不過 Sessions 控制器已經(jīng)提供了一個(gè)名為?SessionsHelper?的模塊,而且這個(gè)模塊中的幫助方法會自動引入 Rails 程序的視圖中。所以,我們就直接使用這個(gè)現(xiàn)成的模塊,然后在 Application 控制器中引入,如代碼 8.14 所示。

    代碼 8.14?在 Application 控制器中引入 Sessions 控制器的幫助方法模塊
    app/controllers/application_controller.rb

    class ApplicationController < ActionController::Baseprotect_from_forgeryinclude SessionsHelper end

    默認(rèn)情況下幫助函數(shù)只可以在視圖中使用,不能在控制器中使用,而我們需要同時(shí)在控制器和視圖中使用幫助函數(shù),所以我們就手動引入幫助函數(shù)所在的模塊。

    因?yàn)?HTTP 是無狀態(tài)的協(xié)議,所以如果應(yīng)用程序需要實(shí)現(xiàn)登錄功能的話,就要找到一種方法記住用戶的狀態(tài)。維持用戶登錄狀態(tài)的方法之一,是使用常規(guī)的 Rails session(通過?session?函數(shù)),把用戶的 id 保存在“記憶權(quán)標(biāo)(remember token)”中:

    session[:remember_token] = user.id

    session?對象把用戶 id 保存在瀏覽器的 cookie 中,這樣在網(wǎng)站的所有頁面就都可以使用了。瀏覽器關(guān)閉后,cookie 也隨之失效。在網(wǎng)站中的任何頁面,只需調(diào)用?User.find(session[:remember_token])?就可以取回用戶對象了。Rails 在處理 session 時(shí),會確保安全性。倘若用戶企圖偽造用戶 id,Rails 可以通過每個(gè) session 的 session id 檢測到。

    根據(jù)示例程序的設(shè)計(jì)目標(biāo),我們計(jì)劃要實(shí)現(xiàn)的是持久保存的 session,即使瀏覽器關(guān)閉了,登錄狀態(tài)依舊存在,所以,登入的用戶要有一個(gè)持久保存的標(biāo)識符才行。為此,我們要為每個(gè)用戶生成一個(gè)唯一而安全的記憶權(quán)標(biāo),長期存儲,不會隨著瀏覽器的關(guān)閉而消失。

    記憶權(quán)標(biāo)要附屬到特定的用戶對象上,而且要保存起來以待后用,所以我們就可以把它設(shè)為 User 模型的屬性(如圖 8.8)。我們先來編寫 User 模型的測試,如代碼 8.15 所示。

    圖 8.8:User 模型,添加了?remember_token?屬性

    代碼 8.15?記憶權(quán)標(biāo)的第一個(gè)測試
    spec/models/user_spec.rb

    require 'spec_helper'describe User do...it { should respond_to(:password_confirmation) }it { should respond_to(:remember_token) }it { should respond_to(:authenticate) }... end

    要讓這個(gè)測試通過,我們要生成記憶權(quán)標(biāo)屬性,執(zhí)行如下命令:

    $ rails generate migration add_remember_token_to_users

    然后按照代碼 8.16 修改生成的遷移文件。注意,因?yàn)槲覀円褂糜洃洐?quán)標(biāo)取回用戶,所以我們?yōu)?remember_token?列加了索引(參見?旁注 6.2)。

    代碼 8.16?為?users?表添加?remember_token?列的遷移
    db/migrate/[timestamp]_add_remember_token_to_users.rb

    class AddRememberTokenToUsers < ActiveRecord::Migrationdef changeadd_column :users, :remember_token, :stringadd_index :users, :remember_tokenend end

    然后,還要更新“開發(fā)數(shù)據(jù)庫”和“測試數(shù)據(jù)庫”:

    $ bundle exec rake db:migrate $ bundle exec rake db:test:prepare

    現(xiàn)在,User 模型的測試應(yīng)該可以通過了:

    $ bundle exec rspec spec/models/user_spec.rb

    接下來我們要考慮記憶權(quán)標(biāo)要保存什么數(shù)據(jù),這有很多種選擇,其實(shí)任何足夠長的隨機(jī)字符串都是可以的。因?yàn)橛脩舻拿艽a是經(jīng)過加密處理的,所以原則上我們可以直接把用戶的?password_hash?值拿來用,不過這么做可能會把用戶的密碼暴露給潛在的攻擊者。以防萬一,我們還是用 Ruby 標(biāo)準(zhǔn)庫中?SecureRandom?模塊提供的?urlsafe_base64?方法來生成隨機(jī)字符串吧。urlsafe_base64?方法生成的是 Base64 字符串,可以放心的在 URI 中使用(因此也可以放心的在 cookie 中使用)。3寫作本書時(shí),SecureRandom.urlsafe_base64?創(chuàng)建的字符串長度為 16,由 A-Z、a-z、0-9、下劃線(_)和連字符(-)組成,每一位字符都有 64 種可能的情況,所以兩個(gè)記憶權(quán)標(biāo)相等的概率就是 1/6416=2-96≈10-29,完全可以忽略。

    我們會使用回調(diào)函數(shù)來創(chuàng)建記憶權(quán)標(biāo),回調(diào)函數(shù)在?6.2.5 節(jié)?中實(shí)現(xiàn) Email 屬性的唯一性驗(yàn)證時(shí)介紹過。和?6.2.5 節(jié)?中的用法一樣,我們還是要使用?before_save?回調(diào)函數(shù),在保存用戶之前創(chuàng)建?remember_token?的值。4要測試這個(gè)過程,我們可以先保存測試所需的用戶對象,然后檢查?remember_token?是否為非空值。這樣做,如果以后需要改變記憶權(quán)標(biāo)的生成方式,也無需修改測試。測試代碼如代碼 8.17 所示。

    代碼 8.17?測試合法的(非空)記憶權(quán)標(biāo)值
    spec/models/user_spec.rb

    require 'spec_helper'describe User dobefore do@user = User.new(name: "Example User", email: "user@example.com",password: "foobar", password_confirmation: "foobar")endsubject { @user }...describe "remember token" dobefore { @user.save }its(:remember_token) { should_not be_blank }end end

    代碼 8.17 中用到了?its?方法,它和?it?很像,不過測試對象是參數(shù)中指定的屬性而不是整個(gè)測試的對象。也就是說,如下的代碼:

    its(:remember_token) { should_not be_blank }

    等同于

    it { @user.remember_token.should_not be_blank }

    程序所需的代碼會涉及到一些新的知識。其一,我們添加了一個(gè)回調(diào)函數(shù)來生成記憶權(quán)標(biāo):

    before_save :create_remember_token

    當(dāng) Rails 執(zhí)行到這行代碼時(shí),會尋找一個(gè)名為?create_remember_token?的方法,在保存用戶之前執(zhí)行。其二,create_remember_token?只會在 User 模型內(nèi)部使用,所以沒必要把它開放給用戶之外的對象。在 Ruby 中,我們可以使用?private?關(guān)鍵字(譯者注:其實(shí)?private?是方法而不是關(guān)鍵字,請參閱《Ruby 編程語言》P233)限制方法的可見性:

    privatedef create_remember_token# Create the token.end

    在類中,private?之后定義的方法都會被設(shè)為私有方法,所以,如果執(zhí)行下面的操作

    $ rails console >> User.first.create_remember_token

    就會拋出?NoMethodError?異常。

    其三,在?create_remember_token?方法中,要給用戶的屬性賦值,需要在?remember_token?前加上?self?關(guān)鍵字:

    def create_remember_tokenself.remember_token = SecureRandom.urlsafe_base64 end

    (提示:如果你使用的是 Ruby 1.8.7,就要把?SecureRandom.urlsafe_base64?換成?SecureRandom_hex。)

    Active Record 是把模型的屬性和數(shù)據(jù)庫表中的列對應(yīng)的,如果不指定?self?的話,我們就只是創(chuàng)建了一個(gè)名為remember_token?的局部變量而已,這可不是我們期望得到的結(jié)果。加上?self?之后,賦值操作就會把值賦值給用戶的remember_token?屬性,保存用戶時(shí),隨著其他的屬性一起存入數(shù)據(jù)庫。

    把上述的分析結(jié)合起來,最終得到的 User 模型文件如代碼 8.18 所示。

    代碼 8.18?生成記憶權(quán)標(biāo)的?before_save?回調(diào)函數(shù)
    app/models/user.rb

    class User < ActiveRecord::Baseattr_accessible :name, :email, :password, :password_confirmationhas_secure_passwordbefore_save { |user| user.email = email.downcase }before_save :create_remember_token...privatedef create_remember_tokenself.remember_token = SecureRandom.urlsafe_base64end end

    順便說一下,我們?yōu)?create_remember_token?方法增加了一層縮進(jìn),這樣可以更好的突出這些方法是在?private?之后定義的。

    譯者注:如果按照 bbatsov 的《Ruby 編程風(fēng)格指南》(中譯版)來編寫 Ruby 代碼的話,就沒必要多加一層縮進(jìn)。

    因?yàn)?SecureRandom.urlsafe_base64?方法創(chuàng)建的字符串不可能為空值,所以對 User 模型的測試現(xiàn)在應(yīng)該可以通過了:

    $ bundle exec rspec spec/models/user_spec.rb

    8.2.2 定義?sign_in?方法

    本小節(jié)我們要開始實(shí)現(xiàn)登錄功能了,首先來定義?sign_in?方法。上一小節(jié)已經(jīng)說明了,我們計(jì)劃實(shí)現(xiàn)的身份驗(yàn)證方式是,在用戶的瀏覽器中存儲記憶權(quán)標(biāo),在網(wǎng)站的頁面與頁面之間通過這個(gè)記憶權(quán)標(biāo)獲取數(shù)據(jù)庫中的用戶記錄(會在?8.2.3 節(jié)實(shí)現(xiàn))。實(shí)現(xiàn)這一設(shè)想所需的代碼如代碼 8.19 所示,這段代碼使用了兩個(gè)新內(nèi)容:cookies?Hash 和?current_user?方法。

    代碼 8.19?完整但還不能正常使用的?sign_in?方法
    app/helpers/sessions_helper.rb

    module SessionsHelperdef sign_in(user)cookies.permanent[:remember_token] = user.remember_tokenself.current_user = userend end

    上述代碼中用到的?cookies?方法是由 Rails 提供的,我們可以把它看成 Hash,其中每個(gè)元素又都是一個(gè) Hash,包含兩個(gè)元素,value?指定 cookie 的文本,expires?指定 cookie 的失效日期。例如,我們可以使用下述代碼實(shí)現(xiàn)登錄功能,把 cookie 的值設(shè)為用戶的記憶權(quán)標(biāo),失效日期設(shè)為 20 年之后:

    cookies[:remember_token] = { value: user.remember_token,expires: 20.years.from_now.utc }

    (這里使用了 Rails 提供的時(shí)間幫助方法,詳情參見旁注 8.1。)

    旁注 8.1 cookie 在?20.years.from_now?之后失效

    在?4.4.2 節(jié)中介紹過,你可以向任何的 Ruby 類,甚至是內(nèi)置的類中添加自定義的方法,我們就向?String?類添加了palindrome??方法(而且還發(fā)現(xiàn)了?"deified"?是回文)。我們還介紹過,Rails 為?Object?類添加了?blank??方法(所以,"".blank?、" ".blank??和?nil.blank??的返回值都是?true)。代碼 8.19 中處理 cookie 的代碼又是一例,使用了 Rails 提供的時(shí)間幫助方法,這些方法是添加到 `Fixnum` 類(數(shù)字的基類)中的。

    $ rails console>> 1.year.from_now=> Sun, 13 Mar 2011 03:38:55 UTC +00:00>> 10.weeks.ago=> Sat, 02 Jan 2010 03:39:14 UTC +00:00

    Rails 還添加了其他的幫助函數(shù),如:

    >> 1.kilobyte=> 1024>> 5.megabytes=> 5242880

    這幾個(gè)幫助函數(shù)可用于限制上傳文件的大小,例如,圖片最大不超過?5.megabytes。

    這種為內(nèi)置類添加方法的特性很靈便,可以擴(kuò)展 Ruby 的功能,不過使用時(shí)要小心一些。其實(shí) Rails 的很多優(yōu)雅之處正式基于 Ruby 語言的這一特性。

    因?yàn)殚_發(fā)者經(jīng)常要把 cookie 的失效日期設(shè)為 20 年后,所以 Rails 特別提供了?permanent?方法,前面處理 cookie 的代碼可以改寫成:

    cookies.permanent[:remember_token] = user.remember_token

    Rails 的?permanent?方法會自動把 cookie 的失效日期設(shè)為 20 年后。

    設(shè)定了 cookie 之后,在網(wǎng)頁中我們就可以使用下面的代碼取回用戶:

    User.find_by_remember_token(cookies[:remember_token])

    其實(shí)瀏覽器中保存的 cookie 并不是 Hash,賦值給?cookies?只是把值以文本的形式保存在瀏覽器中。這正體現(xiàn)了 Rails 的智能,我們無需關(guān)心具體的處理細(xì)節(jié),專注地實(shí)現(xiàn)應(yīng)用程序的功能。

    你可能聽說過,存儲在用戶瀏覽器中的驗(yàn)證 cookie 在和服務(wù)器通訊時(shí)可能會導(dǎo)致程序被會話劫持,攻擊者只需復(fù)制記憶權(quán)標(biāo)就可以偽造成相應(yīng)的用戶登錄網(wǎng)站了。Firesheep 這個(gè) Firefox 擴(kuò)展可以查看會話劫持,你會發(fā)現(xiàn)很多著名的大網(wǎng)站(包括 Facebook 和 Twitter)都存在這種漏洞。避免這個(gè)漏洞的方法就是整站開啟 SSL,詳情參見?7.4.4 節(jié)。

    8.2.3 獲取當(dāng)前用戶

    上一小節(jié)已經(jīng)介紹了如何在 cookie 中存儲記憶權(quán)標(biāo)以待后用,這一小節(jié)我們要看一下如何取回用戶。我們先回顧一下sign_in?方法:

    module SessionsHelperdef sign_in(user)cookies.permanent[:remember_token] = user.remember_tokenself.current_user = userend end

    現(xiàn)在我們關(guān)注的是方法定義體中的第二行代碼:

    self.current_user = user

    這行代碼創(chuàng)建了?current_user?方法,可以在控制器和視圖中使用,所以你既可以這樣用:

    <%= current_user.name %>

    也可以這樣用:

    redirect_to current_user

    這行代碼中的?self?也是必須的,原因在分析代碼 8.18 時(shí)已經(jīng)說過,如果沒有?self,Ruby 只是定義了一個(gè)名為current_user?的局部變量。

    在開始編寫?current_user?方法的代碼之前,請仔細(xì)看這行代碼:

    self.current_user = user

    這是一個(gè)賦值操作,我們必須先定義相應(yīng)的方法才能這么用。Ruby 為這種賦值操作提供了一種特別的定義方式,如代碼 8.20 所示。

    代碼 8.20?實(shí)現(xiàn)?current_user?方法對應(yīng)的賦值操作
    app/helpers/sessions_helper.rb

    module SessionsHelperdef sign_in(user)...enddef current_user=(user)@current_user = userend end

    這段代碼看起來很奇怪,因?yàn)榇蠖鄶?shù)的編程語言并不允許在方法名中使用等號。其實(shí)這段代碼定義的?current_user=?方法是用來處理?current_user?賦值操作的。也就是說,如下的代碼

    self.current_user = ...

    會自動轉(zhuǎn)換成下面這種形式

    current_user=(...)

    就是直接調(diào)用?current_user=?方法,接受的參數(shù)是賦值語句右側(cè)的值,本例中是要登錄的用戶對象。current_user=?方法定義體內(nèi)只有一行代碼,即設(shè)定實(shí)例變量?@current_user?的值,以備后用。

    在常見的 Ruby 代碼中,我們還會定義?current_user?方法,用來讀取?@current_user?的值,如代碼 8.21 所示。

    代碼 8.21?嘗試定義?current_user?方法,不過我們不會使用這種方式

    module SessionsHelperdef sign_in(user)...enddef current_user=(user)@current_user = userenddef current_user@current_user # Useless! Don't use this line.end end

    上面的做法其實(shí)就是實(shí)現(xiàn)了?attr_accessor?方法的功能(4.4.5 節(jié)介紹過)。5如果按照代碼 8.21 來定義?current_user?方法,會出現(xiàn)一個(gè)問題:程序不會記住用戶的登錄狀態(tài)。一旦用戶轉(zhuǎn)到其他的頁面,session 就失效了,會自動退出。若要避免這個(gè)問題,我們要使用代碼 8.19 中生成的記憶權(quán)標(biāo)查找用戶,如代碼 8.22 所示。

    代碼 8.22?通過記憶權(quán)標(biāo)查找當(dāng)前用戶
    app/helpers/sessions_helper.rb

    module SessionsHelper...def current_user=(user)@current_user = userenddef current_user@current_user ||= User.find_by_remember_token(cookies[:remember_token])end end

    代碼 8.22 中使用了一個(gè)常見但不是很容易理解的?||=(“or equals”)操作符(旁注 8.2中有詳細(xì)介紹)。使用這個(gè)操作符之后,當(dāng)且僅當(dāng)?@current_user?未定義時(shí)才會把通過記憶權(quán)標(biāo)獲取的用戶賦值給實(shí)例變量?@current_user。6也就是說,如下的代碼

    @current_user ||= User.find_by_remember_token(cookies[:remember_token])

    只在第一次調(diào)用?current_user?方法時(shí)調(diào)用?find_by_remember_token?方法,如果后續(xù)再調(diào)用的話就直接返回?@current_user的值,而不必再查詢數(shù)據(jù)庫。7這種方式的優(yōu)點(diǎn)只有當(dāng)在一個(gè)請求中多次調(diào)用?current_user?方法時(shí)才能顯現(xiàn)。不管怎樣,只要用戶訪問了相應(yīng)的頁面,find_by_remember_token?方法都至少會執(zhí)行一次。

    旁注 8.2?||=?操作符簡介

    ||=?操作符非常能夠體現(xiàn) Ruby 的特性,如果你打算長期進(jìn)行 Ruby 編程的話就要好好學(xué)習(xí)它的用法。初學(xué)時(shí)會覺得||=?很神秘,不過通過和其他操作符類比之后,你會發(fā)現(xiàn)也不是很難理解。

    我們先來看一下改變已經(jīng)定義的變量時(shí)經(jīng)常使用的結(jié)構(gòu)。在很多程序中都會把變量自增一,如下所示

    x = x + 1

    大多數(shù)語言都為這種操作提供了簡化的操作符,在 Ruby 中,可以按照下面的方式重寫(C、C++、Perl、Python、Java 等也如此):

    x += 1

    其他操作符也有類似的簡化形式:

    $ rails console>> x = 1=> 1>> x += 1=> 2>> x *= 3=> 6>> x -= 7=> -1

    上面的舉例可以概括為,x = x O y?和?x O=y?是等效的,其中?O?表示操作符。

    在 Ruby 中還經(jīng)常會遇到這種情況,如果變量的值為 `nil` 則賦予其他的值,否則就不改變這個(gè)變量的值。[4.2.3 節(jié)](chapter4.html#sec-4-2-3) 中介紹過?||?或操作符,所以這種情況可以用如下的代碼表示:

    >> @user=> nil>> @user = @user || "the user"=> "the user">> @user = @user || "another user"=> "the user"

    因?yàn)?nil?表示的布爾值是?false,所以第一個(gè)賦值操作等同于?nil || "the user",這個(gè)語句的計(jì)算結(jié)果是?"the user";類似的,第二個(gè)賦值操作等同于?"the user" || "another user",這個(gè)語句的計(jì)算結(jié)果還是?"the user",因?yàn)?"the user"?表示的布爾值是?true,這個(gè)或操作在執(zhí)行了第一個(gè)表達(dá)式之后就終止了。(或操作的執(zhí)行順序是從左至右,只要出現(xiàn)真值就會終止語句的執(zhí)行,這種方式稱作“短路計(jì)算(short-circuit evaluation)”。)

    和上面的控制臺會話對比之后,我們可以發(fā)現(xiàn)?@user = @user || value?符合?x = x O y?的形式,只需把?O?換成?||,所以就得到了下面這種簡寫形式:

    >> @user ||= "the user"=> "the user"

    不難理解吧!

    譯者注:這里對?||=?的分析和 Peter Cooper 的分析有點(diǎn)差異,我推薦你看以下 Ruby Inside 中的《What Ruby’s ||= (Double Pipe / Or Equals) Really Does》一文。

    8.2.4 改變導(dǎo)航鏈接

    本小節(jié)我們要完成的是實(shí)現(xiàn)登錄、退出功能的最后一步,根據(jù)登錄狀態(tài)改變布局中的導(dǎo)航鏈接。如圖 8.3 所示,我們要在登錄和退出后顯示不同的導(dǎo)航,要添加指向列出所有用戶頁面的鏈接、到用戶設(shè)置頁面的鏈接(第九章加入),還有到當(dāng)前登錄用戶資料頁面的鏈接。加入這些鏈接之后,代碼 8.6 中的測試就可以通過了,這是本章目前為止測試首次變綠通過。

    在網(wǎng)站的布局中改變導(dǎo)航鏈接需要用到 ERb 的 if-else 分支結(jié)構(gòu):

    <% if signed_in? %> # Links for signed-in users <% else %> # Links for non-signed-in-users <% end %>

    若要上述代碼起作用,先要用?signed_in??方法。我們現(xiàn)在就來定義。

    如果 session 中存有當(dāng)前用戶的話,就可以說用戶已經(jīng)登錄了。我們要判斷?current_user?的值是不是?nil,這里需要用到取反操作符,用感嘆號 ! 表示,一般讀作“bang”。只要?current_user?的值不是?nil,就說明用戶登錄了,如代碼 8.23 所示。

    代碼 8.23?定義?signed_in??幫助方法
    app/helpers/sessions_helper.rb

    module SessionsHelperdef sign_in(user)cookies.permanent[:remember_token] = user.remember_tokenself.current_user = userenddef signed_in?!current_user.nil?end... end

    定義了?signed_in??方法后就可以著手修改布局中的導(dǎo)航了。我們要添加四個(gè)新鏈接,其中兩個(gè)鏈接的地址先不填(第九章再填):

    <%= link_to "Users", '#' %> <%= link_to "Settings", '#' %>

    退出鏈接的地址使用代碼 8.2 中定義的?signout_path:

    <%= link_to "Sign out", signout_path, method: "delete" %>

    (注意,我們還為退出鏈接指定了類型為 Hash 的參數(shù),指明點(diǎn)擊鏈接后發(fā)送的是 HTTP?DELETE?請求。8)最后,我們還要添加一個(gè)到資料頁面的鏈接:

    <%= link_to "Profile", current_user %>

    這個(gè)鏈接我們本可以寫成

    <%= link_to "Profile", user_path(current_user) %>

    不過我們可以直接把鏈接地址設(shè)為?current_user,Rails 會自動將其轉(zhuǎn)換成?user_path(current_user)。

    在添加導(dǎo)航鏈接的過程中,我們還要使用 Bootstrap 實(shí)現(xiàn)下拉菜單的效果,具體的實(shí)現(xiàn)方式可以參閱 Bootstrap 的文檔。添加導(dǎo)航鏈接所需的代碼如代碼 8.24 所示。注意其中和 Bootstrap 下拉菜單有關(guān)的 CSS id 和 class。

    代碼 8.24?根據(jù)登錄狀態(tài)改變導(dǎo)航鏈接
    app/views/layouts/_header.html.erb

    <header class="navbar navbar-fixed-top"> <div class="navbar-inner"> <div class="container"> <%= link_to "sample app", root_path, id: "logo" %> <nav> <ul class="nav pull-right"> <li><%= link_to "Home", root_path %></li> <li><%= link_to "Help", help_path %></li> <% if signed_in? %> <li><%= link_to "Users", '#' %></li> <li id="fat-menu" class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown"> Account <b class="caret"></b> </a> <ul class="dropdown-menu"> <li><%= link_to "Profile", current_user %></li> <li><%= link_to "Settings", '#' %></li> <li class="divider"></li> <li> <%= link_to "Sign out", signout_path, method: "delete" %> </li> </ul> </li> <% else %> <li><%= link_to "Sign in", signin_path %></li> <% end %> </ul> </nav> </div> </div> </header>

    實(shí)現(xiàn)下拉菜單還要用到 Bootstrap 中的 JavaScript 代碼,我們可以編輯應(yīng)用程序的 JavaScript 文件,通過 asset pipeline 引入所需的文件,如代碼 8.25 所示。

    代碼 8.25?把 Bootstrap 的 JavaScript 代碼加入?application.js
    app/assets/javascripts/application.js

    //= require jquery //= require jquery_ujs //= require bootstrap //= require_tree .

    引入文件的功能是由 Sprockets 實(shí)現(xiàn)的,而文件本身是由?5.1.2 節(jié)中添加的?bootstrap-sass?gem 提供的。

    添加了代碼 8.24 之后,所有的測試應(yīng)該都可以通過了:

    $ bundle exec rspec spec/

    不過,如果你在瀏覽器中查看的話,網(wǎng)站還不能正常使用。這是因?yàn)椤坝涀∥摇边@個(gè)功能要求用戶記錄的記憶權(quán)標(biāo)屬性不為空,而現(xiàn)在這個(gè)用戶是在?7.4.3 節(jié)中創(chuàng)建的,遠(yuǎn)在實(shí)現(xiàn)生成記憶權(quán)標(biāo)的回調(diào)函數(shù)之前,所以記憶權(quán)標(biāo)還沒有值。為了解決這個(gè)問題,我們要再次保存用戶,觸發(fā)代碼 8.18 中的?before_save?回調(diào)函數(shù),生成用戶的記憶權(quán)標(biāo):

    $ rails console >> User.first.remember_token => nil >> User.all.each { |user| user.save(validate: false) } >> User.first.remember_token => "Im9P0kWtZvD0RdyiK9UHtg"

    我們遍歷了數(shù)據(jù)庫中的所有用戶,以防之前創(chuàng)建了多個(gè)用戶。注意,我們向?save?方法傳入了一個(gè)參數(shù)。如果不指定這個(gè)參數(shù)的話,就無法保存,因?yàn)槲覀儧]有指定密碼及密碼確認(rèn)的值。在實(shí)際的網(wǎng)站中,我們根本就無法獲知用戶的密碼,但是我們還是要執(zhí)行保存操作,這時(shí)就要指定?validate: false?參數(shù)跳過 Active Record 的數(shù)據(jù)驗(yàn)證(更多內(nèi)容請閱讀 Rails API 中關(guān)于 save 的文檔)。

    做了上述修正之后,登錄的用戶就可以看到代碼 8.24 中添加的新鏈接和下拉菜單了,如圖 8.9 所示。

    圖 8.9:登錄后顯示了新鏈接和下拉菜單

    現(xiàn)在你可以驗(yàn)證一下是否可以登錄,然后關(guān)閉瀏覽器,再打開看一下是否還是登入的狀態(tài)。如果需要,你還可以直接查看瀏覽器的 cookies,如圖 8.10 所示。

    圖 8.10:查看瀏覽器中的記憶權(quán)標(biāo) cookie

    8.2.5 注冊后直接登錄

    雖然現(xiàn)在基本完成了用戶身份驗(yàn)證功能,但是新注冊的用戶可能還是會困惑,為什么注冊后沒有登錄呢。在實(shí)現(xiàn)退出功能之前,我們還要實(shí)現(xiàn)注冊后直接登錄的功能。我們要先編寫測試,在身份驗(yàn)證的測試中加入一行代碼,如代碼 8.26 所示。這段代碼要用到第七章一個(gè)練習(xí)中的“after saving the user”?describe?塊(參見代碼 7.32),如果之前你沒有做這個(gè)練習(xí)的話,現(xiàn)在請?zhí)砑酉鄳?yīng)的測試代碼。

    代碼 8.26?測試剛注冊的用戶是否會自動登錄
    spec/requests/user_pages_spec.rb

    require 'spec_helper'describe "User pages" do...describe "with valid information" do...describe "after saving the user" do...it { should have_link('Sign out') }endend end

    我們檢測頁面中有沒有退出鏈接,來驗(yàn)證用戶注冊后是否登錄了。

    有了?8.2 節(jié)中定義的?sign_in?方法,要讓這個(gè)測試通過就很簡單了:在用戶保存到數(shù)據(jù)庫中之后加上?sign_in @user?就可以了,如代碼 8.27 所示。

    代碼 8.27?用戶注冊后直接登錄
    app/controllers/users_controller.rb

    class UsersController < ApplicationController...def create@user = User.new(params[:user])if @user.savesign_in @userflash[:success] = "Welcome to the Sample App!"redirect_to @userelserender 'new'endend end

    8.2.6 退出

    在?8.1 節(jié)中介紹過,我們要實(shí)現(xiàn)的身份驗(yàn)證機(jī)制會記住用戶的登錄狀態(tài),直到用戶點(diǎn)擊退出鏈接為止。本小節(jié),我們就要實(shí)現(xiàn)退出功能。

    目前為止,Sessions 控制器的動作完全遵從了 REST 架構(gòu),new?動作用于登錄頁面,create?動作實(shí)現(xiàn)登錄的過程。我們還要添加一個(gè)?destroy?動作,刪除 session,實(shí)現(xiàn)退出功能。針對退出功能的測試,我們可以檢測點(diǎn)擊退出鏈接后,頁面中是否有登錄鏈接,如代碼 8.28 所示。

    代碼 8.28?測試用戶退出
    spec/requests/authentication_pages_spec.rb

    require 'spec_helper'describe "Authentication" do...describe "signin" do...describe "with valid information" do...describe "followed by signout" dobefore { click_link "Sign out" }it { should have_link('Sign in') }endendend end

    登錄功能是由?sign_in?方法實(shí)現(xiàn)的,對應(yīng)的,我們會使用?sign_out?方法實(shí)現(xiàn)退出功能,如代碼 8.29 所示。

    代碼 8.29?銷毀 session,實(shí)現(xiàn)退出功能
    app/controllers/sessions_controller.rb

    class SessionsController < ApplicationController...def destroysign_outredirect_to root_pathend end

    和其他身份驗(yàn)證相關(guān)的方法一樣,我們會在 Sessions 控制器的幫助方法模塊中定義?sign_out?方法。方法本身的實(shí)現(xiàn)很簡單,我們先把當(dāng)前用戶設(shè)為?nil,然后在 cookies 上調(diào)用?delete?方法從 session 中刪除記憶權(quán)標(biāo),如代碼 8.30 所示。(其實(shí)這里沒必要把當(dāng)前用戶設(shè)為?nil,因?yàn)樵?destroy?動作中我們加入了轉(zhuǎn)向操作。這里我們之所以這么做是為了兼容不轉(zhuǎn)向的退出操作。)

    代碼 8.30?Sessions 幫助方法模塊中定義的?sign_out?方法
    app/helpers/sessions_helper.rb

    module SessionsHelperdef sign_in(user)cookies.permanent[:remember_token] = user.remember_tokenself.current_user = userend...def sign_outself.current_user = nilcookies.delete(:remember_token)end end

    現(xiàn)在,注冊、登錄和退出三個(gè)功能都實(shí)現(xiàn)了,測試也應(yīng)該可以通過了:

    $ bundle exec rspec spec/

    有一點(diǎn)需要注意,我們的測試覆蓋了身份驗(yàn)證機(jī)制的大多數(shù)功能,但不是全部。例如,我們沒有測試“記住我”到底記住了多久,也沒測試是否設(shè)置了記憶權(quán)標(biāo)。我們當(dāng)然可以加入這些測試,不過經(jīng)驗(yàn)告訴我們,直接測試 cookie 的值不可靠,而且要依賴具體的實(shí)現(xiàn)細(xì)節(jié),而實(shí)現(xiàn)的方法在不同的 Rails 版本中可能會有所不同,即便應(yīng)用程序可以使用,測試卻會失敗。所以我們只關(guān)注抽象的功能(驗(yàn)證用戶是否可以登錄,是否可以保持登錄狀態(tài),以及是否可以退出),編寫的測試沒必要針對實(shí)現(xiàn)的細(xì)節(jié)。

    8.3 Cucumber 簡介(選讀)

    前面兩節(jié)基本完成了示例程序的身份驗(yàn)證系統(tǒng),這一節(jié)我們將介紹如何使用 Cucumber 編寫登錄測試。Cucumber 是一個(gè)流行的行為驅(qū)動開發(fā)(Behavior-driven Development, BDD)工具,在 Ruby 社區(qū)中占據(jù)著一定的地位。本節(jié)的內(nèi)容是選讀的,你可以直接跳過,不會影響后續(xù)內(nèi)容。

    Cucumber 使用純文本的故事(story)描述應(yīng)用程序的行為,很多 Rails 開發(fā)者發(fā)現(xiàn)使用 Cucumber 處理客戶案例時(shí)十分方便,因?yàn)榉羌夹g(shù)人員也能讀懂這些行為描述,Cucumber 測試可以用于和客戶溝通,甚至經(jīng)常是由客戶來編寫的。當(dāng)然,使用不是純 Ruby 代碼組成的測試框架有它的局限性,而且我還發(fā)現(xiàn)純文本的故事很啰嗦。不管怎樣,Cucumber 在 Ruby 測試工具中還是有其存在意義的,我特別欣賞它對抽象行為的關(guān)注,而不是死盯底層的具體實(shí)現(xiàn)。

    因?yàn)楸緯亟榻B的是 RSpec 和 Capybara,所以本節(jié)對 Cucumber 的介紹很淺顯,也不完整,很多內(nèi)容都沒做詳細(xì)說明,我只是想讓你體驗(yàn)一下如何使用 Cucumber,如果你感覺不錯(cuò),可以閱讀專門介紹 Cucumber 的書籍深入學(xué)習(xí)。(一般我會推薦你閱讀 David Chelimsky 的《The RSpec Book》,Ryan Bigg 和 Yehuda Katz 的《Rails 3 in Action》,以及 Matt Wynne 和 Aslak Helles?y 的《The Cucumber Book》。)

    8.3.1 安裝和設(shè)置

    若要安裝 Cucumber,需要在?Gemfile?的?:test?組中加入?cucumber-rails?和?database_cleaner?這兩個(gè) gem,如代碼 8.31 所示。

    代碼 8.31?在?Gemfile?中加入?cucumber-rails

    . . . group :test do...gem 'cucumber-rails', '1.2.1', require: falsegem 'database_cleaner', '0.7.0' end . . .

    然后和之前一樣運(yùn)行一下命令安裝:

    $ bundle install

    如果要在程序中使用 Cucumber,我們先要生成一些所需的文件和文件夾:

    $ rails generate cucumber:install

    這個(gè)命令會在根目錄中創(chuàng)建?features?文件夾,Cucumber 相關(guān)的文件都會存在這個(gè)文件夾中。

    8.3.2 功能和步驟定義

    Cucumber 中的“功能(feature)”就是希望應(yīng)用程序?qū)崿F(xiàn)的行為,使用一種名為 Gherkin 的純文本語言編寫。使用 Gherkin 編寫的測試和寫的很好的 RSpec 測試用例差不多,不過因?yàn)?Gherkin 是純文本,所以特別適合那些不是很懂 Ruby 代碼而可以理解英語的人使用。

    下面我們要編寫一些 Cucumber 功能,實(shí)現(xiàn)代碼 8.5 和代碼 8.6 中針對登錄功能的部分測試用例。首先,我們在?features文件夾中新建名為?signing_in.feature?的文件。

    Cucumber 的功能由一個(gè)簡短的描述文本開始,如下所示:

    Feature: Signing in

    然后再添加一定數(shù)量相對獨(dú)立的場景(scenario)。例如,要測試登錄失敗的情況,我們可以按照如下的方式編寫場景:

    Scenario: Unsuccessful signin Given a user visits the signin page When he submits invalid signin information Then he should see an error message

    類似的,測試登錄成功時(shí),我們可以加入如下的場景:

    Scenario: Successful signin Given a user visits the signin page And the user has an account And the user submits valid signin information Then he should see his profile page And he should see a signout link

    把上述的文本放在一起,就組成了代碼 8.32 所示的 Cucumber 功能文件。

    代碼 8.32?測試用戶登錄功能
    features/signing_in.feature

    Feature: Signing in Scenario: Unsuccessful signin Given a user visits the signin page When he submits invalid signin information Then he should see an error message Scenario: Successful signin Given a user visits the signin page And the user has an account And the user submits valid signin information Then he should see his profile page And he should see a signout link

    然后使用?cucumber?命令運(yùn)行這個(gè)功能:

    $ bundle exec cucumber features/

    上述命令和執(zhí)行 RSpec 測試的命令類似:

    $ bundle exec rspec spec/

    提示一下,Cucumber 和 RSpec 一樣,可以通過 Rake 命令執(zhí)行:

    $ bundle exec rake cucumber

    (鑒于某些原因,我經(jīng)常使用的命令是?rake cucumber:ok。)

    我們只是寫了一些純文本,所以毫不意外,Cucumber 場景現(xiàn)在不會通過。若要讓測試通過,我們要新建一個(gè)步驟定義文件,把場景中的純文本和 Ruby 代碼對應(yīng)起來。步驟定義文件存放在?features/step_definition?文件夾中,我們要將其命名為?authentication_steps.rb。

    以?Feature?和?Scenario?開頭的行基本上只被視作文檔,其他的行則都要和 Ruby 代碼對應(yīng)。例如,功能文件中下面這行

    Given a user visits the signin page

    對應(yīng)到步驟定義中的

    Given /?a user visits the signin page$/ dovisit signin_path end

    在功能文件中,Given?只是普通的字符串,而在步驟定義中?Given?則是一個(gè)方法,可以接受一個(gè)正則表達(dá)式作為參數(shù),后面還可以跟著一個(gè)塊。Given?方法的正則表達(dá)式參數(shù)是用來匹配功能文件中某個(gè)特定行的,塊中的代碼則是實(shí)現(xiàn)描述的行為所需的 Ruby 代碼。本例中的“a user visits the signin page”是由下面這行代碼實(shí)現(xiàn)的:

    visit signin_path

    你可能覺得這行代碼很眼熟,不錯(cuò),這就是前面用過的 Capybara 提供的方法,Cucumber 的步驟定義文件會自動引入 Capybara。接下來的兩行代碼實(shí)現(xiàn)也同樣眼熟。如下的場景步驟:

    When he submits invalid signin information Then he should see an error message

    對應(yīng)到步驟定義文件中的

    When /?he submits invalid signin information$/ doclick_button "Sign in" endThen /?he should see an error message$/ dopage.should have_selector('div.alert.alert-error') end

    上面這段代碼的第一步還是用了 Capybara,第二步則結(jié)合了 Capybara 的?page?和 RSpec。很明顯,之前我們使用 RSpec 和 Capybara 編寫的測試,在 Cucumber 中也是有用武之地的。

    場景中接下來的步驟也可以做類似的處理。最終的步驟定義文件如代碼 8.33 所示。你可以一次只添加一個(gè)步驟,然后執(zhí)行下面的代碼,直到測試都通過為止:

    $ bundle exec cucumber features/

    代碼 8.33?使登錄功能通過的步驟定義
    features/step_definitions/authentication_steps.rb

    Given /?a user visits the signin page$/ dovisit signin_path endWhen /?he submits invalid signin information$/ doclick_button "Sign in" endThen /?he should see an error message$/ dopage.should have_selector('div.alert.alert-error') endGiven /?the user has an account$/ do@user = User.create(name: "Example User", email: "user@example.com",password: "foobar", password_confirmation: "foobar") endWhen /?the user submits valid signin information$/ dofill_in "Email", with: @user.emailfill_in "Password", with: @user.passwordclick_button "Sign in" endThen /?he should see his profile page$/ dopage.should have_selector('title', text: @user.name) endThen /?he should see a signout link$/ dopage.should have_link('Sign out', href: signout_path) end

    添加了代碼 8.33,Cucumber 測試應(yīng)該就可以通過了:

    $ bundle exec cucumber features/

    8.3.3 小技巧:自定義 RSpec 匹配器

    編寫了一些簡單的 Cucumber 場景之后,我們來和相應(yīng)的 RSpec 測試用例對比一下。先看一下代碼 8.32 中的 Cucumber 功能和代碼 8.33 中的步驟定義,然后再看一下如下的 RSpec 集成測試:

    describe "Authentication" dosubject { page }describe "signin" dobefore { visit signin_path }describe "with invalid information" dobefore { click_button "Sign in" }it { should have_selector('title', text: 'Sign in') }it { should have_selector('div.alert.alert-error', text: 'Invalid') }enddescribe "with valid information" dolet(:user) { FactoryGirl.create(:user) }before dofill_in "Email", with: user.emailfill_in "Password", with: user.passwordclick_button "Sign in"endit { should have_selector('title', text: user.name) }it { should have_selector('a', 'Sign out', href: signout_path) }endend end

    由此你大概就可以看出 Cucumber 和集成測試各自的優(yōu)缺點(diǎn)了。Cucumber 功能可讀性很好,但是卻和測試代碼分隔開了,同時(shí)削弱了功能和測試代碼的作用。我覺得 Cucumber 測試讀起來很順口,但是寫起來怪怪的;而集成測試讀起來不太順口,但是很容易編寫。

    Cucumber 把功能描述和步驟定義分開,可以很好的實(shí)現(xiàn)抽象層面的行為。例如,下面這個(gè)描述

    Then he should see an error message

    表達(dá)的意思是,期望看到一個(gè)錯(cuò)誤提示信息。如下的步驟定義則檢測了能否實(shí)現(xiàn)這個(gè)期望:

    Then /?he should see an error message$/ dopage.should have_selector('div.alert.alert-error', text: 'Invalid') end

    Cucumber 這種分離方式特別便捷的地方在于,只有步驟定義是依賴具體實(shí)現(xiàn)的,所以假如我們修改了錯(cuò)誤提示信息所用的 CSS class,功能描述文件是不需要修改的。

    那么,如果你只是想檢測頁面中是否顯示有錯(cuò)誤提示信息,就不想在多個(gè)地方重復(fù)的編寫下面的測試:

    should have_selector('div.alert.alert-error', text: 'Invalid')

    如果你真的這么做了,就把測試和具體的實(shí)現(xiàn)綁死了,一旦改變了實(shí)現(xiàn)方式,就要到處修改測試。在 RSpec 中,可以自定義匹配器來解決這個(gè)問題,我們可以直接這么寫:

    should have_error_message('Invalid')

    我們可以在?5.3.4 節(jié)?中定義?full_title?測試幫助方法的文件中定義這個(gè)匹配器,代碼如下:

    RSpec::Matchers.define :have_error_message do |message|match do |page|page.should have_selector('div.alert.alert-error', text: message)end end

    我們還可以為一些常用的操作定義幫助方法,例如:

    def valid_signin(user)fill_in "Email", with: user.emailfill_in "Password", with: user.passwordclick_button "Sign in" end

    最終的文件如代碼 8.34 所示(把?5.6 節(jié)中的代碼 5.37 和代碼 5.38 合并了)。我覺得這種方法比 Cucumber 的步驟定義還要靈活,特別是當(dāng)匹配器和幫助方法可以接受一個(gè)參數(shù)時(shí),例如?valid_signin(user)。我們也可以用步驟定義中的正則表達(dá)式匹配來實(shí)現(xiàn)這種功能,不過太過繁雜。

    代碼 8.34?添加一個(gè)幫助函數(shù)和一個(gè) RSpec 自定義匹配器
    spec/support/utilities.rb

    include ApplicationHelperdef valid_signin(user)fill_in "Email", with: user.emailfill_in "Password", with: user.passwordclick_button "Sign in" endRSpec::Matchers.define :have_error_message do |message|match do |page|page.should have_selector('div.alert.alert-error', text: message)end end

    添加了代碼 8.34 之后,我們就可以直接寫

    it { should have_error_message('Invalid') }

    describe "with valid information" dolet(:user) { FactoryGirl.create(:user) }before { valid_signin(user) }...

    還有很多測試用例把測試和具體的實(shí)現(xiàn)綁縛在一起了,我們會在?8.5 節(jié)的練習(xí)中徹底的搜查現(xiàn)有的測試組件,使用自定義匹配器和幫助方法解耦測試和具體實(shí)現(xiàn)。

    8.4 小結(jié)

    本章我們介紹了很多基礎(chǔ)知識,也為稍顯簡陋的應(yīng)用程序?qū)崿F(xiàn)了注冊和登錄功能。實(shí)現(xiàn)了用戶身份驗(yàn)證功能后,我們就可以根據(jù)登錄狀態(tài)和用戶的身份限制對特定頁面的訪問權(quán)限。在實(shí)現(xiàn)限制訪問的過程中,我們會為用戶添加編輯個(gè)人信息的功能,還會為管理員添加刪除用戶的功能。這些是第九章的主要內(nèi)容。

    在繼續(xù)閱讀之前,先把本章的改動合并到主分支吧:

    $ git add . $ git commit -m "Finish sign in" $ git checkout master $ git merge sign-in-out

    然后再推送到 GitHub 和 Heroku “生產(chǎn)環(huán)境”服務(wù)器:

    $ git push $ git push heroku $ heroku run rake db:migrate

    如果之前你在生產(chǎn)服務(wù)器中注冊過用戶,我建議你按照?8.2.4 節(jié)中介紹的方法,為各用戶生成記憶權(quán)標(biāo),不能用本地的控制臺,而要用 Heroku 的控制臺:

    $ heroku run console >> User.all.each { |user| user.save(validate: false) }

    8.5 練習(xí)

  • 重構(gòu)登錄表單,把?form_for?換成?form_tag,確保測試還是可以通過的。提示:可以參照 Railscasts 第 270 集《Authentication in Rails 3.1》,特別留意一下?params?Hash 結(jié)構(gòu)的變化。
  • 參照?8.3.3 節(jié)中的示例,遍覽用戶和身份驗(yàn)證相關(guān)的集成測試,在?spec/support/utilities.rb?中定義幫助函數(shù),解耦測試和具體實(shí)現(xiàn)。附加題:把這些幫助方法放到不同的文件和模塊中,然后再引入相應(yīng)的模塊。
  • ? 第七章 用戶注冊第九章 更新、顯示和刪除用戶 ?
  • 另外一個(gè)常見的 session 處理方式是,在一定時(shí)間之后失效。這種方式特別適合包含敏感信息的網(wǎng)站,例如銀行和交易賬戶。???
  • 圖片來自?http://www.flickr.com/photos/hermanusbackpackers/3343254977/???
  • 我選擇這么生成記憶權(quán)標(biāo)是因?yàn)榭戳?Railscasts 第 274 集《Remember Me & Reset Password》。???
  • Active Record 支持的其他回調(diào)函數(shù)在 Rails 指南中有介紹。???
  • 其實(shí)這兩種方式是完全等效的,attr_accessor?會自動創(chuàng)建取值和設(shè)定方法。???
  • 一般來說,這句話的意思是把初始值為?nil?的變量附上了新值,不過?||=?也會把初始值為?false?的變量附上新值。???
  • 這也是一種備忘(memoization),詳情參見旁注 6.3。???
  • 瀏覽器其實(shí)并不能發(fā)送?DELETE?請求,Rails 是通過 JavaScript 模仿的。???
  • from:?http://yongyuan.name/pcvwithpython/chapter8.html

    總結(jié)

    以上是生活随笔為你收集整理的Python计算机视觉:第八章 图像类容分类的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

    国产av久久久久精东av | 国产xxx69麻豆国语对白 | 无遮挡啪啪摇乳动态图 | 水蜜桃亚洲一二三四在线 | 人妻无码αv中文字幕久久琪琪布 | 麻豆国产人妻欲求不满谁演的 | 亚洲欧美日韩综合久久久 | 久久久久免费看成人影片 | 丰满人妻翻云覆雨呻吟视频 | 国产av人人夜夜澡人人爽麻豆 | 又大又硬又黄的免费视频 | 人人爽人人澡人人人妻 | 免费看男女做好爽好硬视频 | 欧美国产日产一区二区 | 欧美日本免费一区二区三区 | 日韩亚洲欧美中文高清在线 | 亚洲国产av精品一区二区蜜芽 | 在线观看国产午夜福利片 | 国产乱码精品一品二品 | 欧美性生交活xxxxxdddd | 草草网站影院白丝内射 | 黑森林福利视频导航 | 欧美人与物videos另类 | 国产午夜无码精品免费看 | 精品欧美一区二区三区久久久 | 青草视频在线播放 | 少妇人妻偷人精品无码视频 | 亚洲aⅴ无码成人网站国产app | 国产成人综合色在线观看网站 | 国产人成高清在线视频99最全资源 | 亚洲国产精品成人久久蜜臀 | 亚洲精品成a人在线观看 | 丁香花在线影院观看在线播放 | 黑人大群体交免费视频 | 狂野欧美性猛交免费视频 | 国产日产欧产精品精品app | 欧美黑人性暴力猛交喷水 | 亚洲成a人片在线观看无码 | 国产精品高潮呻吟av久久 | 久久zyz资源站无码中文动漫 | 67194成是人免费无码 | 久久人人爽人人爽人人片ⅴ | 人人澡人人透人人爽 | 亚洲国产av精品一区二区蜜芽 | 国产性生大片免费观看性 | 99麻豆久久久国产精品免费 | 麻花豆传媒剧国产免费mv在线 | 欧美高清在线精品一区 | 欧美三级不卡在线观看 | 国产精品.xx视频.xxtv | 久久久久av无码免费网 | 蜜桃视频插满18在线观看 | 婷婷五月综合激情中文字幕 | 波多野结衣av一区二区全免费观看 | 性欧美牲交xxxxx视频 | 夜精品a片一区二区三区无码白浆 | 亚洲乱码中文字幕在线 | 捆绑白丝粉色jk震动捧喷白浆 | 少女韩国电视剧在线观看完整 | 无码人妻出轨黑人中文字幕 | 欧美日韩色另类综合 | 日韩成人一区二区三区在线观看 | 欧美熟妇另类久久久久久不卡 | 麻豆md0077饥渴少妇 | 欧美自拍另类欧美综合图片区 | 人人妻人人澡人人爽人人精品 | 国产av一区二区三区最新精品 | 国内精品久久毛片一区二区 | 亚洲中文字幕在线无码一区二区 | 少妇性俱乐部纵欲狂欢电影 | 久久国产自偷自偷免费一区调 | 无码毛片视频一区二区本码 | 国产精华av午夜在线观看 | 国产在线无码精品电影网 | 在线欧美精品一区二区三区 | 久久婷婷五月综合色国产香蕉 | 人人爽人人澡人人高潮 | 精品欧洲av无码一区二区三区 | 少妇被黑人到高潮喷出白浆 | 内射后入在线观看一区 | 国产艳妇av在线观看果冻传媒 | 波多野结衣高清一区二区三区 | 国内少妇偷人精品视频免费 | 精品久久久久香蕉网 | 国内精品一区二区三区不卡 | 狠狠亚洲超碰狼人久久 | 亚洲а∨天堂久久精品2021 | 无套内谢的新婚少妇国语播放 | 国产亚洲精品久久久久久大师 | 黑人玩弄人妻中文在线 | 色欲久久久天天天综合网精品 | 久久人人爽人人人人片 | 国产精品久久久久久久9999 | 亚洲国精产品一二二线 | 久久久中文字幕日本无吗 | 人人澡人摸人人添 | 偷窥村妇洗澡毛毛多 | 亚洲国产精品久久久天堂 | 国产在线精品一区二区三区直播 | 老熟妇仑乱视频一区二区 | 国产精品视频免费播放 | aa片在线观看视频在线播放 | 中文字幕久久久久人妻 | 在线 国产 欧美 亚洲 天堂 | 国产在线精品一区二区三区直播 | 人妻少妇精品视频专区 | 亚洲国产精品久久久久久 | 双乳奶水饱满少妇呻吟 | 久久www免费人成人片 | 国产精品内射视频免费 | 欧美兽交xxxx×视频 | 人妻插b视频一区二区三区 | 国产精品高潮呻吟av久久4虎 | 亚洲自偷自拍另类第1页 | 成熟女人特级毛片www免费 | 久久精品丝袜高跟鞋 | 东京热无码av男人的天堂 | 久久亚洲日韩精品一区二区三区 | 男女下面进入的视频免费午夜 | 色偷偷人人澡人人爽人人模 | 亚洲综合无码久久精品综合 | 亚洲高清偷拍一区二区三区 | 国产区女主播在线观看 | 99久久久无码国产aaa精品 | 日韩亚洲欧美中文高清在线 | 免费网站看v片在线18禁无码 | 国产成人一区二区三区在线观看 | 一本色道久久综合狠狠躁 | 国产精品高潮呻吟av久久 | 成人试看120秒体验区 | 亚洲第一无码av无码专区 | 色婷婷综合激情综在线播放 | 国产激情无码一区二区 | 日产精品高潮呻吟av久久 | 免费观看激色视频网站 | 中文字幕日韩精品一区二区三区 | 真人与拘做受免费视频一 | 亚洲成熟女人毛毛耸耸多 | 大乳丰满人妻中文字幕日本 | 亚洲色欲色欲天天天www | 久久久久久亚洲精品a片成人 | 东京一本一道一二三区 | 中文字幕无码日韩欧毛 | 欧美激情综合亚洲一二区 | 300部国产真实乱 | 亚洲国产欧美日韩精品一区二区三区 | 老太婆性杂交欧美肥老太 | 亚洲成av人在线观看网址 | 国产成人精品必看 | 99re在线播放 | 人妻少妇精品无码专区二区 | 岛国片人妻三上悠亚 | 国产偷抇久久精品a片69 | 中文字幕无码人妻少妇免费 | 午夜肉伦伦影院 | 5858s亚洲色大成网站www | 激情综合激情五月俺也去 | 久久人人爽人人爽人人片ⅴ | 俄罗斯老熟妇色xxxx | 欧美日韩色另类综合 | 最近的中文字幕在线看视频 | 国产色在线 | 国产 | 亚洲 欧美 激情 小说 另类 | 成人无码精品一区二区三区 | 日韩精品成人一区二区三区 | 国产99久久精品一区二区 | 51国偷自产一区二区三区 | 中文字幕无码免费久久9一区9 | 久久精品国产99精品亚洲 | 无码人妻丰满熟妇区五十路百度 | 人妻中文无码久热丝袜 | 狂野欧美性猛xxxx乱大交 | 人妻少妇精品视频专区 | 丝袜 中出 制服 人妻 美腿 | 荡女精品导航 | 免费无码的av片在线观看 | 久久国产精品精品国产色婷婷 | 国产成人精品三级麻豆 | 亚洲 另类 在线 欧美 制服 | 午夜免费福利小电影 | 天天躁日日躁狠狠躁免费麻豆 | 久久精品国产亚洲精品 | 国产精品爱久久久久久久 | 性色欲网站人妻丰满中文久久不卡 | 国产成人亚洲综合无码 | 亚洲色无码一区二区三区 | 国产明星裸体无码xxxx视频 | 免费无码一区二区三区蜜桃大 | 欧美性猛交内射兽交老熟妇 | 精品国产福利一区二区 | 久久久久成人片免费观看蜜芽 | 蜜桃臀无码内射一区二区三区 | 无码纯肉视频在线观看 | 麻豆精品国产精华精华液好用吗 | 99久久精品国产一区二区蜜芽 | 97无码免费人妻超级碰碰夜夜 | 久久亚洲a片com人成 | 麻豆国产丝袜白领秘书在线观看 | 色欲综合久久中文字幕网 | 亚洲а∨天堂久久精品2021 | 精品人妻人人做人人爽夜夜爽 | 特大黑人娇小亚洲女 | 国产办公室秘书无码精品99 | 青青久在线视频免费观看 | 国产成人无码区免费内射一片色欲 | 日本www一道久久久免费榴莲 | 东京一本一道一二三区 | 欧美野外疯狂做受xxxx高潮 | 亚洲欧美综合区丁香五月小说 | 国产美女精品一区二区三区 | 水蜜桃色314在线观看 | 男女性色大片免费网站 | 国产一区二区三区日韩精品 | 欧美阿v高清资源不卡在线播放 | 国产高清av在线播放 | 色综合久久久久综合一本到桃花网 | 国内少妇偷人精品视频 | 亚洲日韩av一区二区三区中文 | 亚洲国产日韩a在线播放 | 伊人久久大香线蕉亚洲 | 亚洲精品国产精品乱码不卡 | 成人试看120秒体验区 | 欧美黑人巨大xxxxx | 牲欲强的熟妇农村老妇女视频 | 国产精品对白交换视频 | 免费网站看v片在线18禁无码 | 久久久精品456亚洲影院 | 久久久久久九九精品久 | 强开小婷嫩苞又嫩又紧视频 | 夜夜躁日日躁狠狠久久av | 国产后入清纯学生妹 | 丰满人妻翻云覆雨呻吟视频 | 亚洲一区二区三区香蕉 | 亚洲中文字幕av在天堂 | 国产激情艳情在线看视频 | 无码吃奶揉捏奶头高潮视频 | 亚洲a无码综合a国产av中文 | 国色天香社区在线视频 | 精品亚洲韩国一区二区三区 | 久久成人a毛片免费观看网站 | 无码人妻丰满熟妇区五十路百度 | 思思久久99热只有频精品66 | 国产av无码专区亚洲a∨毛片 | 少妇性荡欲午夜性开放视频剧场 | 少妇激情av一区二区 | 国产精品第一国产精品 | 中文字幕日韩精品一区二区三区 | 牲交欧美兽交欧美 | 免费看男女做好爽好硬视频 | 精品夜夜澡人妻无码av蜜桃 | 少妇一晚三次一区二区三区 | 欧美丰满熟妇xxxx性ppx人交 | 无码毛片视频一区二区本码 | 日本一卡2卡3卡四卡精品网站 | 欧美黑人巨大xxxxx | 国产精品久久久久久久影院 | 欧美日韩精品 | 天天做天天爱天天爽综合网 | 久久午夜无码鲁丝片 | 国产精品理论片在线观看 | 大肉大捧一进一出视频出来呀 | 欧美日本免费一区二区三区 | 无码国产乱人伦偷精品视频 | 国内精品人妻无码久久久影院 | 亚洲精品综合一区二区三区在线 | 亚洲精品国产第一综合99久久 | 动漫av一区二区在线观看 | 国产小呦泬泬99精品 | 欧美怡红院免费全部视频 | 亚洲成av人片在线观看无码不卡 | 蜜桃视频插满18在线观看 | 天天躁日日躁狠狠躁免费麻豆 | 成人无码精品1区2区3区免费看 | 成熟人妻av无码专区 | 亚洲熟妇色xxxxx欧美老妇y | 国产明星裸体无码xxxx视频 | 成熟女人特级毛片www免费 | 夜精品a片一区二区三区无码白浆 | 欧美亚洲日韩国产人成在线播放 | 日韩精品a片一区二区三区妖精 | 麻豆果冻传媒2021精品传媒一区下载 | 两性色午夜免费视频 | 国产一区二区三区影院 | 黑人玩弄人妻中文在线 | 国内少妇偷人精品视频免费 | 大胆欧美熟妇xx | 亚洲色欲色欲天天天www | 99久久婷婷国产综合精品青草免费 | 国产亚洲人成a在线v网站 | 人妻夜夜爽天天爽三区 | 精品一二三区久久aaa片 | 无码毛片视频一区二区本码 | 亚洲小说春色综合另类 | 日产精品99久久久久久 | 娇妻被黑人粗大高潮白浆 | 精品国产成人一区二区三区 | 人妻体内射精一区二区三四 | 67194成是人免费无码 | 俺去俺来也在线www色官网 | 久久99久久99精品中文字幕 | 久久视频在线观看精品 | 国产精品久久久久9999小说 | 久久精品视频在线看15 | 成年女人永久免费看片 | 日日噜噜噜噜夜夜爽亚洲精品 | 亚洲无人区午夜福利码高清完整版 | 欧美性生交xxxxx久久久 | 精品无码国产一区二区三区av | 中文无码精品a∨在线观看不卡 | 亚洲精品国产品国语在线观看 | 2020久久超碰国产精品最新 | 99久久久无码国产aaa精品 | 久久精品无码一区二区三区 | 无码av岛国片在线播放 | 一个人看的视频www在线 | 色一情一乱一伦一区二区三欧美 | 国产成人午夜福利在线播放 | 日韩精品久久久肉伦网站 | 双乳奶水饱满少妇呻吟 | 男女猛烈xx00免费视频试看 | 国产av无码专区亚洲a∨毛片 | 国产精品欧美成人 | 国产成人av免费观看 | 国产乱码精品一品二品 | 宝宝好涨水快流出来免费视频 | 天干天干啦夜天干天2017 | 99精品无人区乱码1区2区3区 | 国产亚洲精品久久久久久久久动漫 | 成人女人看片免费视频放人 | 亚洲国产日韩a在线播放 | 99久久精品日本一区二区免费 | 少妇久久久久久人妻无码 | 国产一区二区三区四区五区加勒比 | 波多野结衣av在线观看 | 波多野结衣av一区二区全免费观看 | 最新国产乱人伦偷精品免费网站 | 亚洲乱亚洲乱妇50p | 国产又爽又猛又粗的视频a片 | 欧美喷潮久久久xxxxx | 鲁一鲁av2019在线 | 精品人妻人人做人人爽 | 欧美 日韩 人妻 高清 中文 | 亚洲呦女专区 | 撕开奶罩揉吮奶头视频 | 国产成人无码午夜视频在线观看 | 粉嫩少妇内射浓精videos | 亚洲精品一区三区三区在线观看 | 国产成人精品久久亚洲高清不卡 | 国产美女精品一区二区三区 | 午夜精品久久久内射近拍高清 | 国产av一区二区三区最新精品 | 国产偷抇久久精品a片69 | 亚洲成a人片在线观看无码 | 巨爆乳无码视频在线观看 | 久久国产自偷自偷免费一区调 | 人人妻人人澡人人爽精品欧美 | 久久久久av无码免费网 | 伊人色综合久久天天小片 | 丰满少妇弄高潮了www | 天天摸天天碰天天添 | 日韩在线不卡免费视频一区 | 无遮挡国产高潮视频免费观看 | 一本久道久久综合婷婷五月 | 午夜福利一区二区三区在线观看 | 国产在线aaa片一区二区99 | 久久五月精品中文字幕 | 亚洲成av人在线观看网址 | 国产深夜福利视频在线 | 日本乱偷人妻中文字幕 | 国产精品毛片一区二区 | 亚洲天堂2017无码 | 亚洲欧美日韩综合久久久 | 波多野结衣高清一区二区三区 | 国产成人无码区免费内射一片色欲 | 成人av无码一区二区三区 | 欧美丰满少妇xxxx性 | 国产性猛交╳xxx乱大交 国产精品久久久久久无码 欧洲欧美人成视频在线 | 亚洲人成网站免费播放 | 国产午夜亚洲精品不卡 | 人妻人人添人妻人人爱 | 狠狠色欧美亚洲狠狠色www | 欧美亚洲日韩国产人成在线播放 | 国产真实夫妇视频 | 一本无码人妻在中文字幕免费 | 久热国产vs视频在线观看 | 综合激情五月综合激情五月激情1 | 樱花草在线社区www | 久激情内射婷内射蜜桃人妖 | 高清国产亚洲精品自在久久 | 国产又爽又猛又粗的视频a片 | 爆乳一区二区三区无码 | 天天摸天天透天天添 | 综合激情五月综合激情五月激情1 | 任你躁在线精品免费 | 无码任你躁久久久久久久 | 无码人中文字幕 | 无遮无挡爽爽免费视频 | 亚洲国产欧美在线成人 | 玩弄少妇高潮ⅹxxxyw | 中文无码伦av中文字幕 | 76少妇精品导航 | 国产精品国产自线拍免费软件 | 精品国产一区二区三区四区在线看 | 欧美日韩一区二区三区自拍 | 日本精品少妇一区二区三区 | 国产精品久久久久无码av色戒 | 中文字幕无码av激情不卡 | 一个人看的www免费视频在线观看 | 欧美精品免费观看二区 | 秋霞成人午夜鲁丝一区二区三区 | √8天堂资源地址中文在线 | 美女黄网站人色视频免费国产 | 老太婆性杂交欧美肥老太 | 国产熟妇另类久久久久 | 国产激情无码一区二区app | 欧美 丝袜 自拍 制服 另类 | 一本大道久久东京热无码av | 免费国产成人高清在线观看网站 | 中文毛片无遮挡高清免费 | 成年美女黄网站色大免费视频 | 国产午夜福利100集发布 | 亚洲精品无码国产 | 欧美xxxx黑人又粗又长 | 中文字幕人妻无码一夲道 | 久久久久久久久888 | 无码av中文字幕免费放 | 97久久超碰中文字幕 | 国产成人无码区免费内射一片色欲 | 内射爽无广熟女亚洲 | 麻豆成人精品国产免费 | 亚洲 欧美 激情 小说 另类 | 亚洲乱码国产乱码精品精 | 久久久www成人免费毛片 | 欧美老人巨大xxxx做受 | 午夜无码区在线观看 | 欧美激情综合亚洲一二区 | 漂亮人妻洗澡被公强 日日躁 | 东京热男人av天堂 | 中文字幕av无码一区二区三区电影 | 爆乳一区二区三区无码 | 丰满岳乱妇在线观看中字无码 | 少妇性l交大片欧洲热妇乱xxx | 国产成人无码一二三区视频 | 无套内谢的新婚少妇国语播放 | 麻豆av传媒蜜桃天美传媒 | 人妻少妇被猛烈进入中文字幕 | 任你躁国产自任一区二区三区 | 国产成人无码av一区二区 | 亚洲热妇无码av在线播放 | 亚洲国产av精品一区二区蜜芽 | 国产熟妇高潮叫床视频播放 | 亚洲自偷自拍另类第1页 | 国产精品99久久精品爆乳 | 中文精品久久久久人妻不卡 | 亚洲日韩av片在线观看 | 欧美老妇交乱视频在线观看 | 熟妇女人妻丰满少妇中文字幕 | 综合人妻久久一区二区精品 | 一区二区三区乱码在线 | 欧洲 | 男女猛烈xx00免费视频试看 | 成人女人看片免费视频放人 | 人妻有码中文字幕在线 | 日本成熟视频免费视频 | 国产极品视觉盛宴 | 性做久久久久久久免费看 | 内射巨臀欧美在线视频 | 亚洲理论电影在线观看 | 久久精品一区二区三区四区 | 国产成人一区二区三区别 | 18禁止看的免费污网站 | 99精品无人区乱码1区2区3区 | 亚洲色偷偷偷综合网 | 高潮毛片无遮挡高清免费视频 | 正在播放东北夫妻内射 | 国产后入清纯学生妹 | 亚洲一区二区三区偷拍女厕 | 5858s亚洲色大成网站www | 人人妻人人藻人人爽欧美一区 | 亚洲乱码日产精品bd | 国产精品高潮呻吟av久久4虎 | 在线精品亚洲一区二区 | 亚洲日本一区二区三区在线 | 亚洲国产成人av在线观看 | 亚洲成av人片在线观看无码不卡 | 亚洲欧洲中文日韩av乱码 | 欧美野外疯狂做受xxxx高潮 | 亚洲成熟女人毛毛耸耸多 | 久久99国产综合精品 | 亚洲日本一区二区三区在线 | 亚洲欧美国产精品久久 | 久久天天躁夜夜躁狠狠 | 国产亚洲精品精品国产亚洲综合 | 国产成人人人97超碰超爽8 | 国产av人人夜夜澡人人爽麻豆 | 亚洲理论电影在线观看 | 学生妹亚洲一区二区 | 成人一在线视频日韩国产 | 欧美人妻一区二区三区 | 俺去俺来也www色官网 | 澳门永久av免费网站 | 国产无套内射久久久国产 | 蜜桃av抽搐高潮一区二区 | 精品久久久久香蕉网 | 日本一区二区三区免费高清 | 亚洲理论电影在线观看 | 少女韩国电视剧在线观看完整 | 国产凸凹视频一区二区 | 亚洲 欧美 激情 小说 另类 | 麻豆精品国产精华精华液好用吗 | 亚洲熟女一区二区三区 | 两性色午夜免费视频 | 久久久精品欧美一区二区免费 | 人人爽人人爽人人片av亚洲 | 少妇性俱乐部纵欲狂欢电影 | 亚洲色成人中文字幕网站 | 国产成人精品必看 | 成人无码视频在线观看网站 | 亚洲熟妇自偷自拍另类 | 欧美高清在线精品一区 | 久激情内射婷内射蜜桃人妖 | 中文字幕色婷婷在线视频 | 天天拍夜夜添久久精品 | 成人无码精品1区2区3区免费看 | 成人影院yy111111在线观看 | 亚洲va欧美va天堂v国产综合 | 亚洲欧洲无卡二区视頻 | 久久99久久99精品中文字幕 | 乱中年女人伦av三区 | 国产在线aaa片一区二区99 | 无码精品国产va在线观看dvd | 妺妺窝人体色www在线小说 | 久久精品成人欧美大片 | 亚洲精品国产精品乱码视色 | 一个人看的www免费视频在线观看 | 国产精品丝袜黑色高跟鞋 | 日韩 欧美 动漫 国产 制服 | а√资源新版在线天堂 | 色妞www精品免费视频 | 日本精品久久久久中文字幕 | 曰本女人与公拘交酡免费视频 | 国产69精品久久久久app下载 | 日本免费一区二区三区最新 | 亚洲日韩av一区二区三区四区 | 国产三级精品三级男人的天堂 | 成人三级无码视频在线观看 | 亚洲精品久久久久久久久久久 | 亚洲色欲色欲欲www在线 | 日日麻批免费40分钟无码 | 欧美一区二区三区视频在线观看 | 人妻少妇精品视频专区 | 久久亚洲中文字幕无码 | 国语精品一区二区三区 | 亚洲男人av香蕉爽爽爽爽 | 中文字幕无码av激情不卡 | 少妇性荡欲午夜性开放视频剧场 | 国内精品久久久久久中文字幕 | 日韩在线不卡免费视频一区 | 无码人妻少妇伦在线电影 | 久久无码人妻影院 | 亚洲精品中文字幕 | 男女爱爱好爽视频免费看 | 日韩欧美中文字幕公布 | 成年美女黄网站色大免费视频 | 永久黄网站色视频免费直播 | 国産精品久久久久久久 | 日日干夜夜干 | 亚洲男女内射在线播放 | 国产一区二区三区影院 | 亚洲熟女一区二区三区 | 中国大陆精品视频xxxx | 扒开双腿疯狂进出爽爽爽视频 | 亚洲精品国产品国语在线观看 | 亚洲一区二区三区播放 | 国产激情一区二区三区 | 六十路熟妇乱子伦 | 精品日本一区二区三区在线观看 | 久久久精品456亚洲影院 | 日本成熟视频免费视频 | 国产肉丝袜在线观看 | 国产精华av午夜在线观看 | 国产成人精品视频ⅴa片软件竹菊 | 国产无遮挡又黄又爽免费视频 | 丰满人妻精品国产99aⅴ | 人妻有码中文字幕在线 | 欧美色就是色 | 亚洲综合无码久久精品综合 | aⅴ在线视频男人的天堂 | 亚洲狠狠婷婷综合久久 | 双乳奶水饱满少妇呻吟 | 无码午夜成人1000部免费视频 | 久久国产精品_国产精品 | yw尤物av无码国产在线观看 | 人妻少妇精品无码专区二区 | 成人无码影片精品久久久 | 亚拍精品一区二区三区探花 | 天干天干啦夜天干天2017 | 亚洲色大成网站www国产 | 成人女人看片免费视频放人 | 76少妇精品导航 | 国产成人精品视频ⅴa片软件竹菊 | 久久97精品久久久久久久不卡 | 久久久久人妻一区精品色欧美 | 亚洲色成人中文字幕网站 | 国精产品一区二区三区 | 99久久精品无码一区二区毛片 | 狠狠色丁香久久婷婷综合五月 | 无码av免费一区二区三区试看 | 综合人妻久久一区二区精品 | 亚拍精品一区二区三区探花 | 中文字幕无码热在线视频 | 久久久亚洲欧洲日产国码αv | 欧美成人家庭影院 | 亚洲中文字幕在线观看 | 亚洲一区二区三区偷拍女厕 | 亚洲s色大片在线观看 | 精品国产aⅴ无码一区二区 | 国产电影无码午夜在线播放 | 日韩亚洲欧美中文高清在线 | 久久亚洲日韩精品一区二区三区 | 久久精品人人做人人综合试看 | 国产综合久久久久鬼色 | 日韩在线不卡免费视频一区 | 婷婷综合久久中文字幕蜜桃三电影 | 女人被男人躁得好爽免费视频 | 精品国产麻豆免费人成网站 | 亚洲日本va午夜在线电影 | 欧美 丝袜 自拍 制服 另类 | 色偷偷人人澡人人爽人人模 | 人人妻人人澡人人爽欧美精品 | 高清国产亚洲精品自在久久 | 久久精品国产日本波多野结衣 | 亚洲色大成网站www | 男女性色大片免费网站 | 十八禁视频网站在线观看 | 伊人久久大香线蕉av一区二区 | 思思久久99热只有频精品66 | 少妇久久久久久人妻无码 | 纯爱无遮挡h肉动漫在线播放 | 兔费看少妇性l交大片免费 | 欧美日韩精品 | 18无码粉嫩小泬无套在线观看 | 亚洲精品成a人在线观看 | 中文字幕久久久久人妻 | 中文字幕人妻无码一区二区三区 | 国产免费无码一区二区视频 | 人人爽人人澡人人人妻 | 国产后入清纯学生妹 | 久久久久99精品国产片 | 动漫av一区二区在线观看 | 亚洲自偷精品视频自拍 | 久久午夜夜伦鲁鲁片无码免费 | 亚洲欧美国产精品久久 | 秋霞成人午夜鲁丝一区二区三区 | 无码av免费一区二区三区试看 | 国产在线精品一区二区三区直播 | 蜜桃视频插满18在线观看 | 蜜桃视频韩日免费播放 | 影音先锋中文字幕无码 | 欧美喷潮久久久xxxxx | 东京热无码av男人的天堂 | 久久精品中文闷骚内射 | 精品少妇爆乳无码av无码专区 | 自拍偷自拍亚洲精品10p | 18精品久久久无码午夜福利 | 内射巨臀欧美在线视频 | 无套内谢老熟女 | 自拍偷自拍亚洲精品10p | 国产精品va在线播放 | 在线看片无码永久免费视频 | 国产成人av免费观看 | 无码国产乱人伦偷精品视频 | 国内少妇偷人精品视频 | 福利一区二区三区视频在线观看 | 欧美熟妇另类久久久久久不卡 | 成人亚洲精品久久久久 | 国产精品无码mv在线观看 | 久久国产精品精品国产色婷婷 | 东京热一精品无码av | 领导边摸边吃奶边做爽在线观看 | 2020久久超碰国产精品最新 | 日本欧美一区二区三区乱码 | 亚洲狠狠婷婷综合久久 | 亚洲精品国产精品乱码不卡 | 玩弄中年熟妇正在播放 | 欧美性生交xxxxx久久久 | 日本一区二区三区免费高清 | а√资源新版在线天堂 | 国产乱人伦app精品久久 国产在线无码精品电影网 国产国产精品人在线视 | 岛国片人妻三上悠亚 | 中文毛片无遮挡高清免费 | 免费观看激色视频网站 | 在线 国产 欧美 亚洲 天堂 | 国产97在线 | 亚洲 | 国产麻豆精品一区二区三区v视界 | 亚洲色欲色欲天天天www | 亚洲成av人片天堂网无码】 | 久久99国产综合精品 | 99久久婷婷国产综合精品青草免费 | 精品人妻中文字幕有码在线 | 乌克兰少妇性做爰 | 国产国产精品人在线视 | 亚洲精品午夜无码电影网 | 性色av无码免费一区二区三区 | 无码人妻精品一区二区三区下载 | 国产又爽又黄又刺激的视频 | 国产免费久久久久久无码 | 色噜噜亚洲男人的天堂 | 伦伦影院午夜理论片 | 国产精品久久久久久亚洲毛片 | 天干天干啦夜天干天2017 | 亚洲成av人综合在线观看 | 国产亚洲日韩欧美另类第八页 | 鲁大师影院在线观看 | 亚洲va中文字幕无码久久不卡 | 久久国产劲爆∧v内射 | 一二三四社区在线中文视频 | 美女扒开屁股让男人桶 | 2019nv天堂香蕉在线观看 | 黑人巨大精品欧美一区二区 | 亚洲中文字幕久久无码 | 久久久国产一区二区三区 | 精品国产aⅴ无码一区二区 | 精品一区二区三区波多野结衣 | 中文字幕中文有码在线 | 亚洲午夜福利在线观看 | 女人被爽到呻吟gif动态图视看 | 亚洲精品无码国产 | 精品国偷自产在线视频 | 亚洲の无码国产の无码影院 | 精品久久8x国产免费观看 | 国产午夜福利100集发布 | 少妇愉情理伦片bd | 天堂无码人妻精品一区二区三区 | 国产精品va在线观看无码 | 一个人免费观看的www视频 | 婷婷五月综合激情中文字幕 | 欧美野外疯狂做受xxxx高潮 | 国产成人精品三级麻豆 | 免费网站看v片在线18禁无码 | 少妇无码av无码专区在线观看 | 精品亚洲成av人在线观看 | 少妇激情av一区二区 | 少妇性荡欲午夜性开放视频剧场 | 亚洲精品一区三区三区在线观看 | 精品无码av一区二区三区 | 欧美老人巨大xxxx做受 | 亚洲人成影院在线无码按摩店 | 国产麻豆精品精东影业av网站 | 精品无码国产一区二区三区av | 国产三级久久久精品麻豆三级 | 久久久久久久久蜜桃 | 兔费看少妇性l交大片免费 | 亚洲一区二区三区国产精华液 | 亚洲热妇无码av在线播放 | 婷婷六月久久综合丁香 | 无码国产色欲xxxxx视频 | 亚洲精品一区二区三区四区五区 | 日产精品99久久久久久 | 久久久中文久久久无码 | 国产无遮挡吃胸膜奶免费看 | 亚洲成a人一区二区三区 | 性做久久久久久久免费看 | 少妇人妻av毛片在线看 | 在线天堂新版最新版在线8 | 国产亚洲欧美在线专区 | 成人亚洲精品久久久久 | 狂野欧美性猛xxxx乱大交 | 无码国产乱人伦偷精品视频 | 亚洲精品美女久久久久久久 | 日日橹狠狠爱欧美视频 | 亚洲精品综合一区二区三区在线 | 日日碰狠狠丁香久燥 | 在线a亚洲视频播放在线观看 | 亚洲国产欧美国产综合一区 | 狠狠cao日日穞夜夜穞av | 午夜无码人妻av大片色欲 | 欧美自拍另类欧美综合图片区 | 综合激情五月综合激情五月激情1 | 女人色极品影院 | 中文精品久久久久人妻不卡 | 国产香蕉尹人综合在线观看 | 国产后入清纯学生妹 | 国产av一区二区精品久久凹凸 | 亚洲日本在线电影 | 精品aⅴ一区二区三区 | 99国产欧美久久久精品 | 亚洲中文字幕无码一久久区 | 亚洲欧美综合区丁香五月小说 | 97精品人妻一区二区三区香蕉 | 精品成在人线av无码免费看 | 少妇性l交大片欧洲热妇乱xxx | 98国产精品综合一区二区三区 | 国产精品人人爽人人做我的可爱 | 一本加勒比波多野结衣 | 天天摸天天碰天天添 | 精品偷拍一区二区三区在线看 | 人人爽人人澡人人人妻 | 日韩 欧美 动漫 国产 制服 | 欧洲熟妇色 欧美 | 日日橹狠狠爱欧美视频 | 999久久久国产精品消防器材 | 岛国片人妻三上悠亚 | 中文字幕乱码人妻无码久久 | 十八禁视频网站在线观看 | 亚洲无人区午夜福利码高清完整版 | 日韩欧美中文字幕在线三区 | 人人爽人人澡人人人妻 | 免费男性肉肉影院 | 欧美高清在线精品一区 | 久久99精品国产麻豆蜜芽 | 国产精品美女久久久 | 久久97精品久久久久久久不卡 | 国产成人综合美国十次 | 少妇太爽了在线观看 | 国产成人无码av片在线观看不卡 | 丰满人妻精品国产99aⅴ | 免费人成在线观看网站 | 久久久婷婷五月亚洲97号色 | 国产一区二区三区精品视频 | 婷婷丁香五月天综合东京热 | 九九综合va免费看 | 国内精品人妻无码久久久影院蜜桃 | 巨爆乳无码视频在线观看 | 澳门永久av免费网站 | 国产香蕉尹人视频在线 | 欧美 日韩 人妻 高清 中文 | 六十路熟妇乱子伦 | 中文字幕无码热在线视频 | 亚洲精品欧美二区三区中文字幕 | 亚洲色欲久久久综合网东京热 | 国产精品久久久久9999小说 | 丰满少妇熟乱xxxxx视频 | 国产亚洲精品精品国产亚洲综合 | 亚洲国产欧美在线成人 | 亚洲国精产品一二二线 | 国产sm调教视频在线观看 | 久久久久久亚洲精品a片成人 | 国产两女互慰高潮视频在线观看 | 精品欧洲av无码一区二区三区 | 久久熟妇人妻午夜寂寞影院 | 麻豆md0077饥渴少妇 | 亚洲国产欧美日韩精品一区二区三区 | 少妇久久久久久人妻无码 | 色一情一乱一伦一视频免费看 | 久久精品成人欧美大片 | 国产另类ts人妖一区二区 | 激情内射亚州一区二区三区爱妻 | 天海翼激烈高潮到腰振不止 | 国产乱子伦视频在线播放 | 国产成人一区二区三区别 | 国产三级久久久精品麻豆三级 | 伊人色综合久久天天小片 | 水蜜桃亚洲一二三四在线 | 免费观看激色视频网站 | 欧洲vodafone精品性 | 波多野结衣av在线观看 | 亚洲区小说区激情区图片区 | 国产 精品 自在自线 | 午夜熟女插插xx免费视频 | 国色天香社区在线视频 | 亚洲人成影院在线观看 | 内射巨臀欧美在线视频 | 久久精品国产亚洲精品 | 美女极度色诱视频国产 | 国产成人午夜福利在线播放 | 久久综合狠狠综合久久综合88 | 国产人妖乱国产精品人妖 | 中文字幕乱码人妻二区三区 | 日本乱人伦片中文三区 | 欧美精品无码一区二区三区 | av人摸人人人澡人人超碰下载 | 激情亚洲一区国产精品 | 亚洲成a人一区二区三区 | 国产成人精品久久亚洲高清不卡 | 亚洲а∨天堂久久精品2021 | 国产偷自视频区视频 | 女人被爽到呻吟gif动态图视看 | 九九热爱视频精品 | 人人妻人人澡人人爽欧美一区 | 欧美xxxx黑人又粗又长 | 亚洲中文字幕乱码av波多ji | 三级4级全黄60分钟 | 欧美人与牲动交xxxx | 国产午夜亚洲精品不卡 | 无码帝国www无码专区色综合 | 理论片87福利理论电影 | 亚洲精品www久久久 | 色欲综合久久中文字幕网 | 亚洲大尺度无码无码专区 | 亚洲国产欧美在线成人 | 午夜精品一区二区三区的区别 | 特黄特色大片免费播放器图片 | 天天拍夜夜添久久精品大 | 成人免费视频视频在线观看 免费 | 国产精品高潮呻吟av久久 | 欧美成人高清在线播放 | a在线亚洲男人的天堂 | 天堂无码人妻精品一区二区三区 | 在线视频网站www色 | 国产精华av午夜在线观看 | 中文字幕久久久久人妻 | 少妇高潮喷潮久久久影院 | 亚洲国产精品久久久久久 | 国产精品第一区揄拍无码 | 成人av无码一区二区三区 | 成人aaa片一区国产精品 | 欧美 丝袜 自拍 制服 另类 | 国产真人无遮挡作爱免费视频 | 亚洲国产精品久久久天堂 | 欧美老熟妇乱xxxxx | 九九综合va免费看 | 熟女俱乐部五十路六十路av | ass日本丰满熟妇pics | 少妇激情av一区二区 | 好爽又高潮了毛片免费下载 | 无码一区二区三区在线 | 一本加勒比波多野结衣 | 久久国产自偷自偷免费一区调 | 久久亚洲国产成人精品性色 | 波多野结衣aⅴ在线 | 日韩精品久久久肉伦网站 | www国产亚洲精品久久久日本 | aⅴ在线视频男人的天堂 | 玩弄少妇高潮ⅹxxxyw | 亚洲色在线无码国产精品不卡 | 国产又粗又硬又大爽黄老大爷视 | 一二三四在线观看免费视频 | 亚洲国产综合无码一区 | 久久国产精品偷任你爽任你 | 激情内射亚州一区二区三区爱妻 | 一个人看的www免费视频在线观看 | 欧美性猛交内射兽交老熟妇 | 国产又爽又黄又刺激的视频 | 精品无码成人片一区二区98 | 人人妻人人澡人人爽精品欧美 | 久久亚洲中文字幕无码 | 香蕉久久久久久av成人 | aⅴ在线视频男人的天堂 | 少妇的肉体aa片免费 | 国产无av码在线观看 | 乌克兰少妇xxxx做受 | 国产精品va在线观看无码 | 亚洲大尺度无码无码专区 | 国产凸凹视频一区二区 | 在线a亚洲视频播放在线观看 | 狠狠躁日日躁夜夜躁2020 | 在线播放亚洲第一字幕 | 99riav国产精品视频 | 国产无套内射久久久国产 | 国产精品鲁鲁鲁 | 久久这里只有精品视频9 | 天堂亚洲2017在线观看 | 国产亚洲欧美在线专区 | 亚洲s码欧洲m码国产av | 精品久久8x国产免费观看 | 欧美日韩在线亚洲综合国产人 | 日本精品高清一区二区 | 国产福利视频一区二区 | 国产sm调教视频在线观看 | 免费观看又污又黄的网站 | 日本大香伊一区二区三区 | 搡女人真爽免费视频大全 | 久久精品国产大片免费观看 | 18禁止看的免费污网站 | 综合人妻久久一区二区精品 | 精品国产一区二区三区av 性色 | 国产精品嫩草久久久久 | 无码人妻出轨黑人中文字幕 | 精品国产麻豆免费人成网站 | 欧美日韩亚洲国产精品 | 国产精品美女久久久 | 欧美成人高清在线播放 | 国产精品久久久一区二区三区 | 日韩av无码一区二区三区不卡 | 思思久久99热只有频精品66 | 色欲av亚洲一区无码少妇 | 亚洲精品国产品国语在线观看 | 国产亚av手机在线观看 | 日本精品人妻无码免费大全 | 日本一卡二卡不卡视频查询 | 在线观看免费人成视频 | 日日摸夜夜摸狠狠摸婷婷 | 久久精品国产一区二区三区肥胖 | 国产亚洲精品久久久久久久 | 国产va免费精品观看 | 亚洲色欲久久久综合网东京热 | 日韩欧美中文字幕在线三区 | 日产国产精品亚洲系列 | 久久久久久久久蜜桃 | 亚洲狠狠色丁香婷婷综合 | 亚洲国产欧美日韩精品一区二区三区 | 国产精品福利视频导航 | 人妻与老人中文字幕 | 99久久人妻精品免费一区 | 亚洲日韩一区二区三区 | 成年美女黄网站色大免费全看 | 激情人妻另类人妻伦 | 精品无码成人片一区二区98 | 日本精品久久久久中文字幕 | 国产精品99久久精品爆乳 | 在线播放亚洲第一字幕 | 日本一区二区三区免费高清 | 久久国产自偷自偷免费一区调 | 久久久久成人精品免费播放动漫 | 粉嫩少妇内射浓精videos | 扒开双腿吃奶呻吟做受视频 | 国产精品久久福利网站 | 性欧美videos高清精品 | 秋霞成人午夜鲁丝一区二区三区 | 国产猛烈高潮尖叫视频免费 | 狂野欧美性猛xxxx乱大交 | 国产精品资源一区二区 | 久久亚洲中文字幕无码 | 理论片87福利理论电影 | 大色综合色综合网站 | 久久久精品欧美一区二区免费 | 牛和人交xxxx欧美 | 亚洲小说图区综合在线 | 国产精品永久免费视频 | 精品久久久中文字幕人妻 | 成人aaa片一区国产精品 | 亚洲码国产精品高潮在线 | 久久久久成人精品免费播放动漫 | 亚洲午夜久久久影院 | 在线看片无码永久免费视频 | 大色综合色综合网站 | 中文字幕久久久久人妻 | 日日碰狠狠躁久久躁蜜桃 | 久久久久人妻一区精品色欧美 | 樱花草在线播放免费中文 | 无码av中文字幕免费放 | 中文字幕无码免费久久99 | www国产精品内射老师 | 少妇高潮一区二区三区99 | 婷婷色婷婷开心五月四房播播 | 久久97精品久久久久久久不卡 | 中文亚洲成a人片在线观看 | 久久精品丝袜高跟鞋 | 中文字幕无码av波多野吉衣 | 图片小说视频一区二区 | 亚洲 激情 小说 另类 欧美 | 成年女人永久免费看片 | 人人澡人人妻人人爽人人蜜桃 | 日欧一片内射va在线影院 | 成人精品天堂一区二区三区 | 黑森林福利视频导航 | 久久精品国产精品国产精品污 | 无码国产激情在线观看 | 国产麻豆精品精东影业av网站 | 亚洲第一网站男人都懂 | 久久久久se色偷偷亚洲精品av | 日产精品高潮呻吟av久久 | 少妇无套内谢久久久久 | 日欧一片内射va在线影院 | 88国产精品欧美一区二区三区 | 在教室伦流澡到高潮hnp视频 | 国产国产精品人在线视 | 九九久久精品国产免费看小说 | 国产真人无遮挡作爱免费视频 | 无码任你躁久久久久久久 | 久久精品国产一区二区三区 | 国产精品人妻一区二区三区四 | 狂野欧美激情性xxxx | 成人无码视频在线观看网站 | 亚洲色偷偷男人的天堂 | 曰本女人与公拘交酡免费视频 | 久久zyz资源站无码中文动漫 | 狠狠噜狠狠狠狠丁香五月 | 国内老熟妇对白xxxxhd | 久久久成人毛片无码 | 亚洲欧美中文字幕5发布 | 久久综合狠狠综合久久综合88 | 精品久久8x国产免费观看 | 正在播放老肥熟妇露脸 | 国产舌乚八伦偷品w中 | 国产人妻人伦精品1国产丝袜 | 国产精品无码一区二区桃花视频 | 亚洲精品无码人妻无码 | 国产两女互慰高潮视频在线观看 | 国内精品人妻无码久久久影院蜜桃 | 成熟女人特级毛片www免费 | 男人和女人高潮免费网站 | 午夜性刺激在线视频免费 | 国产精品无码成人午夜电影 | 5858s亚洲色大成网站www | www国产亚洲精品久久网站 | 日本成熟视频免费视频 | 欧美老妇交乱视频在线观看 | 亚洲中文字幕乱码av波多ji | 在线欧美精品一区二区三区 | 97色伦图片97综合影院 | 亚洲综合在线一区二区三区 | 亚洲精品一区二区三区在线观看 | 影音先锋中文字幕无码 | 国产乱子伦视频在线播放 | 全球成人中文在线 | 乱人伦人妻中文字幕无码久久网 | 狂野欧美激情性xxxx | 国产精品多人p群无码 | 在线欧美精品一区二区三区 | 亚洲の无码国产の无码影院 | 久久午夜夜伦鲁鲁片无码免费 | 欧美阿v高清资源不卡在线播放 | 欧美老妇交乱视频在线观看 | 色老头在线一区二区三区 | 国产亚洲精品久久久ai换 | 日韩成人一区二区三区在线观看 | 国语自产偷拍精品视频偷 | 国产乱人无码伦av在线a | 无码人妻精品一区二区三区不卡 | 荫蒂添的好舒服视频囗交 | 日韩欧美群交p片內射中文 | 少妇的肉体aa片免费 | 国产人妻精品午夜福利免费 | 国产精品毛片一区二区 | 97无码免费人妻超级碰碰夜夜 | 成人精品视频一区二区 | 亚洲综合无码一区二区三区 | 麻豆蜜桃av蜜臀av色欲av | a国产一区二区免费入口 | 国产成人精品三级麻豆 | 精品久久久久久人妻无码中文字幕 | 久久精品99久久香蕉国产色戒 | 欧美日韩视频无码一区二区三 | 一区二区传媒有限公司 | 国产69精品久久久久app下载 | 小鲜肉自慰网站xnxx | 亚洲の无码国产の无码步美 | 对白脏话肉麻粗话av | 国产两女互慰高潮视频在线观看 | 精品厕所偷拍各类美女tp嘘嘘 | 国产两女互慰高潮视频在线观看 | 亚洲中文字幕av在天堂 | 帮老师解开蕾丝奶罩吸乳网站 | 国产午夜福利亚洲第一 | 国产精品美女久久久 | 国产精品无码一区二区三区不卡 | 一本久久a久久精品亚洲 | 国产美女精品一区二区三区 | 精品少妇爆乳无码av无码专区 | 国产精品国产自线拍免费软件 | 久久97精品久久久久久久不卡 | 欧洲熟妇精品视频 | 欧美freesex黑人又粗又大 | 亚洲区小说区激情区图片区 | 亚欧洲精品在线视频免费观看 | 99精品国产综合久久久久五月天 | 一本色道久久综合亚洲精品不卡 | 国产两女互慰高潮视频在线观看 | 成熟人妻av无码专区 | 最近中文2019字幕第二页 | 国产av久久久久精东av | 无码av岛国片在线播放 | 色综合久久久久综合一本到桃花网 | 国产香蕉97碰碰久久人人 | 乱人伦人妻中文字幕无码久久网 | 九一九色国产 | 性开放的女人aaa片 | 玩弄中年熟妇正在播放 | 67194成是人免费无码 | 日本精品人妻无码免费大全 | 蜜桃av抽搐高潮一区二区 | 亚无码乱人伦一区二区 | 久久久久99精品国产片 | 亚洲一区二区三区偷拍女厕 | 国产极品美女高潮无套在线观看 | av无码久久久久不卡免费网站 | 99久久99久久免费精品蜜桃 | 少妇性俱乐部纵欲狂欢电影 | 国产精品va在线观看无码 | 国产绳艺sm调教室论坛 | 国产精品香蕉在线观看 | 东京一本一道一二三区 | 日日天干夜夜狠狠爱 | 国産精品久久久久久久 | 国内少妇偷人精品视频免费 | 97色伦图片97综合影院 | 97无码免费人妻超级碰碰夜夜 | 人妻无码αv中文字幕久久琪琪布 | 噜噜噜亚洲色成人网站 | 一本加勒比波多野结衣 | 亚洲日韩乱码中文无码蜜桃臀网站 | 欧美 日韩 亚洲 在线 | 动漫av网站免费观看 | 欧美国产日产一区二区 | 精品人妻人人做人人爽 | 强辱丰满人妻hd中文字幕 | 精品国产成人一区二区三区 | 亚洲一区二区三区在线观看网站 | 人人爽人人澡人人高潮 | 久久精品国产大片免费观看 | 香蕉久久久久久av成人 | 亚洲精品国偷拍自产在线观看蜜桃 | 两性色午夜视频免费播放 | 欧美 丝袜 自拍 制服 另类 | 欧美人与动性行为视频 | 亚洲啪av永久无码精品放毛片 | 亚洲日本va午夜在线电影 | 亚洲色偷偷偷综合网 | 精品国产一区二区三区四区在线看 | 亚洲精品成人av在线 | 亚洲熟熟妇xxxx | 中文精品无码中文字幕无码专区 | 国产又爽又猛又粗的视频a片 | 中文字幕无码视频专区 | 亚洲精品久久久久中文第一幕 | 高清国产亚洲精品自在久久 | 欧美成人午夜精品久久久 | 亚洲一区二区三区四区 | 日本xxxx色视频在线观看免费 | 十八禁真人啪啪免费网站 | 欧美日韩人成综合在线播放 | 久久久国产一区二区三区 | 老太婆性杂交欧美肥老太 | 精品国产一区av天美传媒 | 大地资源网第二页免费观看 | 99久久久无码国产精品免费 | 亚洲高清偷拍一区二区三区 | 性欧美大战久久久久久久 | 久久精品国产亚洲精品 | 久久99精品国产麻豆 | 在线播放亚洲第一字幕 | 国产热a欧美热a在线视频 | 无码精品人妻一区二区三区av | 人妻有码中文字幕在线 | 国产精品自产拍在线观看 | 无码av岛国片在线播放 | 丰满肥臀大屁股熟妇激情视频 | аⅴ资源天堂资源库在线 | 少妇愉情理伦片bd | 亚洲国产成人a精品不卡在线 | 樱花草在线社区www | 日日躁夜夜躁狠狠躁 | 装睡被陌生人摸出水好爽 | 欧美日韩综合一区二区三区 | 国产精品无套呻吟在线 | 在教室伦流澡到高潮hnp视频 | 国产成人精品视频ⅴa片软件竹菊 | 又大又黄又粗又爽的免费视频 | 正在播放东北夫妻内射 | 人妻体内射精一区二区三四 | 国产无套内射久久久国产 | 久久国产精品_国产精品 | 成人欧美一区二区三区 | 久久国语露脸国产精品电影 | 正在播放东北夫妻内射 | 亚洲欧美综合区丁香五月小说 | 久久精品99久久香蕉国产色戒 | 特大黑人娇小亚洲女 | 久久综合网欧美色妞网 | 在线观看免费人成视频 | 亚洲成av人片天堂网无码】 | 精品成在人线av无码免费看 | 亚洲精品一区二区三区婷婷月 | 中文无码精品a∨在线观看不卡 | 久久久国产精品无码免费专区 | 国产熟妇另类久久久久 | 牲交欧美兽交欧美 | 永久免费精品精品永久-夜色 | 97精品国产97久久久久久免费 | 性欧美疯狂xxxxbbbb | 牛和人交xxxx欧美 | 久久人人97超碰a片精品 | 日本护士xxxxhd少妇 | 国产精品无码一区二区三区不卡 | 国产99久久精品一区二区 | 人妻有码中文字幕在线 | 国产亚洲视频中文字幕97精品 | 色综合久久久久综合一本到桃花网 | av无码电影一区二区三区 | 久久熟妇人妻午夜寂寞影院 | 亚洲中文字幕无码中文字在线 | 人妻体内射精一区二区三四 | 一本精品99久久精品77 | 国产卡一卡二卡三 | 最新国产麻豆aⅴ精品无码 | 国产乡下妇女做爰 | 国产成人无码区免费内射一片色欲 | 黑人玩弄人妻中文在线 | 丰满岳乱妇在线观看中字无码 | 性欧美疯狂xxxxbbbb | 国产办公室秘书无码精品99 | 人妻与老人中文字幕 | av人摸人人人澡人人超碰下载 | 丝袜人妻一区二区三区 | 青草青草久热国产精品 | 久久视频在线观看精品 | 久久99热只有频精品8 | 国产偷抇久久精品a片69 | 2020久久超碰国产精品最新 | 四虎永久在线精品免费网址 | 久久精品国产99精品亚洲 | 欧美成人家庭影院 | 亚洲一区二区三区 | 亚洲国产精品久久久久久 | 免费中文字幕日韩欧美 | 一本久道高清无码视频 | 2019nv天堂香蕉在线观看 | 好屌草这里只有精品 | www国产亚洲精品久久网站 | 精品乱子伦一区二区三区 | 亚洲国产欧美国产综合一区 | 2019午夜福利不卡片在线 | 精品无码av一区二区三区 | 女人被爽到呻吟gif动态图视看 | 国产精品无码一区二区桃花视频 | 国产在线一区二区三区四区五区 | 午夜精品久久久久久久 | 国产电影无码午夜在线播放 | 十八禁真人啪啪免费网站 | 中文字幕人成乱码熟女app | 亚洲精品午夜国产va久久成人 | 国产乡下妇女做爰 | 最近的中文字幕在线看视频 | 99精品视频在线观看免费 | 亚洲精品中文字幕久久久久 | 国产人妻精品一区二区三区不卡 | 亚洲精品午夜无码电影网 | 无码人中文字幕 | 亚洲人成影院在线观看 | 国产精品对白交换视频 | 无码人妻丰满熟妇区五十路百度 | 在线播放无码字幕亚洲 | 特级做a爰片毛片免费69 | 对白脏话肉麻粗话av | 亚洲一区二区三区无码久久 | 国产精品美女久久久网av | 国产人妻精品一区二区三区 | 搡女人真爽免费视频大全 | 十八禁真人啪啪免费网站 | 无码吃奶揉捏奶头高潮视频 | 国产69精品久久久久app下载 | 国产av剧情md精品麻豆 | 亚洲欧美精品伊人久久 | 亚洲一区二区三区香蕉 | 一二三四社区在线中文视频 | 99久久久国产精品无码免费 | 东京热一精品无码av | 男女下面进入的视频免费午夜 | 国产亚洲精品久久久久久 | 2019午夜福利不卡片在线 | 午夜精品久久久久久久 | 任你躁在线精品免费 | 麻豆精品国产精华精华液好用吗 | 东京一本一道一二三区 | 中文字幕亚洲情99在线 | 午夜免费福利小电影 | 久热国产vs视频在线观看 | 西西人体www44rt大胆高清 | 久久久久人妻一区精品色欧美 | 牲欲强的熟妇农村老妇女视频 | 丰满妇女强制高潮18xxxx | 久久综合九色综合欧美狠狠 | 精品国产一区二区三区四区在线看 | 亚洲欧美国产精品专区久久 | 一本色道久久综合亚洲精品不卡 | 男人和女人高潮免费网站 | 色老头在线一区二区三区 | 亚洲综合无码久久精品综合 | 久久精品中文闷骚内射 | 亚洲日韩中文字幕在线播放 | 福利一区二区三区视频在线观看 | 免费观看的无遮挡av | 成人一区二区免费视频 | 久久国产精品偷任你爽任你 | 久久人人爽人人爽人人片av高清 | 女人高潮内射99精品 | 色婷婷久久一区二区三区麻豆 | 人人澡人人透人人爽 | 亚洲综合精品香蕉久久网 | 久久人妻内射无码一区三区 | 成人片黄网站色大片免费观看 | 亚洲成a人片在线观看无码3d | 久久综合久久自在自线精品自 | 国产偷国产偷精品高清尤物 | 久久久久人妻一区精品色欧美 | 熟妇人妻激情偷爽文 | www一区二区www免费 | 国产超碰人人爽人人做人人添 | 欧美激情综合亚洲一二区 | 在教室伦流澡到高潮hnp视频 | 精品成在人线av无码免费看 | 中文精品久久久久人妻不卡 | 荫蒂添的好舒服视频囗交 | 男女下面进入的视频免费午夜 | 亚洲乱码国产乱码精品精 | 玩弄中年熟妇正在播放 | 亚洲中文字幕在线观看 | 51国偷自产一区二区三区 | 丰满少妇高潮惨叫视频 | 欧洲熟妇精品视频 | 久久熟妇人妻午夜寂寞影院 | 免费看男女做好爽好硬视频 | 国语自产偷拍精品视频偷 | 日本xxxx色视频在线观看免费 | 呦交小u女精品视频 | 性做久久久久久久久 | 精品亚洲韩国一区二区三区 | 亚洲va欧美va天堂v国产综合 | 国产精品久久久久久久影院 | 中文精品久久久久人妻不卡 | 玩弄中年熟妇正在播放 | 国产精品欧美成人 | 日产精品高潮呻吟av久久 | 国产成人无码午夜视频在线观看 | 欧美性色19p | 久久成人a毛片免费观看网站 | 狠狠噜狠狠狠狠丁香五月 | 国产亚洲人成在线播放 | 亚洲日本一区二区三区在线 | 鲁一鲁av2019在线 | 少妇一晚三次一区二区三区 | 亚洲无人区午夜福利码高清完整版 | 99久久久无码国产aaa精品 | 日本一卡2卡3卡四卡精品网站 | 永久免费观看美女裸体的网站 | 国产真实伦对白全集 | 国产婷婷色一区二区三区在线 | 亚洲精品中文字幕久久久久 | 在线观看欧美一区二区三区 | 无码国产色欲xxxxx视频 | 亚洲一区二区三区在线观看网站 | 丰满人妻精品国产99aⅴ | 久久久久99精品成人片 | 日韩精品一区二区av在线 | 欧美日本日韩 | 纯爱无遮挡h肉动漫在线播放 | 四十如虎的丰满熟妇啪啪 | 狠狠色色综合网站 | 国产av剧情md精品麻豆 | 欧美一区二区三区视频在线观看 | 久精品国产欧美亚洲色aⅴ大片 | 国产综合久久久久鬼色 | 国产欧美精品一区二区三区 | 男人的天堂2018无码 | 色五月五月丁香亚洲综合网 | 成人无码精品一区二区三区 | 午夜精品久久久内射近拍高清 | 无码午夜成人1000部免费视频 | 一二三四社区在线中文视频 | 四虎影视成人永久免费观看视频 | 中文无码成人免费视频在线观看 | 无码av中文字幕免费放 | 激情综合激情五月俺也去 | 亚洲中文字幕无码中文字在线 | 台湾无码一区二区 | 国产精品va在线观看无码 | 亚洲一区二区三区播放 | 精品无码国产自产拍在线观看蜜 | 性欧美牲交xxxxx视频 | 国产农村妇女aaaaa视频 撕开奶罩揉吮奶头视频 | 日韩亚洲欧美精品综合 | 国产精品久久久久影院嫩草 | 亚洲成av人在线观看网址 | 无码av免费一区二区三区试看 | 亚洲国产一区二区三区在线观看 | 亚洲综合无码一区二区三区 | 九九热爱视频精品 | 久久国产36精品色熟妇 | 国产一区二区三区日韩精品 | 亚洲中文字幕久久无码 | 国产精品igao视频网 | 久久99精品久久久久久 | 东京一本一道一二三区 | 两性色午夜视频免费播放 | 日本精品少妇一区二区三区 | 日本精品少妇一区二区三区 | 真人与拘做受免费视频一 | 成人试看120秒体验区 | 国产麻豆精品精东影业av网站 | 熟女俱乐部五十路六十路av | 亚洲精品一区二区三区大桥未久 | 2019午夜福利不卡片在线 | 狂野欧美性猛交免费视频 | 久久人妻内射无码一区三区 | 日产国产精品亚洲系列 | 亚洲一区二区三区在线观看网站 | 精品久久久中文字幕人妻 | 俺去俺来也www色官网 | 在线视频网站www色 | 福利一区二区三区视频在线观看 | 国内少妇偷人精品视频 | 老头边吃奶边弄进去呻吟 | 中文字幕无码av波多野吉衣 | 久精品国产欧美亚洲色aⅴ大片 | 人人妻人人澡人人爽欧美一区 | 女人被男人躁得好爽免费视频 | 亚洲成在人网站无码天堂 | 国产激情艳情在线看视频 | 男女下面进入的视频免费午夜 | 国产va免费精品观看 | 欧美日韩综合一区二区三区 | 亚洲国产av美女网站 | 亚洲日本va中文字幕 | 鲁鲁鲁爽爽爽在线视频观看 | 精品国产一区二区三区四区 | 久久婷婷五月综合色国产香蕉 | 99久久人妻精品免费一区 | 国产精品毛多多水多 | 精品国产福利一区二区 | 国产高清不卡无码视频 | 亚洲热妇无码av在线播放 | 欧洲精品码一区二区三区免费看 | 欧美 日韩 亚洲 在线 | 精品无码国产一区二区三区av | 国产精品香蕉在线观看 | 自拍偷自拍亚洲精品10p | 免费中文字幕日韩欧美 | 欧美人与善在线com | 久久亚洲中文字幕无码 | 亚洲精品国偷拍自产在线观看蜜桃 | 国产精品无码一区二区桃花视频 | 国产激情综合五月久久 | 成熟人妻av无码专区 | 日本一区二区三区免费高清 | 久久久久亚洲精品男人的天堂 | 欧美激情综合亚洲一二区 | 亚洲色偷偷男人的天堂 | 国内少妇偷人精品视频免费 | 99精品国产综合久久久久五月天 | 18禁黄网站男男禁片免费观看 | 青草视频在线播放 | 一个人看的视频www在线 | 在线a亚洲视频播放在线观看 | av在线亚洲欧洲日产一区二区 | 内射后入在线观看一区 | 无码人妻黑人中文字幕 | 一本久道久久综合婷婷五月 | 亚洲中文字幕无码中文字在线 | 在线欧美精品一区二区三区 | 久久精品中文闷骚内射 | 欧美黑人巨大xxxxx | 久久99精品久久久久久动态图 | 在线播放免费人成毛片乱码 | 国产小呦泬泬99精品 | 日韩欧美中文字幕公布 | 成人无码精品一区二区三区 | 亚洲精品综合五月久久小说 | 亚洲一区二区三区播放 | 国产成人无码一二三区视频 | 3d动漫精品啪啪一区二区中 | 好屌草这里只有精品 | 青青草原综合久久大伊人精品 | 色婷婷香蕉在线一区二区 | 亚洲欧美精品aaaaaa片 | 天天躁日日躁狠狠躁免费麻豆 | 欧美熟妇另类久久久久久不卡 | 国产成人精品视频ⅴa片软件竹菊 | 一本久久a久久精品亚洲 | 亚洲一区二区三区香蕉 | 久久精品人妻少妇一区二区三区 | 国产又爽又黄又刺激的视频 | 久久午夜无码鲁丝片午夜精品 | 国产真实乱对白精彩久久 | 无码纯肉视频在线观看 | 久久亚洲日韩精品一区二区三区 | 免费国产成人高清在线观看网站 | 欧美35页视频在线观看 | 性啪啪chinese东北女人 | 亚洲国产高清在线观看视频 | 永久黄网站色视频免费直播 | 少妇人妻大乳在线视频 | 色狠狠av一区二区三区 | 亚无码乱人伦一区二区 | 久久久无码中文字幕久... | 成熟女人特级毛片www免费 | 亚洲 a v无 码免 费 成 人 a v | av无码电影一区二区三区 | 色综合久久中文娱乐网 | 亚拍精品一区二区三区探花 | 国产激情无码一区二区 | 国产精品视频免费播放 | 99精品国产综合久久久久五月天 | 曰本女人与公拘交酡免费视频 | 欧美激情一区二区三区成人 | 亚洲天堂2017无码 | 日本乱偷人妻中文字幕 | 在线精品国产一区二区三区 | 国产偷国产偷精品高清尤物 | 偷窥日本少妇撒尿chinese | 午夜福利不卡在线视频 | 欧美自拍另类欧美综合图片区 | 欧美日本精品一区二区三区 | 亚洲国产日韩a在线播放 | 国产av无码专区亚洲awww | 中文字幕无码人妻少妇免费 | 欧美性生交xxxxx久久久 | 国产极品视觉盛宴 | 人妻无码αv中文字幕久久琪琪布 | 国内精品久久毛片一区二区 | 国产午夜视频在线观看 | 一本久道久久综合狠狠爱 | 99久久精品国产一区二区蜜芽 | 全黄性性激高免费视频 | 超碰97人人射妻 | 久热国产vs视频在线观看 | 国产人妻精品一区二区三区 | 日本在线高清不卡免费播放 | 日产精品99久久久久久 | 国产熟女一区二区三区四区五区 | 免费看少妇作爱视频 | 久久 国产 尿 小便 嘘嘘 | 丰满妇女强制高潮18xxxx | 免费中文字幕日韩欧美 | 欧美日韩在线亚洲综合国产人 | 人妻少妇精品无码专区动漫 | 亚洲一区二区三区在线观看网站 | 四虎永久在线精品免费网址 | 亚洲大尺度无码无码专区 | 一本久道久久综合狠狠爱 | 国产婷婷色一区二区三区在线 | 暴力强奷在线播放无码 | 国产成人精品无码播放 | 国产熟女一区二区三区四区五区 | 熟妇人妻无码xxx视频 | 精品无人国产偷自产在线 | 成人亚洲精品久久久久软件 | 牲欲强的熟妇农村老妇女 | 伊人久久大香线焦av综合影院 | 色婷婷欧美在线播放内射 | 精品偷拍一区二区三区在线看 | 国色天香社区在线视频 | 亚洲一区二区三区播放 | 久久人人97超碰a片精品 | 日韩av激情在线观看 | 欧美成人免费全部网站 | 麻豆成人精品国产免费 | 午夜丰满少妇性开放视频 | 亚洲熟妇色xxxxx欧美老妇y | 无码吃奶揉捏奶头高潮视频 | 国产国产精品人在线视 | 丰满诱人的人妻3 | 亚洲国产精品无码一区二区三区 | 九月婷婷人人澡人人添人人爽 | 国产真实夫妇视频 | 又色又爽又黄的美女裸体网站 | 无码午夜成人1000部免费视频 | 欧美精品在线观看 | 成人精品天堂一区二区三区 | 国内精品久久毛片一区二区 | 国产明星裸体无码xxxx视频 | 精品久久久无码人妻字幂 | 国产亚洲精品久久久久久久久动漫 | 色婷婷欧美在线播放内射 | 精品国产aⅴ无码一区二区 | 亚洲成av人片天堂网无码】 | 内射欧美老妇wbb | 亚洲国产精品无码久久久久高潮 | 蜜臀aⅴ国产精品久久久国产老师 | 久久国产精品萌白酱免费 | 丰满诱人的人妻3 | 性色欲情网站iwww九文堂 | 国产成人无码av在线影院 | 学生妹亚洲一区二区 | 2020久久超碰国产精品最新 | 亚洲男女内射在线播放 | 露脸叫床粗话东北少妇 | 精品国产一区二区三区av 性色 | 久久人妻内射无码一区三区 | 国产乱码精品一品二品 | 夜精品a片一区二区三区无码白浆 | 国产美女极度色诱视频www | 精品国产精品久久一区免费式 | 永久免费精品精品永久-夜色 | 色婷婷av一区二区三区之红樱桃 | 国产午夜亚洲精品不卡下载 | 精品国产成人一区二区三区 | 牛和人交xxxx欧美 | 俺去俺来也www色官网 | 亚洲经典千人经典日产 | 99久久婷婷国产综合精品青草免费 | 国产特级毛片aaaaaaa高清 | 国产av人人夜夜澡人人爽麻豆 | 久久久久亚洲精品中文字幕 | 亚洲日韩一区二区 | 天干天干啦夜天干天2017 |