色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

三次輸入密碼錯誤怎么辦?

jf_ro2CN3Fa ? 來源:稀土掘金 ? 2023-11-28 10:00 ? 次閱讀

1 故事背景

忘記密碼這件事,相信絕大多數人都遇到過,輸一次錯一次,錯到幾次以上,就不允許你繼續嘗試了。

但當你嘗試重置密碼,又發現新密碼不能和原密碼重復:

雖然,但是,密碼還是很重要的,順便我有了一個問題:三次輸錯密碼后,系統是怎么做到不讓我繼續嘗試的?

2 我想了想,有如下幾個問題需要搞定

是只有輸錯密碼才鎖定,還是賬戶名和密碼任何一個輸錯就鎖定?

輸錯之后也不是完全凍結,為啥隔了幾分鐘又可以重新輸了?

技術棧到底麻不麻煩?

去網上搜了搜,也問了下ChatGPT,找到一套解決方案:SpringBoot+Redis+Lua腳本。

這套方案也不算新,很早就有人在用了,不過難得是自己想到的問題和解法,就記錄一下吧。

順便回答一下上面的三個問題:

鎖定的是IP,不是輸入的賬戶名或者密碼,也就是說任一一個輸錯3次就會被鎖定

Redis的Lua腳本中實現了key過期策略,當key消失時鎖定自然也就消失了

技術棧同SpringBoot+Redis+Lua腳本

3 那么自己動手實現一下

前端部分

首先寫一個賬密輸入頁面,使用很簡單HTML加表單提交




登錄頁面




用戶名

密碼





效果如下:

e9fe2882-8b73-11ee-939d-92fbcf53809c.png

后端部分

技術選型分析

首先我們畫一個流程圖來分析一下這個登錄限制流程

ea140d8c-8b73-11ee-939d-92fbcf53809c.png

從流程圖上看,首先訪問次數的統計與判斷不是在登錄邏輯執行后,而是執行前就加1了;

其次登錄邏輯的成功與失敗并不會影響到次數的統計;

最后還有一點流程圖上沒有體現出來,這個次數的統計是有過期時間的,當過期之后又可以重新登錄了。

那為什么是Redis+Lua腳本呢?

Redis的選擇不難看出,這個流程比較重要的是存在一個用來計數的變量,這個變量既要滿足分布式讀寫需求,還要滿足全局遞增或遞減的需求,那Redis的incr方法是最優選了。

那為什么需要Lua腳本呢?流程上在驗證用戶操作前有些操作,如圖:

ea32f9c2-8b73-11ee-939d-92fbcf53809c.png

這里至少有3步Redis的操作,get、incr、expire,如果全放到應用里面來操作,有點慢且浪費資源。

Lua腳本的優點如下:

減少網絡開銷。 可以將多個請求通過腳本的形式一次發送,減少網絡時延。

原子操作。 Redis會將整個腳本作為一個整體執行,中間不會被其他請求插入。因此在腳本運行過程中無需擔心會出現競態條件,無需使用事務。

復用。 客戶端發送的腳本會永久存在redis中,這樣其他客戶端可以復用這一腳本,而不需要使用代碼完成相同的邏輯。

最后為了增加功能的復用性,我打算使用Java注解的方式實現這個功能。

代碼實現

項目結構如下

ea4302ae-8b73-11ee-939d-92fbcf53809c.png

配置文件

pom.xml



4.0.0

org.springframework.boot
spring-boot-starter-parent
2.7.11
 

com.example
LoginLimit
0.0.1-SNAPSHOT
LoginLimit
DemoprojectforSpringBoot

1.8



org.springframework.boot
spring-boot-starter-web



org.springframework.boot
spring-boot-starter-test
test

 

org.springframework.boot
spring-boot-starter-data-redis

 

redis.clients
jedis

 

org.aspectj
aspectjweaver

 

org.apache.commons
commons-lang3

 

com.google.guava
guava
23.0

 

org.projectlombok
lombok
true






org.springframework.boot
spring-boot-maven-plugin





application.properties

#Redis配置
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.password=
spring.redis.timeout=1000
#Jedis配置
spring.redis.jedis.pool.min-idle=0
spring.redis.jedis.pool.max-idle=500
spring.redis.jedis.pool.max-active=2000
spring.redis.jedis.pool.max-wait=10000

