欧美一级特黄大片做受成人-亚洲成人一区二区电影-激情熟女一区二区三区-日韩专区欧美专区国产专区

SpringBoot+SpringSecurity學習筆記實現(xiàn)短信驗證碼+登錄功能

在 Spring Security 中基于表單的認證模式,默認就是密碼帳號登錄認證,那么對于短信驗證碼+登錄的方式,Spring Security 沒有現(xiàn)成的接口可以使用,所以需要自己的封裝一個類似的認證過濾器和認證處理器實現(xiàn)短信認證。

10余年專業(yè)網(wǎng)站制作公司歷程,堅持以創(chuàng)新為先導的網(wǎng)站服務,服務超過近1000家企業(yè)及個人,涉及網(wǎng)站設計、成都App制作、微信開發(fā)、平面設計、互聯(lián)網(wǎng)整合營銷等多個領域。在不同行業(yè)和領域給人們的工作和生活帶來美好變化。

短信驗證碼認證

驗證碼對象類設計

和圖片驗證碼一樣,需要自己封裝一個驗證碼對象,用來生成手機驗證碼并發(fā)送給手機。因為圖片驗證碼和手機驗證碼對象的區(qū)別就在于前者多了個圖片對象,所以兩者共同部分抽象出來可以設計成一個ValidateCode類,這個類里面只存放驗證碼和過期時間,短信驗證碼直接使用這個類即可:

import java.time.LocalDateTime;

import lombok.Data;

@Data
public class ValidateCode {

    private String code;

    private LocalDateTime expireTime;

    public ValidateCode(String code, int expireIn){
        this.code = code;
        this.expireTime = LocalDateTime.now().plusSeconds(expireIn);
    }

    public boolean isExpried() {
        return LocalDateTime.now().isAfter(getExpireTime());
    }

    public ValidateCode(String code, LocalDateTime expireTime) {
        super();
        this.code = code;
        this.expireTime = expireTime;
    }

圖片驗證碼承繼此類:

import java.awt.image.BufferedImage;
import java.time.LocalDateTime;

import org.woodwhales.king.validate.code.ValidateCode;

import lombok.Data;
import lombok.EqualsAndHashCode;

@Data
@EqualsAndHashCode(callSuper=false)
public class ImageCode extends ValidateCode {

    private BufferedImage image;

    public ImageCode(BufferedImage image, String code, int expireId) {
        super(code, LocalDateTime.now().plusSeconds(expireId));
        this.image = image;
    }

    public ImageCode(BufferedImage image, String code, LocalDateTime localDateTime) {
        super(code, localDateTime);
        this.image = image;
    }

}

驗證碼生成類設計

由于圖片和短信類均可以生成相應的驗證碼,所以直接設計一個驗證碼生成接口,具體實現(xiàn)類根據(jù)業(yè)務進行實現(xiàn):

import org.springframework.web.context.request.ServletWebRequest;

public interface ValidateCodeGenerator {

    ValidateCode generate(ServletWebRequest request);

}

這里的傳參設計成了ServletWebRequest是能夠根據(jù)前端請求中的參數(shù)進行不同的業(yè)務實現(xiàn)
目前實現(xiàn)累只有圖片生成器和驗證碼生成器:

// 圖片驗證碼生成器
@Component("imageCodeGenerator")
public class ImageCodeGenerator implements ValidateCodeGenerator {

    /**
     * 生成圖形驗證碼
     * @param request
     * @return
     */
    @Override
    public ValidateCode generate(ServletWebRequest request) {

        ……

        return new ImageCode(image, sRand, SecurityConstants.EXPIRE_SECOND);

    }
}

// 短信驗證碼生成器
@Component("smsCodeGenerator")
public class SmsCodeGenerator implements ValidateCodeGenerator {

    @Override
    public ValidateCode generate(ServletWebRequest request) {
        String code = RandomStringUtils.randomNumeric(SecurityConstants.SMS_RANDOM_SIZE);
        return new ValidateCode(code, SecurityConstants.SMS_EXPIRE_SECOND);
    }

}

短信驗證碼發(fā)送接口設計

短信驗證碼生成之后,需要設計接口依賴短信服務提供商進行驗證碼發(fā)送,因此至少設計一個統(tǒng)一的接口,供短信服務提供商生成發(fā)送短信服務:

public interface SmsCodeSender {
// 至少需要手機號和驗證碼
void send(String mobile, String code);

}
為了演示,設計一個虛擬的默認×××,只在日志文件中打印一行l(wèi)og:

import org.springframework.stereotype.Service;

import lombok.extern.slf4j.Slf4j;

/**

  • 短信發(fā)送模擬
  • @author Administrator
  • */@Slf4j
    br/>@Slf4j
    public class DefaultSmsCodeSender implements SmsCodeSender {

