1. SecurityAutoConfiguration源碼解析

        共 7207字,需瀏覽 15分鐘

         ·

        2022-04-17 09:20


        SecurityAutoConfiguration 詳解

        SpringBoot 對(duì) Security 的支持類(lèi)均位于
        org.springframework.boot.autoconfigure.security包下,主要通過(guò) SecurityAutoConfiguration 自動(dòng)配置類(lèi)和 SecurityProperties 屬性配置來(lái)完成。

        下面,我們通過(guò)對(duì) SecurityAutoConfiguration及引入的相關(guān)自動(dòng)配 置源碼進(jìn)行解析說(shuō)明。

        @Configuration(proxyBeanMethods = false)
        @ConditionalOnClass (DefaultAuthenticationEventPublisher . class)
        @EnableConfigurationProperties (SecurityProperties. class)
        @Import({ SpringBootWebSecurityConfiguration. class, WebSecurityEnablerConfi
        guration.
        class,
        SecurityDataConfiguration. class })public class SecurityAutoConfiguration {
        @Bean
        @ConditionalOnMissingBean(Authenticat ionEventPublisher. class)
        public DefaultAuthenticat ionEventPublisher authenticationEventPublisher(
        ApplicationEventPublisher publisher) {
        return new DefaultAuthenticationEventPublisher(publisher);
        }
        @ConditionalOnClass

        指定classpath路徑中必須存在
        DefaultAuthenticationEventPublisher 類(lèi) 才 會(huì) 進(jìn) 行 實(shí) 例 化 操 作 , 通 過(guò)@EnableConfigurationProperties 指定了配置文件對(duì)應(yīng)的類(lèi),通過(guò)@lmport 導(dǎo)入了SpringBootWebSecurityConfigurationWebSecurityEnablerConfiguration和Security-DataConfiguration 自動(dòng)配置類(lèi)。

        首先,@
        EnableConfigurationProperties 指定的 SecurityProperties 類(lèi),部分源碼如下。

        @ConfigurationProperties(prefix = "spring . security" )
        public class SecurityProperties {
        private final Filter filter = new Filter();
        private User user = new User();
        public static class Filter {
        // Security 過(guò)糖器鏈順序
        private int order = DEFAULT_ FILTER_ _ORDER;
        // Security 過(guò)濾器鏈分發(fā)類(lèi)型
        private Set dispatcherTypes = new HashSet<>(
        Arrays. asList(DispatcherType . ASYNC, DispatcherType . ERROR, Dispa-
        tcherType . REQUEST));
        public static class User {
        //默認(rèn)用戶(hù)名
        private String name = "user";
        //默認(rèn)密碼
        private String password = UUID. randomUUID() . toString();
        // 默認(rèn)用戶(hù)角色
        private List roles = new ArrayList<>();
        }
        }
        }

        通過(guò) SecurityProperties 中定義的配置項(xiàng),可以對(duì)照最開(kāi)始在 application.properties 文件中配置的用戶(hù)名和密碼,如果沒(méi)有進(jìn)行用戶(hù)名和密碼的配置,則默認(rèn)使用 user 作為用戶(hù)名,并自動(dòng)生成一個(gè) UUID 字符串作為密碼。那么,默認(rèn)密碼在哪里獲取呢?通常情況下,系統(tǒng)會(huì)在啟動(dòng)時(shí)的控制臺(tái)日志中打印出對(duì)應(yīng)的密碼信息,具體日志格式如下。

        Using generated security password: 67bd059b-d503-4976-95b1-5fa09e6c9588

        而該日志的輸出功能是在
        UserDetailsServiceAutoConfiguration 自動(dòng)配置類(lèi)中實(shí)例化InMemoryUserDetailsManager 類(lèi)時(shí)執(zhí)行的, 該類(lèi)是基于內(nèi)存的用戶(hù)詳情管理,比如提供用戶(hù)信息的增刪改查等操作。關(guān)于 UserDetailsServiceAutoConfiguration 自動(dòng)配置類(lèi),最核心的功能就是實(shí)例化了該類(lèi)的對(duì)象,我們不再過(guò)度展開(kāi),只看一下其中判斷和打印密碼的一個(gè)方法。

        private String getOrDeducePassword(SecurityProperties .User user, PasswoFRiEn
        String password = user . getPassword();
        if (user. isPasswordGenerated()) {
        logger . info(String . format("%n%nUsing generated security password: %s%
        "
        ,user.
        getPassword()));
        if (encoder != null | PASSWORD_ ALGORITHM PATTERN. matcher(pas sword) . match
        2s())
        return password;
        return NOOP_ PASSWORD_ PREFIX + password;
        }
        }

        在獲取密碼時(shí),通過(guò) SecurityProperties 中的 isPasswordGenerated 方法判斷是否是自動(dòng)生成的密碼,如果是,則通過(guò)日志打印出對(duì)應(yīng)的密碼。


        下面繼續(xù)看 SecurityAutoConfiguration 導(dǎo)入的
        SpringBootWebSecurityConfiguration 自動(dòng)配置類(lèi)。

        @Configuration(proxyBeanMethods = false)
        @ConditionalOnClass (WebSecurityConfigurerAdapter . class)
        @ConditionalOnMiss ingBean(WebSecurityConfigurerAdapter .class)
        @ConditionalOnWebApplication(type = Type . SERVLET)
        public class SpringBootWebSecurityConfiguration {
        @Configuration
        @Order(SecurityProperties . BASIC_ AUTH _ORDER)
        static class DefaultConfigurerAdapter extends WebSecurityConfigurerAdapter {
        }
        }

        該 自 動(dòng) 配 置 類(lèi) 為 Security 的 Web 應(yīng) 用 默 認(rèn) 配 置 , 當(dāng) 類(lèi) 路 徑 下 存 在
        WebSecurityCon-figurerAdapter 類(lèi), 并且不存在對(duì)應(yīng)的 Bean 對(duì)象時(shí),會(huì)觸發(fā)該自動(dòng)配置類(lèi)。同時(shí),@ConditionalOnWebApplication 指定應(yīng)用類(lèi)型必須為 Servlet 應(yīng)用。該自動(dòng)配置類(lèi)的核心在于 WebSecurityConfigurerAdapter 適配器的實(shí)例化。用一句話來(lái)描述 SpringBootWebSecurityConfiguration 的功能就是:針對(duì)使用 Security 的 Web 應(yīng)用,如果用戶(hù)沒(méi)有注入自定義 WebSecurityConfigurerAdapter 的實(shí)現(xiàn)類(lèi), 則 Spring Boot 默認(rèn)提供一 個(gè)。


        WebSecurityConfigurerAdapter 用于配置 Sping Security Web 安全。默認(rèn)情況下 SpringBoot 提供的 DefaultConfigurerAdapter 適配器實(shí)現(xiàn)為空,用 SecurityProperties 中常量BASIC_ _AUTH_ ORDER 指定的值(-5) 作為注入 Spring loC 容器的順序。

        在正常使用的過(guò)程中,針對(duì) Web 項(xiàng)目我們都是通過(guò)繼承
        WebSecurityConfigurer-Adapter,并實(shí)現(xiàn)其 configure(HttpSecurity http)方法來(lái)實(shí)現(xiàn)定制化設(shè)置的。下面看一下該類(lèi)的該方法的默認(rèn)實(shí)現(xiàn)。

        @Order(100)
        public abstract class WebSecurityConfigurerAdapter implements
        WebSecurityConfigurer <WebSecurity>
        {
        // @formatter:off
        protected void configure(HttpSecurity http) throws Exception {
        http. authorizeRequests()
        . anyRequest() . authenticated()
        . and()
        . formLogin(). and()
        .httpBasic();
        }
        }

        從上述默認(rèn)實(shí)現(xiàn)的代碼中可以看出,針對(duì)請(qǐng)求的攔截使用了 anyRequest 方法,該方法會(huì)匹配所有的請(qǐng)求路徑。同時(shí),Security 還提供 了基于 Ant 風(fēng)格的路徑匹配方法(antMatches)和基于正則表達(dá)式的匹配方法(regexMathes)。

        另外通過(guò) formLogin 方法,設(shè)置了默認(rèn)登錄時(shí)的登錄請(qǐng)求、用戶(hù)名、密碼等信息,在其調(diào)用過(guò)程中會(huì)創(chuàng)建一-個(gè) FormLoginConfigurer 對(duì)象,用來(lái)設(shè)置默認(rèn)信息。FormL oginConfigurer構(gòu)造方法如下。

        public FormL oginConfigurer() {
        super(new UsernamePas swordAuthenticationFilter(), null);
        usernameParameter("username");
        passwordParameter("password");
        }

        其中
        UsernamePasswordAuthenticationFilter 中定義了請(qǐng)求跳轉(zhuǎn)的頁(yè)面。

        public UsernamePasswordAuthenticationFilter() {
        super(new AntPathRequestMatcher("/login", "POST"));}

        這就是當(dāng)引入 Security 框架之后,訪問(wèn)頁(yè)面時(shí)會(huì)默認(rèn)跳轉(zhuǎn)到 login 頁(yè)面的原因了。

        下 面 繼 續(xù) 看SecurityAutoConfiguration引 入 的 自 動(dòng) 配 置 類(lèi)
        WebSecurityEnablerConfigu-ration。在早期版本中,當(dāng)我們使用 Security 時(shí)還需要自己使用 @EnableWebSecurity 注 解 , Spring Boot2.0.0 版 本 新 增 的WebSecurityEnablerConfiguration 幫我們解決了該問(wèn)題,該類(lèi)源碼如下。

        @Configuration(proxyBeanMethods = false)
        @ConditionalOnBean(WebSecurityConfigurerAdapter. class)
        @ConditionalOnMi ssingBean(name = BeanIds . SPRING_ SECURITY_ FILTER_
        _CHAIN)
        @ConditionalOnWebApplication(type = ConditionalOnWebApplication. Type . SERVLE
        T)
        @EnableWebSecurity
        public class WebSecurityEnablerConfiguration {
        }
        該類(lèi)并沒(méi)有具體的實(shí)現(xiàn),重點(diǎn)在于滿(mǎn)足條件時(shí)激活@EnableWebSecurity 注解,即當(dāng)WebSecurityConfigurerAdapter 對(duì)應(yīng)的 Bean 存在,name 為 springSecurityFilterChain 的Bean 不存在,應(yīng)用類(lèi)型為 Servlet 時(shí),激活@EnableWebSecurity 注解。

        該自動(dòng)配置類(lèi)的主要作用是防止用戶(hù)漏使用@EnableWebSecurity 注解,通過(guò)該自動(dòng)配置類(lèi)確保@EnableWebSecurity 注解被使用,從而保障 springSecurityFilterChain Bean 的定義。

        我們看一下 @EnableWebSecurity 的源碼。

        @Retention(value = java. lang . annotation. Retent ionPolicy . RUNTIME)
        @Target(value = { java. lang . annotation. ElementType.TYPE })
        @Documented
        @Import({ WebSecurityConfiguration. class,
        SpringWebMvc ImportSe lector.class,
        OAuth2ImportSelector .class })
        @EnableGlobalAuthentication
        @Configuration
        public @interface EnableWebSecurity {
        boolean debug() default false;
        }

        @EnableWebSecurity 用來(lái)控制 Spring Security 是否使用調(diào)試模式,并且組合了其他自動(dòng)配置。導(dǎo)入了 WebSecurityConfiguration,用于配置 Web 安全過(guò)濾器 FilterChainProxy。


        如果是 Servlet 環(huán)境,導(dǎo)入
        WebMvcSecurityConfiguration;如果是 OAuth2 環(huán)境,導(dǎo)入OAuth2ClientConfiguration。使用注解@EnableGlobalAuthentication 啟用全局認(rèn)證機(jī)制。最后,我們看一下 SecurityAutoConfiguration 引入的 SecurityDataConfiguration.

        @Configuration(proxyBeanMethods = false)
        @ConditionalOnClass (SecurityEvaluat ionContextExtension. class)
        public class SecurityDataConfiguration {
        @Bean
        @Conditiona lOnMissingBean
        public SecurityEvaluationContextExtension securityEvaluationContextExtens
        ion() {
        return new SecurityEvaluat ionContextExtension();
        }
        }

        在該自動(dòng)配置類(lèi)中實(shí)例化了
        SecurityEvaluationContextExtension 類(lèi)的對(duì)象,其主要作用是將 Spring Security 與 Spring Data 進(jìn)行整合。

        回 到SecurityAutoConfiguration類(lèi) 內(nèi) 部 , 它 實(shí) 例 化 了 一 個(gè)
        DefaultAuthenticationEvent-Publisher 將其作為默認(rèn)的 AuthenticationEventPublisher, 并將其注入 Spring 容器。


        DefaultAuthenticationEventPublisher 為發(fā)布身份驗(yàn)證事件的默認(rèn)策略類(lèi),將眾所周知的AuthenticationException 類(lèi)型映射到事件中, 并通過(guò)應(yīng)用程序上下文進(jìn)行發(fā)布。如果配置為 Bean,它將自動(dòng)獲取 ApplicationEventPublisher。否則,應(yīng)該使用構(gòu)造方法將 ApplicationEventPublisher 傳入。


        DefaultAuthenticationEventPublisher 內(nèi)部通過(guò) HashMap 維護(hù)認(rèn)證異常處理和對(duì)應(yīng)異常事件處理邏輯的映射關(guān)系,發(fā)生不同認(rèn)證異常會(huì)采用不同的處理策略。我們看一下該類(lèi)的部分源碼。

        public class DefaultAuthenticationEventPublisher implements AuthenticationE
        ventPublisher,
        ApplicationEventPublisherAware {
        private Applicat ionEventPublisher applicationEventPublisher;
        private final HashMapnEvent>>
        except ionMappings = new HashMaphentica-
        tionEvent>>();
        public DefaultAuthenticat ionEventPublisher(
        ApplicationEventPublisher applicationEventPublisher) {
        this . applicationEventPublisher = applicationEventPublisher;addMapping(BadCredentialsException. class . getName() ,
        AuthenticationFailureBadCredentialsEvent. class);
        addMapping(UsernameNotFoundException. class . getName() ,
        AuthenticationF ailureBadCredent ialsEvent . class);
        addMapping(AccountExpiredException. class . getName( )
        AuthenticationF ailureExpiredEvent.class);
        addMapping(ProviderNotFoundExcept ion. class . getName(),
        Authenticat ionFai lureProviderNotFoundEvent. class);
        addMapping(DisabledException. class . getName(),
        Authenticat ionF ailureDisabledEvent . class);
        addMapping(LockedException. class . getName(),
        AuthenticationFailureLockedEvent . class);
        addMapping(Authenticat ionServiceException. class . getName(),
        AuthenticationFailureServiceExceptionEvent. class);
        addMapping(CredentialsExpiredException. class . getName(),
        AuthenticationF ailureCredentialsExpiredEvent. class);
        addMapping(
        "org. springframework . security . authentication. cas . ProxyUntrustedExcept
        ion"
        ,
        AuthenticationFailureProxyUntrustedEvent. class);
        }
        }

        在上述代碼中提供了未找到用戶(hù)異常( UsernameNotFoundException )、賬戶(hù)過(guò)期異常(AccountExpiredException) 等 常 見(jiàn) 異 常 的 對(duì) 應(yīng) 事 件 。同 時(shí) , 該 類(lèi) 集 成 了 Spring 的
        Application-EventPublisher, 通 過(guò) ApplicationEventPublisher 可 以 將 定 義 在exceptionMappings 中的異常事件進(jìn)行發(fā)布,相關(guān)核心代碼如下。

        public void publishAuthenticat ionFailure(Authenticat ionException exceptm,
        Authentication authentication) {
        //根據(jù)異常名稱(chēng)獲得對(duì)應(yīng)事件的構(gòu)造器
        Constructor extends AbstractAuthenticationEvent> constructor = exceptio
        nMappings
        . get(exception. getClass(). getName());
        AbstractAuthenticationEvent event = null;
        // 如果構(gòu)造器不為 null, 則實(shí)例化對(duì)應(yīng)的對(duì)象
        if (constructor != null) {
        tryevent = constructor . newInstance(authentication, exception);
        } catch (IllegalAccessException| InvocationTargetException| Instantia
        tion
        Exception ignored) {
        //如果對(duì)象實(shí)例化成功,則調(diào)用 Appl icationEventPubl isher 的 publ ishEvent 方法進(jìn)
        行發(fā)布
        if (event != null) {
        if (applicationEventPublisher != null) {
        applicationEventPublisher . publishEvent (event);
        } else {
        if (logger. isDebugEnabled())
        logger. debug("No event was found for the exception
        + exception. getClass().getName());
        }
        }
        }

        上述代碼的操作就是根據(jù)異常信息在 exceptionMappings 中獲得對(duì)應(yīng)事件的構(gòu)造方法,然后實(shí)例化對(duì)象,并調(diào)用 ApplicationEventPublisher 的 publishEvent 方法進(jìn)行發(fā)布。

        至此,關(guān)于 SecurityAutoConfiguration 的自動(dòng)配置過(guò)程已經(jīng)完成了。

        SecurityFilterAutoConfiguration 詳解


        SecurityFilterAutoConfiguration 主要用于自動(dòng)配置 Spring Security 的 Filter,該自動(dòng)配置類(lèi)與 SpringBootWebSecurityConfiguration 分 開(kāi) 配 置 , 以 確 保 在 存 在 用 戶(hù) 提 供 的WebSecurity-Configuration 情況下仍可以配置過(guò)濾器的順序。

        下面看一下
        SecurityFilterAutoConfiguration 類(lèi)的源代碼。

        @Configuration(proxyBeanMethods = false)
        @ConditionalOnWebApplication(type = Type . SERVLET)
        @EnableConfigurationProperties (SecurityProperties.class)
        @ConditionalOnClass({ AbstractSecurityWebApplicationInitializer .class, Sess
        ionCreationPolicy. class })

        @AutoConfigureAfter(SecurityAutoConfiguration. class)
        public class SecurityFilterAutoConfiguration {
        private static final String DEFAULT FILTER NAME = AbstractSecurityWebApp-
        licationInitializer .DEFAULT_ FILTER_ NAME ;
        @Bean@ConditionalOnBean(name = DEFAULT_ FILTER_ NAME)
        public DelegatingFilterProxyRegistrationBean securityFilterChainRegistrat
        ion(
        SecurityProperties securityProperties) {
        DelegatingF ilterProxyRegistrat ionBean registration = new DelegatingFi-
        lterProxyRegistrationBean(
        DEFAULT_ FILTER_ NAME);
        registrat ion. setOrder( securityProperties . getFilter(). get0rder());
        registration. setDispatcherTypes(getDispatcherTypes(securityPropertie
        s));
        return registration;
        private EnumSet getDispatcherTypes (SecurityProperties sec
        urityProperties) {
        if (securityProperties . getFilter(). getDispatcherTypes() == null) {
        return null;
        return securityProperties . getFilter(). getDispatcherTypes(). stream()
        .map((type) -> DispatcherType . value0f(type .name()))
        . collect(Collectors . collectingAndThen(Collectors . toSet(), EnumSet: : copy
        0f));
        }
        }

        通 過(guò) 注 解 部 分 可 以 看 出 : 當(dāng) 項(xiàng) 目 為 Web 的 Servlet 項(xiàng) 目 , 類(lèi) 路 徑 下 存 在 類(lèi)SessionCreation-Policy 和
        AbstractSecurityWebApplicationlnitializer 時(shí) ,會(huì) 在SecurityAutoConfiguration 配置完成之后進(jìn)行自動(dòng)配置,并導(dǎo)入 SecurityProperties 配置類(lèi)。


        SecurityFilterAutoConfiguration 的內(nèi)部實(shí)現(xiàn)中,主要向容器中注冊(cè)了一個(gè)名稱(chēng)為securityilterChainRegistration的Bean,具體實(shí)現(xiàn)類(lèi)是DelegatingFilterProxyRegistrationBean.

        常 量 DEFAULT_FILTER_NAME 定 義 了 要 注 冊(cè) 到 Servlet 容 器 的
        DelegatingFilterProxy-Filter 的目標(biāo)代理 Filter Bean ,名稱(chēng)為 springSecurityFilterChain。


        securityFilterChainRegistration 方法用@ConditionalOnBean 注解判斷容器中是否存在名稱(chēng)為 springSecurityFilterChain 的 Bean, 如果不存在,則執(zhí)行該方法內(nèi)的操作。


        securityFilterChainRegistration 方法 內(nèi) , 首 先 創(chuàng) 建 了 一 個(gè)DelegatingilterProxyRegist-rationBean 對(duì)象,并以 springSecuritFilterChain 參數(shù)作為委托的目標(biāo)類(lèi)的名稱(chēng),也就是要在 Spring 應(yīng)用程序上下文中查找的目標(biāo)過(guò)濾器的 Bean 的名稱(chēng)。


        DelegatingFilterProxyRegistrationBean 本質(zhì)上是一個(gè) ServletContextlnitializer,用于在Servlet 3.0+ 容器中注冊(cè) DelegatingFilterProxys.與 ServletContext 提供的注冊(cè)功能相似,但 DelegatigFilterProxyRegistrationBean 具有 Spring Bean 的友好性設(shè)計(jì)。通常,應(yīng)該使用構(gòu)造方法的 targetBeanName 參數(shù)指定實(shí)際委托過(guò)濾器的 Bean 名稱(chēng)(上述源代碼便是 如此操作)。與 FilterRegistrationBean 不同, 引用的過(guò)濾器不會(huì)過(guò)早的被實(shí)例化。實(shí)際上,如果將委托過(guò)濾器 Bean 標(biāo)記為@Lazy,則在調(diào)用過(guò)濾器之前根本不會(huì)實(shí)例化它。


        DelegatingFilterProxyRegistrationBean 內(nèi)部,實(shí)現(xiàn)了通過(guò)傳入的 targetBeanName 名字,在 WebApplicationContext 查找該 Fillter 的 Bean, 并通過(guò) DelegatingFilterProxy 生成基于該 Bean 的代理 Filter 對(duì)象。

        DelegatingFilterProxy 其實(shí)是-個(gè)代理過(guò)濾器,Servlet 容器處理請(qǐng)求時(shí), 會(huì)將任務(wù)委托給指定給的 Filter Bean。在該自動(dòng)配置類(lèi)中就是名稱(chēng)為 springSecurityFilterChain 的 Bean,該Bean 也是 Spring Security Web 提供的用于請(qǐng)求安全處理的 Filter Bean。

        實(shí) 例 化
        DelegatingFilterProxyRegistrationBean 之 后 , 便 對(duì) 其 設(shè) 置 優(yōu) 先 級(jí) , 默 認(rèn) 為SecurityProperties 中定義的 DEFAULT_ _FILTER_ ORDER 的值(-100)。最后,設(shè)置其DispatcherTypes。SecurityFilterAutoConfiguration 中的 getDispatcherTypes 方法便是根據(jù)配置獲得對(duì)應(yīng)的調(diào)度類(lèi)型的集合。在 Servlet 中,調(diào)度類(lèi)型定義在枚舉類(lèi) DispatcherType中,包括: FORWARD、INCLUDE、REQUEST、ASYNC 和 ERROR 這 5 種類(lèi)型。至此,關(guān)于 SecurityFilterAutoConfiguration 的自動(dòng)化配置及功能講解完畢。


        小結(jié)

        本章重點(diǎn)進(jìn)行了在 Web Servlet 下 Spring Security 的自動(dòng)配置源碼解析。

        Spring Boot支持很 多 Spring Security的 自動(dòng)配 置 , 均 位 于
        org.springframework.boot.autoconfigure.security 包下,限于篇幅無(wú)法一一講解,大家可根據(jù)需要自行閱讀。而關(guān)于 Spring Security 更多功能的具體使用,我們可參考官方文檔和相關(guān)書(shū)籍進(jìn)行學(xué)習(xí)實(shí)踐。

        本文給大家講解的內(nèi)容是SpringBootSecurity支持:SecurityAutoConfiguration 詳解

        1. 下篇文章給大家講解的是微服務(wù)架構(gòu)與Spring Cloud;

        2. 覺(jué)得文章不錯(cuò)的朋友可以轉(zhuǎn)發(fā)此文關(guān)注小編;

        3. 感謝大家的支持!


        本文就是愿天堂沒(méi)有BUG給大家分享的內(nèi)容,大家有收獲的話可以分享下,想學(xué)習(xí)更多的話可以到微信公眾號(hào)里找我,我等你哦。

        瀏覽 37
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
          
          

            1. 污污的网站入口 | 久久无码激情 | 高h重口激h慎宫交h | 国产乱码一区二区三区 | 国产精品美女久久久久久久网站 |