注解部分

LimitCount.java

packagecom.example.loginlimit.annotation;

importjava.lang.annotation.ElementType;
importjava.lang.annotation.Retention;
importjava.lang.annotation.RetentionPolicy;
importjava.lang.annotation.Target;

/**
*次數限制注解
*作用在接口方法上
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public@interfaceLimitCount{
/**
*資源名稱,用于描述接口功能
*/
Stringname()default"";

/**
*資源key
*/
Stringkey()default"";

/**
*keyprefix
*
*@return
*/
Stringprefix()default"";

/**
*時間的,單位秒
*默認60s過期
*/
intperiod()default60;

/**
*限制訪問次數
*默認3次
*/
intcount()default3;
}

核心處理邏輯類:LimitCountAspect.java

packagecom.example.loginlimit.aspect;

importjava.io.Serializable;
importjava.lang.reflect.Method;
importjava.util.Objects;

importjavax.servlet.http.HttpServletRequest;

importcom.example.loginlimit.annotation.LimitCount;
importcom.example.loginlimit.util.IPUtil;
importcom.google.common.collect.ImmutableList;
importlombok.extern.slf4j.Slf4j;
importorg.apache.commons.lang3.StringUtils;
importorg.aspectj.lang.ProceedingJoinPoint;
importorg.aspectj.lang.annotation.Around;
importorg.aspectj.lang.annotation.Aspect;
importorg.aspectj.lang.annotation.Pointcut;
importorg.aspectj.lang.reflect.MethodSignature;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.data.redis.core.RedisTemplate;
importorg.springframework.data.redis.core.script.DefaultRedisScript;
importorg.springframework.data.redis.core.script.RedisScript;
importorg.springframework.stereotype.Component;
importorg.springframework.web.context.request.RequestContextHolder;
importorg.springframework.web.context.request.ServletRequestAttributes;

@Slf4j
@Aspect
@Component
publicclassLimitCountAspect{

privatefinalRedisTemplatelimitRedisTemplate;

@Autowired
publicLimitCountAspect(RedisTemplatelimitRedisTemplate){
this.limitRedisTemplate=limitRedisTemplate;
}

@Pointcut("@annotation(com.example.loginlimit.annotation.LimitCount)")
publicvoidpointcut(){
//donothing
}

@Around("pointcut()")
publicObjectaround(ProceedingJoinPointpoint)throwsThrowable{
HttpServletRequestrequest=((ServletRequestAttributes)Objects.requireNonNull(
RequestContextHolder.getRequestAttributes())).getRequest();

MethodSignaturesignature=(MethodSignature)point.getSignature();
Methodmethod=signature.getMethod();
LimitCountannotation=method.getAnnotation(LimitCount.class);
//注解名稱
Stringname=annotation.name();
//注解key
Stringkey=annotation.key();
//訪問IP
Stringip=IPUtil.getIpAddr(request);
//過期時間
intlimitPeriod=annotation.period();
//過期次數
intlimitCount=annotation.count();

ImmutableListkeys=ImmutableList.of(StringUtils.join(annotation.prefix()+"_",key,ip));
StringluaScript=buildLuaScript();
RedisScriptredisScript=newDefaultRedisScript<>(luaScript,Number.class);
Numbercount=limitRedisTemplate.execute(redisScript,keys,limitCount,limitPeriod);
log.info("IP:{}第{}次訪問key為{},描述為[{}]的接口",ip,count,keys,name);
if(count!=null&&count.intValue()<=?limitCount)?{
????????????return?point.proceed();
????????}?else?{
????????????return?"接口訪問超出頻率限制";
????????}
????}

????/**
?????*?限流腳本
?????*?調用的時候不超過閾值,則直接返回并執行計算器自加。
?????*
?????*?@return?lua腳本
?????*/
????private?String?buildLuaScript()?{
????????return?"local?c"?+
????????????"
c?=?redis.call('get',KEYS[1])"?+
????????????"
if?c?and?tonumber(c)?>tonumber(ARGV[1])then"+
"
returnc;"+
"
end"+
"
c=redis.call('incr',KEYS[1])"+
"
iftonumber(c)==1then"+
"
redis.call('expire',KEYS[1],ARGV[2])"+
"
end"+
"
returnc;";
}

}