    @Override
    public void send(String mobile, String code) {
    log.debug("send to mobile :{}, code : {}", mobile, code);
    }
    }
    短信驗證碼請求Controller

所有驗證碼的請求都在統(tǒng)一的ValidateCodeController里,這里注入了兩個驗證碼生成器ValidateCodeGenerator,后期可以利用 spring 的依賴查找/搜索技巧來重構代碼,另外所有的請求也是可以做成動態(tài)配置,這里臨時全部 hardCode 在代碼里:

import java.io.IOException;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.social.connect.web.SessionStrategy;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.ServletRequestUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.ServletWebRequest;
import org.woodwhales.king.core.commons.SecurityConstants;
import org.woodwhales.king.validate.code.ValidateCode;
import org.woodwhales.king.validate.code.ValidateCodeGenerator;
import org.woodwhales.king.validate.code.image.ImageCode;
import org.woodwhales.king.validate.code.sms.DefaultSmsCodeSender;

@RestController
public class ValidateCodeController {

@Autowired
private SessionStrategy sessionStrategy;

@Autowired
private ValidateCodeGenerator imageCodeGenerator;

@Autowired
private ValidateCodeGenerator smsCodeGenerator;

@Autowired
private DefaultSmsCodeSender defaultSmsCodeSender;

@GetMapping("code/image")
public void createImageCode(HttpServletRequest request, HttpServletResponse response) throws IOException {
    ImageCode imageCode = (ImageCode)imageCodeGenerator.generate(new ServletWebRequest(request));
    sessionStrategy.setAttribute(new ServletWebRequest(request), SecurityConstants.SESSION_KEY, imageCode);
    ImageIO.write(imageCode.getImage(), "JPEG", response.getOutputStream());
}

@GetMapping("code/sms")
public void createSmsCode(HttpServletRequest request, HttpServletResponse response) throws ServletRequestBindingException {
    ValidateCode smsCode = smsCodeGenerator.generate(new ServletWebRequest(request));
    sessionStrategy.setAttribute(new ServletWebRequest(request), SecurityConstants.SESSION_KEY, smsCode);
    String mobile = ServletRequestUtils.getStringParameter(request, "mobile");
    defaultSmsCodeSender.send(mobile, smsCode.getCode());
}

}
從上述代碼中可以看出圖片驗證碼和短信驗證碼的生成請求邏輯是相似的:首先調用驗證碼生成接口生成驗證碼,然后將驗證碼放入 session 中,最后將驗證碼返回給前端或者用戶。因此這個套路流程可以抽象成一個模板方法,以增強代碼的可維護性和可擴展性。

用一張圖來表述重構后的代碼結構:

SpringBoot + Spring Security 學習筆記實現(xiàn)短信驗證碼+登錄功能

隨機驗證碼過濾器設計

由于圖片和手機都會產(chǎn)生驗證碼,后期還可以通過郵件發(fā)送隨機驗證碼的方式進行隨機驗證碼登錄驗證,因此將隨機驗證碼的認證可以獨立封裝在一個隨機驗證碼過濾器中,并且這個過濾器在整個 spring security 過濾器鏈的最前端(它是第一道認證墻)。

隨機驗證碼過濾器只要繼承 spring 框架中的OncePerRequestFilter即可保證這個過濾器在請求來的時候只被調用一次,具體代碼實現(xiàn)參見文末源碼。

這里重點解釋一下如何將隨機驗證碼過濾器配置到 spring security 過濾器認證最前端,需要重寫SecurityConfigurerAdapter的configure()方法,并將自定義的過濾器放到AbstractPreAuthenticatedProcessingFilter過濾器之前即可:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;
import org.springframework.stereotype.Component;

import javax.servlet.Filter;

@Component
public class ValidateCodeSecurityConfig extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {

@Autowired
private Filter validateCodeFilter;

@Override
public void configure(HttpSecurity http) throws Exception {
    super.configure(http);
    http.addFilterBefore(validateCodeFilter, AbstractPreAuthenticatedProcessingFilter.class);
}

}
短信驗證碼認證

在自定義短信登錄認證流程之前,建議可以移步到之前的文章:SpringBoot + Spring Security 學習筆記(二)安全認證流程源碼詳解,了解清除用戶密碼的認證流程才能更容易理解下面這張經(jīng)典的流程圖:

SpringBoot + Spring Security 學習筆記實現(xiàn)短信驗證碼+登錄功能

左側是用戶+密碼的認證流程,整體的流程就是經(jīng)過用戶名+密碼認證過濾器認證,將請求封裝成 token 并注入到 AutheticationMananger 中,之后由默認的認證校驗器進行校驗,在校驗的過程中會調用 UserDetailsService 接口進行 token 校驗,當校驗成功之后,就會將已經(jīng)認證的 token 放到 SecurityContextHolder 中。

同理,由于短信登錄方式只需要使用隨機驗證碼進行校驗而不需要密碼登錄功能,當校驗成功之后就認為用戶認證成功了,因此需要仿造左側的流程開發(fā)自定義的短信登錄認證 token,這個 token 只需要存放手機號即可,在token 校驗的過程中,不能使用默認的校驗器了,需要自己開發(fā)校驗當前自定義 token 的校驗器,最后將自定義的過濾器和校驗器配置到 spring security 框架中即可。

注意:短信隨機驗證碼的驗證過程是在 SmsCodeAuthticationFIlter 之前就已經(jīng)完成。
短信登錄認證Token

仿造UsernamePasswordAuthenticationToken設計一個屬于短信驗證的認證 token 對象,為什么要自定義一個短信驗證的 token,spring security 框架不只提供了用戶名+密碼的驗證方式,用戶認證是否成功,最終看的就是SecurityContextHolder對象中是否有對應的AuthenticationToken,因此要設計一個認證對象,當認證成功之后,將其設置到SecurityContextHolder即可。

import java.util.Collection;

import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.SpringSecurityCoreVersion;

public class SmsCodeAuthenticationToken extends AbstractAuthenticationToken {

private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;

private final Object principal;

public SmsCodeAuthenticationToken(Object mobile) {
    super(null);
    this.principal = mobile;
    setAuthenticated(false);
}

public SmsCodeAuthenticationToken(Object mobile, Collection<? extends GrantedAuthority> authorities) {
    super(authorities);
    this.principal = mobile;
    super.setAuthenticated(true); // must use super, as we override
}

public Object getPrincipal() {
    return this.principal;
}

public Object getCredentials() {
    return null;
}

public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
    if (isAuthenticated) {
        throw new IllegalArgumentException("Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");
    }