獲取IP地址的功能我寫了一個工具類IPUtil.java,代碼如下:

packagecom.example.loginlimit.util;

importjavax.servlet.http.HttpServletRequest;

publicclassIPUtil{

privatestaticfinalStringUNKNOWN="unknown";

protectedIPUtil(){

}

/**
*獲取IP地址
*使用Nginx等反向代理軟件,則不能通過request.getRemoteAddr()獲取IP地址
*如果使用了多級反向代理的話,X-Forwarded-For的值并不止一個,而是一串IP地址,
*X-Forwarded-For中第一個非unknown的有效IP字符串,則為真實IP地址
*/
publicstaticStringgetIpAddr(HttpServletRequestrequest){
Stringip=request.getHeader("x-forwarded-for");
if(ip==null||ip.length()==0||UNKNOWN.equalsIgnoreCase(ip)){
ip=request.getHeader("Proxy-Client-IP");
}
if(ip==null||ip.length()==0||UNKNOWN.equalsIgnoreCase(ip)){
ip=request.getHeader("WL-Proxy-Client-IP");
}
if(ip==null||ip.length()==0||UNKNOWN.equalsIgnoreCase(ip)){
ip=request.getRemoteAddr();
}
return"0000:1".equals(ip)?"127.0.0.1":ip;
}

}

另外就是Lua限流腳本的說明,腳本代碼如下:

privateStringbuildLuaScript(){
return"localc"+
"
c=redis.call('get',KEYS[1])"+
"
ifcandtonumber(c)>tonumber(ARGV[1])then"+
"
returnc;"+
"
end"+
"
c=redis.call('incr',KEYS[1])"+
"
iftonumber(c)==1then"+
"
redis.call('expire',KEYS[1],ARGV[2])"+
"
end"+
"
returnc;";
}

這段腳本有一個判斷, tonumber(c) > tonumber(ARGV[1])這行表示如果當前key 的值大于了limitCount,直接返回;否則調用incr方法進行累加1,且調用expire方法設置過期時間。

最后就是RedisConfig.java,代碼如下:

packagecom.example.loginlimit.config;

importjava.io.IOException;
importjava.io.Serializable;
importjava.time.Duration;
importjava.util.Arrays;

importcom.fasterxml.jackson.core.JsonProcessingException;
importcom.fasterxml.jackson.databind.ObjectMapper;
importorg.apache.commons.lang3.StringUtils;
importorg.springframework.beans.factory.annotation.Value;
importorg.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
importorg.springframework.cache.CacheManager;
importorg.springframework.cache.annotation.CachingConfigurerSupport;
importorg.springframework.cache.interceptor.KeyGenerator;
importorg.springframework.context.annotation.Bean;
importorg.springframework.context.annotation.Configuration;
importorg.springframework.data.redis.cache.RedisCacheManager;
importorg.springframework.data.redis.connection.RedisConnectionFactory;
importorg.springframework.data.redis.connection.RedisPassword;
importorg.springframework.data.redis.connection.RedisStandaloneConfiguration;
importorg.springframework.data.redis.connection.jedis.JedisClientConfiguration;
importorg.springframework.data.redis.connection.jedis.JedisConnectionFactory;
importorg.springframework.data.redis.core.RedisTemplate;
importorg.springframework.data.redis.core.StringRedisTemplate;
importorg.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
importorg.springframework.data.redis.serializer.RedisSerializer;
importorg.springframework.data.redis.serializer.SerializationException;
importorg.springframework.data.redis.serializer.StringRedisSerializer;
importredis.clients.jedis.JedisPool;
importredis.clients.jedis.JedisPoolConfig;

@Configuration
publicclassRedisConfigextendsCachingConfigurerSupport{

@Value("${spring.redis.host}")
privateStringhost;

@Value("${spring.redis.port}")
privateintport;

@Value("${spring.redis.password}")
privateStringpassword;

@Value("${spring.redis.timeout}")
privateinttimeout;

@Value("${spring.redis.jedis.pool.max-idle}")
privateintmaxIdle;

@Value("${spring.redis.jedis.pool.max-wait}")
privatelongmaxWaitMillis;

@Value("${spring.redis.database:0}")
privateintdatabase;

@Bean
publicJedisPoolredisPoolFactory(){
JedisPoolConfigjedisPoolConfig=newJedisPoolConfig();
jedisPoolConfig.setMaxIdle(maxIdle);
jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
if(StringUtils.isNotBlank(password)){
returnnewJedisPool(jedisPoolConfig,host,port,timeout,password,database);
}else{
returnnewJedisPool(jedisPoolConfig,host,port,timeout,null,database);
}
}

@Bean
JedisConnectionFactoryjedisConnectionFactory(){
RedisStandaloneConfigurationredisStandaloneConfiguration=newRedisStandaloneConfiguration();
redisStandaloneConfiguration.setHostName(host);
redisStandaloneConfiguration.setPort(port);
redisStandaloneConfiguration.setPassword(RedisPassword.of(password));
redisStandaloneConfiguration.setDatabase(database);

JedisClientConfiguration.JedisClientConfigurationBuilderjedisClientConfiguration=JedisClientConfiguration
.builder();
jedisClientConfiguration.connectTimeout(Duration.ofMillis(timeout));
jedisClientConfiguration.usePooling();
returnnewJedisConnectionFactory(redisStandaloneConfiguration,jedisClientConfiguration.build());
}

@Bean(name="redisTemplate")
@SuppressWarnings({"rawtypes"})
@ConditionalOnMissingBean(name="redisTemplate")
publicRedisTemplateredisTemplate(RedisConnectionFactoryredisConnectionFactory){
RedisTemplatetemplate=newRedisTemplate<>();
//使用fastjson序列化
JacksonRedisSerializerjacksonRedisSerializer=newJacksonRedisSerializer<>(Object.class);
//value值的序列化采用fastJsonRedisSerializer
template.setValueSerializer(jacksonRedisSerializer);
template.setHashValueSerializer(jacksonRedisSerializer);
//key的序列化采用StringRedisSerializer
template.setKeySerializer(newStringRedisSerializer());
template.setHashKeySerializer(newStringRedisSerializer());

template.setConnectionFactory(redisConnectionFactory);
returntemplate;
}

//緩存管理器
@Bean
publicCacheManagercacheManager(RedisConnectionFactoryredisConnectionFactory){
RedisCacheManager.RedisCacheManagerBuilderbuilder=RedisCacheManager.RedisCacheManagerBuilder
.fromConnectionFactory(redisConnectionFactory);
returnbuilder.build();
}

@Bean
@ConditionalOnMissingBean(StringRedisTemplate.class)
publicStringRedisTemplatestringRedisTemplate(RedisConnectionFactoryredisConnectionFactory){
StringRedisTemplatetemplate=newStringRedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
returntemplate;
}

@Bean
publicKeyGeneratorwiselyKeyGenerator(){
return(target,method,params)->{
StringBuildersb=newStringBuilder();
sb.append(target.getClass().getName());
sb.append(method.getName());
Arrays.stream(params).map(Object::append);
returnsb.toString();
};
}

@Bean
publicRedisTemplatelimitRedisTemplate(RedisConnectionFactoryredisConnectionFactory){
RedisTemplatetemplate=newRedisTemplate<>();
template.setKeySerializer(newStringRedisSerializer());
template.setValueSerializer(newGenericJackson2JsonRedisSerializer());
template.setConnectionFactory(redisConnectionFactory);
returntemplate;
}
}

classJacksonRedisSerializerimplementsRedisSerializer{
privateClassclazz;
privateObjectMappermapper;

JacksonRedisSerializer(Classclazz){
super();
this.clazz=clazz;
this.mapper=newObjectMapper();
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
}

@Override
publicbyte[]serialize(Tt)throwsSerializationException{
try{
returnmapper.writeValueAsBytes(t);
}catch(JsonProcessingExceptione){
e.printStackTrace();
returnnull;
}
}

@Override
publicTdeserialize(byte[]bytes)throwsSerializationException{
if(bytes.length<=?0)?{
????????????return?null;
????????}
????????try?{
????????????return?mapper.readValue(bytes,?clazz);
????????}?catch?(IOException?e)?{
????????????e.printStackTrace();
????????????return?null;
????????}
????}
}

LoginController.java

packagecom.example.loginlimit.controller;

importjavax.servlet.http.HttpServletRequest;