    super.setAuthenticated(false);
}

@Override
public void eraseCredentials() {
    super.eraseCredentials();
}

}
從AuthenticationToken接口可以看到,現(xiàn)在框架中有我們自己定義短信登錄的 token 了:
SpringBoot + Spring Security 學習筆記實現(xiàn)短信驗證碼+登錄功能

短信登錄認證過濾器

短信驗證碼的過濾器設計思路同理,仿造UsernamePasswordAuthenticationFilter過濾器,這里再次提醒,短信隨機驗證碼

import java.util.Objects;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.util.Assert;
import org.woodwhales.core.constants.SecurityConstants;

public class SmsCodeAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

/**
 * 請求中的參數(shù)
 */
private String mobileParameter = SecurityConstants.DEFAULT_PARAMETER_NAME_MOBILE;

private boolean postOnly = true;

public SmsCodeAuthenticationFilter() {
    super(new AntPathRequestMatcher(SecurityConstants.DEFAULT_LOGIN_PROCESSING_URL_MOBILE, "POST"));
}

public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
    if (postOnly && !request.getMethod().equals("POST")) {
        throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
    }

    // 獲取請求中的參數(shù)值
    String mobile = obtainMobile(request);

    if (Objects.isNull(mobile)) {
        mobile = "";
    }

    mobile = mobile.trim();

    SmsCodeAuthenticationToken authRequest = new SmsCodeAuthenticationToken(mobile);

    // Allow subclasses to set the "details" property
    setDetails(request, authRequest);

    return this.getAuthenticationManager().authenticate(authRequest);
}

/**
 * 獲取手機號
 */
protected String obtainMobile(HttpServletRequest request) {
    return request.getParameter(mobileParameter);
}

protected void setDetails(HttpServletRequest request, SmsCodeAuthenticationToken authRequest) {
    authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
}

public void setMobileParameter(String mobileParameter) {
    Assert.hasText(mobileParameter, "Mobile parameter must not be empty or null");
    this.mobileParameter = mobileParameter;
}

public void setPostOnly(boolean postOnly) {
    this.postOnly = postOnly;
}

public final String getMobileParameter() {
    return mobileParameter;
}

}
短信驗證碼過濾器也成為了AbstractAuthenticationProcessingFilter其中一個子類,后期需要注冊到安全配置中,讓它成為安全認證過濾鏈中的一環(huán):

SpringBoot + Spring Security 學習筆記實現(xiàn)短信驗證碼+登錄功能

短信登錄認證校驗器

短信登錄認證校驗器的作用就是調用UserDetailsService的loadUserByUsername()方法對 authenticationToken 進行校驗,所有校驗器的根接口為:AuthenticationProvider,因此自定義的短信登錄認證校驗器實現(xiàn)這個接口,重寫authenticate()即可:

import java.util.Objects;

import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;

import lombok.Data;

@Data
public class SmsCodeAuthenticationProvider implements AuthenticationProvider {

private UserDetailsService userDetailsService;

@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {

    SmsCodeAuthenticationToken authenticationToken = (SmsCodeAuthenticationToken) authentication;

    /**
     * 調用 {@link UserDetailsService}
     */
    UserDetails user = userDetailsService.loadUserByUsername((String)authenticationToken.getPrincipal());

    if (Objects.isNull(user)) {
        throw new InternalAuthenticationServiceException("無法獲取用戶信息");
    }

    SmsCodeAuthenticationToken authenticationResult = new SmsCodeAuthenticationToken(user, user.getAuthorities());

    authenticationResult.setDetails(authenticationToken.getDetails());

    return authenticationResult;
}

@Override
public boolean supports(Class<?> authentication) {
    return SmsCodeAuthenticationToken.class.isAssignableFrom(authentication);
}

}
注意,這里使用@Data注解生成 setter 和 getter 方法。

SpringBoot + Spring Security 學習筆記實現(xiàn)短信驗證碼+登錄功能

短信登錄認證安全配置設計

設計一個封裝好的短信登錄認證配置類,以供外部調用者直接調用:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.stereotype.Component;

@Component
public class SmsCodeAuthenticationSecurityConfig extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {

@Autowired
private AuthenticationSuccessHandler myAuthenticationSuccessHandler;

@Autowired
private AuthenticationFailureHandler myAuthenticationFailureHandler;

@Autowired
private UserDetailsService userDetailsService;

@Override
public void configure(HttpSecurity http) throws Exception {

    SmsCodeAuthenticationFilter smsCodeAuthenticationFilter = new SmsCodeAuthenticationFilter();
    smsCodeAuthenticationFilter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class));
    smsCodeAuthenticationFilter.setAuthenticationSuccessHandler(myAuthenticationSuccessHandler);
    smsCodeAuthenticationFilter.setAuthenticationFailureHandler(myAuthenticationFailureHandler);

    // 獲取驗證碼提供者
    SmsCodeAuthenticationProvider smsCodeAuthenticationProvider = new SmsCodeAuthenticationProvider();
    smsCodeAuthenticationProvider.setUserDetailsService(userDetailsService);

    // 將短信驗證碼校驗器注冊到 HttpSecurity, 并將短信驗證碼過濾器添加在 UsernamePasswordAuthenticationFilter 之前
    http.authenticationProvider(smsCodeAuthenticationProvider).addFilterAfter(smsCodeAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);

}

}
當外部想要引用這個封裝好的配置,只需要在自定義的AbstractChannelSecurityConfig安全認證配置中添加進去即可,注意這個配置對象使用了@Component注解,注冊到了spring 中,所以可以直接通過@Autowired引用,如:

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import org.springframework.stereotype.Component;
import org.woodwhales.core.authentication.sms.AbstractChannelSecurityConfig;
import org.woodwhales.core.authentication.sms.SmsCodeAuthenticationSecurityConfig;
import org.woodwhales.core.validate.code.config.ValidateCodeSecurityConfig;