importcom.example.loginlimit.annotation.LimitCount;
importlombok.extern.slf4j.Slf4j;
importorg.apache.commons.lang3.StringUtils;
importorg.springframework.web.bind.annotation.GetMapping;
importorg.springframework.web.bind.annotation.RequestParam;
importorg.springframework.web.bind.annotation.RestController;

@Slf4j
@RestController
publicclassLoginController{

@GetMapping("/login")
@LimitCount(key="login",name="登錄接口",prefix="limit")
publicStringlogin(
@RequestParam(required=true)Stringusername,
@RequestParam(required=true)Stringpassword,HttpServletRequestrequest)throwsException{
if(StringUtils.equals("張三",username)&&StringUtils.equals("123456",password)){
return"登錄成功";
}
return"賬戶名或密碼錯誤";
}

}

LoginLimitApplication.java

packagecom.example.loginlimit;

importorg.springframework.boot.SpringApplication;
importorg.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
publicclassLoginLimitApplication{

publicstaticvoidmain(String[]args){
SpringApplication.run(LoginLimitApplication.class,args);
}

}

4 演示一下效果

ea62eb28-8b73-11ee-939d-92fbcf53809c.png

上面這套限流的邏輯感覺用在小型或中型的項目上應該問題不大,不過目前的登錄很少有直接鎖定賬號不能輸入的,一般都是彈出一個驗證碼框,讓你輸入驗證碼再提交。我覺得用我這套邏輯改改應該不成問題,核心還是接口嘗試次數的限制嘛!

審核編輯:黃飛

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • ip地址
    +關注

    關注

    0

    文章

    301

    瀏覽量

    17032
  • Redis
    +關注

    關注

    0

    文章

    374

    瀏覽量

    10871
  • ChatGPT
    +關注

    關注

    29

    文章

    1558

    瀏覽量

    7596
  • SpringBoot
    +關注

    關注

    0

    文章

    173

    瀏覽量

    177

原文標題:三次輸錯密碼后,系統是怎么做到不讓我繼續嘗試的?