@Component
public class BrowserSecurityConfig extends AbstractChannelSecurityConfig {

@Autowired
private SmsCodeAuthenticationSecurityConfig smsCodeAuthenticationSecurityConfig;

@Autowired
private ValidateCodeSecurityConfig validateCodeSecurityConfig;

@Autowired
protected AuthenticationSuccessHandler authenticationSuccessHandler;

@Autowired
protected AuthenticationFailureHandler authenticationFailureHandler;

@Autowired
private UserDetailsService userDetailsService;

@Autowired
private DataSource dataSource;

@Override
protected void configure(HttpSecurity http) throws Exception {

    http.formLogin()
        .loginPage("/authentication/require") // 登錄頁面回調
        .successHandler(authenticationSuccessHandler)// 認證成功回調
        .failureHandler(authenticationFailureHandler)

        // 以下驗證碼的校驗配置
        .and()
        .apply(validateCodeSecurityConfig) 

        // 以下短信登錄認證的配置
        .and()
        .apply(smsCodeAuthenticationSecurityConfig)

        // 記住我的配置
        .and()
        .rememberMe()
        .tokenRepository(persistentTokenRepository())
        .tokenValiditySeconds(3600) // 設置記住我的過期時間
        .userDetailsService(userDetailsService)

        .and()
        // 請求做授權配置
        .authorizeRequests() 
        // 以下請求路徑不需要認證
        .antMatchers("/authentication/require",
                "/authentication/mobile",
                "/login",
                "/code/*",
                "/")
        .permitAll() 
        .anyRequest() // 任何請求
        .authenticated() // 都需要身份認證

        // 暫時將防護跨站請求偽造的功能置為不可用
        .and()
        .csrf().disable();
}

/**
 * 配置TokenRepository
 * @return
 */
@Bean
public PersistentTokenRepository persistentTokenRepository() {
    JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
    jdbcTokenRepository.setDataSource(dataSource);
    // 初始化記住我的數(shù)據(jù)庫表,建議通過看源碼直接創(chuàng)建出來
    // jdbcTokenRepository.setCreateTableOnStartup(true);
    return jdbcTokenRepository;
}

}
這里的配置中有些代碼出現(xiàn)了冗余配置,可以全部封裝成抽象模板,完成一些基礎的配置。

網(wǎng)頁標題:SpringBoot+SpringSecurity學習筆記實現(xiàn)短信驗證碼+登錄功能
本文地址:http://aaarwkj.com/article32/gghipc.html

成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供動態(tài)網(wǎng)站、移動網(wǎng)站建設建站公司、微信公眾號、網(wǎng)站內(nèi)鏈、網(wǎng)站收錄

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉載內(nèi)容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)

成都定制網(wǎng)站網(wǎng)頁設計
国产亚洲精品热视频在线观看| 人妻丰满熟妇九九久久| 亚洲欧美精品专区久久| 久久人妻制服乱码中文字幕| 中文字幕熟女av一区二区| 欧美日韩在线亚洲二区综二 | 中文字幕精品一区二区三区视频| 日韩精品在线观看视频一区二区三区| 日韩国产精品激情一区| 国产一级三级视频在线| 人妻日韩字幕一区二区| 视频免费观看网站不卡| 中文字幕91在线播放| 综合久久久精品国产亚洲av| 中文字慕日韩精品欧美一区| 日韩不卡永久免费视频观看| 五月天久久开心激情网| 亚洲av二区三区成人| 日本欧美国产一区二区| 男女性生活视频成年人观看| 成人av男人天堂东京热| 色综合一区二区日本韩国亚洲| 在线国产视频一区二区三区| 精品视频中文字幕天码| 五月婷婷色丁香综合激情| 国产欧美日韩精品av| 美女午夜福利精品视频| 天堂av在线资源观看| 新午夜福利片在线观看| 91在线播放欧美国产视频| 自拍偷拍欧美日韩第一页| 美女少妇性高潮的视频| 亚洲男人堂色偷偷一区| 麻豆一精品传二传媒短视频| 国产成人三级视频网站| 国产精品一区巨乳人妻| 久久久久久亚洲精品人妻| 国产麻豆精品传媒av| 欧美日韩在线国产一区| 亚洲av网站女性向在线观看| 日韩一区二区亚洲精品|