文章出處:【微信號:芋道源碼,微信公眾號:芋道源碼】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    自動布線換了N 還是那么多錯誤 怎么辦

    `RT 自動布線原件位置換了N 還是那么多錯誤怎么辦啊`
    發表于 01-02 20:46

    我這個設計怎么添加讓密碼輸入三次錯誤失效的程序

    怎么把各模塊獨立出來,變為子程序。密碼怎么寫三次輸入錯誤失效的程序?
    發表于 06-18 12:07

    三次握手,四揮手你懂嗎

    程序員面試被問到“三次握手,四揮手”怎么辦
    發表于 04-08 07:23

    手機密碼鎖忘了怎么辦?教你解手機密碼

    手機密碼鎖忘了怎么辦? 解話機鎖:*2767*2878#/*2767*7377#   星碼片復位:*2767*3855# 也可用于解機鎖或卡鎖   星顯溫度、電池容量:*#022
    發表于 02-25 09:49 ?74.5w次閱讀

    電腦密碼忘記了怎么辦_win7系統電腦忘記密碼的處理方法

    現在使用電腦的人越來越多,而各種各樣的密碼也越來越多,很多人在剛剛設置了電腦密碼后一下就忘記了。電腦密碼忘記了怎么辦?并且現在使用WIN7系統的人也越來越多,WIN7電腦密
    發表于 10-23 17:00 ?77.6w次閱讀

    TCP三次握手的過程描述

    本文檔主要描述TCP三次握手的過程,一個完整的三次握手也就是 請求---應答---再次確認
    發表于 03-02 15:37 ?8次下載

    蘋果iphone7plus的下載密碼忘了怎么辦

    忘記手機解鎖密碼是用戶經常忘記的事情,有很多人都不得不去刷機解鎖重新設置。前幾天有個人問小編說iPhone7Plus的解鎖密碼忘記了怎么辦?今天小編就來說說蘋果iPhone解鎖密碼那些
    發表于 10-13 16:40 ?8437次閱讀

    若忘記了Linux系統的root密碼,該怎么辦?

    很多朋友經常會忘記Linux系統的root密碼,linux系統忘記root密碼的情況該怎么辦呢?
    的頭像 發表于 10-15 16:49 ?1.3w次閱讀

    蘋果iPad忘記了Apple ID密碼怎么辦

    Apple ID密碼忘了怎么辦?蘋果用戶最常見的一個問題是忘記了Apple ID密碼,這樣就沒辦法從App Store下載應用了,那么如何才能將密碼找回來呢?一般在蘋果
    的頭像 發表于 09-11 12:10 ?9w次閱讀
    蘋果iPad忘記了Apple ID<b class='flag-5'>密碼</b>該<b class='flag-5'>怎么辦</b>?

    三次諧波是什么,三次諧波會造成哪些影響

    每次平臺文章過后看見很多朋友問到底什么是三次諧波跟電工有什么關系?會產生怎樣的影響?如何治理或防止三次諧波的滋生?別急今天就出一期有關三次諧波的全面講解! ①三次諧波是什么? 答:
    發表于 11-16 15:44 ?3.1w次閱讀
    <b class='flag-5'>三次</b>諧波是什么,<b class='flag-5'>三次</b>諧波會造成哪些影響

    deepin密碼忘了怎么辦_deepin分區方案

    為了安全考慮,在安裝 Deepin 系統的時候一定會要用戶設置好密碼,你只有知道電腦的登錄密碼后,才能夠登錄進行一系列的操作,可是萬一忘記了登錄密碼怎么辦呢?這里就教大家一招重設 D
    發表于 11-11 14:31 ?1.1w次閱讀

    windows不能更改密碼怎么辦

     很多電腦用戶為了加強電腦安全或保護個人隱私會給電腦設置開機密碼,只有正確輸入密碼后才能進入桌面操作。但是有些用戶在設置密碼時卻遇到了一些問題,例如系統彈出Windows不能更改
    的頭像 發表于 12-23 15:24 ?1.1w次閱讀

    MySQL密碼忘記了怎么辦?MySQL密碼快速重置方法步驟命令示例!

    MySQL密碼忘記了怎么辦?MySQL密碼快速重置方法步驟命令示例! MySQL是一種常用的關系型數據庫管理系統,如果你忘記了MySQL的密碼,不必擔心,可以通過一些簡單的步驟來快速重
    的頭像 發表于 01-12 16:06 ?741次閱讀

    說說TCP三次握手的過程?為什么是三次而不是兩、四?

    說說TCP三次握手的過程?為什么是三次而不是兩、四? TCP三次握手是建立TCP連接的過程,確保數據的可靠傳輸。它是由發送端和接收端完成
    的頭像 發表于 02-04 11:03 ?674次閱讀

    諧波和三次諧波區別 二諧波危害沒有三次諧波大?

    諧波和三次諧波區別 二諧波危害沒有三次諧波大? 在現代電力系統中,諧波問題逐漸引起人們的關注。諧波是指頻率是基波頻率的倍數的電流或電壓成分。二
    的頭像 發表于 04-08 17:11 ?5799次閱讀
    主站蜘蛛池模板: 成人在线小视频| 在线精品视频免费观看| 精品一区二区三区色花堂| 伊人久久大香| 欧美日韩888在线观看| 高清视频在线观看SEYEYE| 天堂岛www| 久久久免费观成人影院| 9420高清免费观看在线大全| 免费在线a| 搞基福利社| 午夜影院一区二区三区| 久欠热视频精品首页| A片毛片免费视频在线看| 国产成人精品一区二区三区视频 | 91福利在线观看| 欧美 亚洲 有码中文字幕| 国产第81页| 伊人色综合久久大香| 捏揉舔水插按摩师| 国产精品久久久久久久久久久| 亚洲欧美日韩在线码不卡| 美女18黄| 吃奶摸下的羞羞漫画| 亚洲精品高清中文字幕完整版| 就操成人网| 国产成人高清视频| 野花视频在线观看免费最新动漫| 欧美精品v欧洲高清| 国产露脸A片国语露对白| 影音先锋色小姐| 失禁h啪肉尿出来高h| 久久99re8热在线播放| 99久久99| 亚洲免费无码av线观看| 男男h啪肉np文总受| 国产亚洲精品久久久999蜜臀| 96.8在线收听| 无套日出白浆在线播放| 久就热视频精品免费99| 超碰免费视频部落格|