Spring-Security-架構初談

身份驗證和訪問控制

應用程序安全性歸結為或多或少的兩個獨立問題:

authentication/認證(你是誰良蒸?)和 authorization/授權(你可以做什么?)。

有時人們會說“訪問控制”而不是“授權”,這可能會造成混淆,但是以這種方式思考可能會有所幫助蝇完,因為“授權”在其他地方可能有點言過其重。Spring Security 的體系結構旨在將認證與授權分開矗蕊,并各自具有策略和擴展點短蜕。

Authentication(身份驗證/認證)

身份驗證的主要策略接口是 AuthenticationManager,它只有一個方法:

public interface AuthenticationManager {

  Authentication authenticate(Authentication authentication)
    throws AuthenticationException;

}

AuthenticationManager 可以在 authenticate() 方法中執(zhí)行以下三項操作之一:

  1. 如果它可以驗證輸入是否代表有效的主體傻咖,則返回 Authentication(通常使用 authenticated = true)朋魔。
  2. 如果認為輸入代表無效的主體,則拋出 AuthenticationException卿操。
  3. 如果無法決策警检,則返回 null孙援。

AuthenticationException 是運行時異常。它通常由應用程序以通用方式處理扇雕,具體取決于應用程序的用例或目的拓售。換句話說,通常不希望用戶代碼捕獲并處理它镶奉。例如础淤,web 程序?qū)⒊尸F(xiàn)一個頁面,指出認證失敗腮鞍,后端 HTTP服務將發(fā)送401響應值骇,取決于上下文莹菱,帶有或不帶有 WWW-Authenticate 標頭移国。

AuthenticationManager 最常用的實現(xiàn)是 ProviderManager,它委派了 AuthenticationProvider 實例鏈道伟。AuthenticationProvider 有點像 AuthenticationManager迹缀,但是它還有一個額外的方法,允許調(diào)用者查詢是否支持給定的 Authentication 類型:

public interface AuthenticationProvider {

    Authentication authenticate(Authentication authentication)
            throws AuthenticationException;

    boolean supports(Class<?> authentication);

}

supports() 方法中的 Class <?> 參數(shù)實際上是 Class <? extends Authentication>(僅會詢問它是否支持將內(nèi)容傳遞到 authenticate() 方法中)蜜徽。通過委托給 AuthenticationProviders 鏈祝懂,ProviderManager 可以在同一應用程序中支持多種不同的身份驗證機制。如果 ProviderManager 無法識別特定的身份驗證實例類型拘鞋,則將跳過該類型砚蓬。

ProviderManager 具有可選的父級,如果所有提供程序都返回 null盆色,則可以咨詢該父級灰蛙。如果父級不可用,則 null 身份驗證將導致 AuthenticationException隔躲。

有時摩梧,應用程序具有邏輯組的受保護資源(例如,與路徑模式 /api/** 匹配的所有 Web 資源)宣旱,并且每個組可以具有自己的專用 AuthenticationManager仅父。通常,每一個都是 ProviderManager浑吟,它們共享一個父級笙纤。因此,父級是一種“全局”資源组力,充當所有提供程序的后備省容。

ProviderManagers with a common parent

圖1.使用 ProviderManagerAuthenticationManager 層次結構

自定義身份驗證管理器

Spring Security 提供了一些配置幫助類,可以在自己的應用程序中便捷的得到通用身份驗證管理器功能忿项。最常用的幫助類是 AuthenticationManagerBuilder蓉冈,它非常適合配置內(nèi)存中的 JDBC 或 LDAP 用戶詳情城舞,或者用于添加自定義 UserDetailsService。這是配置全局(父)AuthenticationManager 的應用程序的示例:

@Configuration
public class ApplicationSecurity extends WebSecurityConfigurerAdapter {

   ... // web stuff here

  @Autowired
  public void initialize(AuthenticationManagerBuilder builder, DataSource dataSource) {
    builder.jdbcAuthentication().dataSource(dataSource).withUser("dave")
      .password("secret").roles("USER");
  }

}

此示例與 Web 應用程序有關寞酿,但是 AuthenticationManagerBuilder 的用法更為廣泛(有關如何實現(xiàn) Web 應用程序安全性的詳細信息家夺,請參見下文)。請注意伐弹,AuthenticationManagerBuilder 使用 @Autowired 注入到@Bean 的方法中-這就是使它構建全局(父)AuthenticationManager 的 原因拉馋。相反,如果我們這樣做的話:

@Configuration
public class ApplicationSecurity extends WebSecurityConfigurerAdapter {

  @Autowired
  DataSource dataSource;

   ... // web stuff here

  @Override
  public void configure(AuthenticationManagerBuilder builder) {
    builder.jdbcAuthentication().dataSource(dataSource).withUser("dave")
      .password("secret").roles("USER");
  }

}

(在配置類中使用方法的 @Override)惨好,那么 AuthenticationManagerBuilder 僅用于構建“本地” AuthenticationManager煌茴,這是全局的一個子類。在 Spring Boot 應用程序中日川,您可以將全局變量 @Autowired連接到另一個 bean 中蔓腐,但是除非你自己明確暴漏出它,否則不能對本地對象執(zhí)行此操作龄句。

Spring Boot 提供了一個默認的全局 AuthenticationManager(只有一個用戶)回论,除非你通過提供自己的AuthenticationManager 類型的 bean 來搶占它。除非你需要自定義全局 AuthenticationManager分歇,否則默認值本身就足夠安全傀蓉,你不必擔心太多。

授權或訪問控制

身份驗證成功后职抡,我們可以繼續(xù)進行授權葬燎,這里的核心策略是 AccessDecisionManager「克Γ框架提供了三種實現(xiàn)方式谱净,所有這三種實現(xiàn)都委托給 AccessDecisionVoter 鏈,有點像 ProviderManager 委托給AuthenticationProviders蹄胰。

AccessDecisionVoter 使用 ConfigAttributes 修飾的身份驗證主體和安全 Object 進行投票:

boolean supports(ConfigAttribute attribute);

boolean supports(Class<?> clazz);

int vote(Authentication authentication, S object,
        Collection<ConfigAttribute> attributes);

ObjectAccessDecisionManagerAccessDecisionVoter 的簽名中是完全通用的-它表示用戶可能要訪問的任何內(nèi)容(Web 資源或 Java 類中的方法是兩種最常見的情況)岳遥。ConfigAttributes 也相當通用,用一些元數(shù)據(jù)來表示安全 Object 的修飾裕寨,這些元數(shù)據(jù)確定訪問它所需的權限級別浩蓉。ConfigAttribute 是一個接口,但是它只有一個通用的方法并返回 String宾袜,這些字符串以某種方式編碼資源所有者的意圖捻艳,表明有關允許誰訪問它的規(guī)則。典型的 ConfigAttribute 是用戶角色的名稱(如 ROLE_ADMINROLE_AUDIT)庆猫,并且它們通常具有特殊的格式(如 ROLE_ 前綴)或表示需要求值的表達式认轨。

大多數(shù)人只使用默認的 AccessDecisionManager,它是 AffirmativeBased 的(如果任何選民投票通過月培,則允許授予訪問權限)嘁字。任何定制都傾向于在選民中發(fā)生恩急,要么添加新選民,要么修改現(xiàn)有選民的投票方式纪蜒。

使用作為 Spring 表達式語言(SpEL)表達式的 ConfigAttributes 非常常見衷恭,例如 isFullyAuthenticated() && hasRole(‘FOO')AccessDecisionVoter 支持此功能纯续,可以處理表達式并為其創(chuàng)建上下文随珠。為了擴展可以處理的表達式的范圍,需要 SecurityExpressionRoot 的自定義實現(xiàn)猬错,有時還需要 SecurityExpressionHandler窗看。

網(wǎng)絡安全

Web 層(用于 UI 和 HTTP 后端)中的 Spring Security 基于 Servlet 過濾器,因此通常首先了解過濾器的作用會很有幫助倦炒。下圖顯示了單個 HTTP 請求的處理程序的典型分層显沈。

Filter chain delegating to a Servlet

客戶端向應用程序發(fā)送請求,然后容器根據(jù)請求 URI 的路徑確定對它應用哪些過濾器和哪個 servlet析校。一個 servlet 最多只能處理一個請求构罗,但是過濾器形成一個鏈,因此它們是有序的智玻,實際上,如果過濾器要處理請求本身芙代,則可以否決鏈的其余部分吊奢。過濾器還可以修改下游過濾器和 Servlet 中使用的請求和/或響應。過濾器鏈的順序非常重要纹烹,Spring Boot 通過兩種機制對其進行管理:一種是 Filter 類型的 @Bean 可以具有 @Order 或?qū)崿F(xiàn) Ordered页滚,另一個是它們可以成為 FilterRegistrationBean 的一部分,而 FilterRegistrationBean 本身也將順序作為其 API 的一部分铺呵。一些現(xiàn)成的過濾器定義了自己的常量裹驰,以幫助表示它們希望相對于彼此的順序(例如,Spring Session 中的 SessionRepositoryFilterDEFAULT_ORDERInteger.MIN_VALUE + 50片挂,它告訴我們幻林,它喜歡處于過濾器鏈的前端,但并不排除其他過濾器的出現(xiàn)音念。

Spring Security 作為鏈中的單個 Filter 安裝沪饺,其具體類型為 FilterChainProxy闷愤,原因很快就會變得顯而易見整葡。在 Spring Boot 應用程序中遭居,安全過濾器是 ApplicationContext 中的 @Bean镀首,默認情況下會安裝該過濾器,以便將其應用于每個請求成翩。它安裝在 SecurityProperties.DEFAULT_FILTER_ORDER 定義的位置,反過來由 FilterRegistrationBean.REQUEST_WRAPPER_FILTER_MAX_ORDER 錨定(Spring Boot 應用程序希望過濾器包裝請求并修改其行為時期望的最大順序)赦役。但是麻敌,還有更多的功能:從容器的角度來看,Spring Security 是一個過濾器掂摔,但是在內(nèi)部有其他過濾器术羔,每個過濾器都扮演著特殊的角色。如圖:

Spring Security Filter

圖2. Spring Security 是單個真實的過濾器乙漓,但是將處理委托給一系列內(nèi)部過濾器级历。實際上,安全性過濾器中甚至還有一層間接層:通常作為 DelegatingFilterProxy 安裝在容器中叭披,而不必是 Spring @Bean寥殖,該代理類是 Spring Web 提供的 servlet 過濾器,它將所有工作委托給根 ApplicationContext 中的 Spring bean涩蜘。該代理委托給一個始終為 @BeanFilterChainProxy嚼贡,通常使用固定名稱 springSecurityFilterChain

public class DelegatingFilterProxy implements Filter {
    void doFilter(request, response, filterChain) {
        Filter delegate = applicationContet.getBean("springSecurityFilterChain")
            delegate.doFilter(request, response, filterChain);
    }
}

這個被委托的 Bean 就是 FilterChainProxy同诫,它里面包含所有內(nèi)部安全性邏輯粤策,這些安全性邏輯在內(nèi)部排列為一個或多個過濾器鏈,它們?nèi)坑?Spring Security 在同一頂級 FilterChainProxy 中管理误窖,而對于容器來說都是未知的叮盘,該類的主要邏輯如下偽代碼所示:

public class FilterChainProxy implements Filter {
    void doFilter(request, response, filterChain) {
        // 查找此請求的所有過濾器
        List<Filter> delegates = lookupDelegates(request, response)
            // 除非委托過濾器類決定停止,否則調(diào)用每個篩選器
            for delegate in delegates {
                if continue processing 
                    delegate.doFilter(request, response, filterChain)
            }
        // 如果所有過濾器都認為ok贩猎,則允許應用程序的其余部分運行
        if continue processing
            filterChain.doFilter(request, response)
    }
}

Spring Security 過濾器包含一個過濾器鏈列表熊户,并向與其匹配的第一個鏈發(fā)送請求。下圖顯示了基于匹配請求路徑(/foo/**/** 之前匹配)發(fā)生的調(diào)度吭服。這是很常見的嚷堡,但不是匹配請求的唯一方法。此調(diào)度過程的最重要特征是,只有一個鏈處理過請求蝌戒。

Security Filter Dispatch

圖3. Spring Security FilterChainProxy 將請求分派到匹配的第一個鏈串塑。 沒有自定義安全配置的普通 Spring Boot 應用程序具有多個(稱為n)過濾器鏈,通常 n = 6北苟。前 (n-1) 個鏈只是忽略靜態(tài)資源匹配模式桩匪,像 /css/**/images/**,以及錯誤視圖 /error(路徑可以由用戶通過 SecurityProperties 配置 bean 中 security.ignored 控制)友鼻。最后一條鏈與捕獲所有路徑/** 相匹配傻昙,并且更活躍,包含用于身份驗證彩扔,授權妆档,異常處理的邏輯,會話處理虫碉,請求寫入等贾惦。默認情況下,此鏈中總共有11個過濾器敦捧,但通常用戶不必擔心使用什么過濾器以及何時使用须板。

容器不知道 Spring Security 內(nèi)部的所有過濾器這一事實非常重要,尤其是在 Spring Boo t應用程序中兢卵,默認情況下习瑰,所有 Filter 類型的 @Bean 都會自動向容器注冊。因此济蝉,如果要向安全鏈中添加自定義過濾器杰刽,則無需將其設置為 @Bean 或?qū)⑵浒b在明確禁用容器注冊的 FilterRegistrationBean 中。

創(chuàng)建和定制過濾器鏈

Spring Boot 應用程序(帶有 /** 請求匹配器的應用程序)中的默認后備過濾器鏈具有 SecurityProperties.BASIC_AUTH_ORDER 的預定義順序王滤。您可以通過設置 security.basic.enabled = false 完全關閉它,也可以將其用作后備并僅以較低的順序定義其他規(guī)則滓鸠。為此雁乡,只需添加類型為 WebSecurityConfigurerAdapter(或 WebSecurityConfigurer)的 @Bean 并使用 @Order 裝飾類。例:

@Configuration
@Order(SecurityProperties.BASIC_AUTH_ORDER - 10)
public class ApplicationConfigurerAdapter extends WebSecurityConfigurerAdapter {
  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.antMatcher("/foo/**")
     ...;
  
}

這個 bean 將導致 Spring Security 添加一個新的過濾器鏈并在回退之前對其進行排序糜俗。

許多應用程序?qū)商踪Y源的訪問規(guī)則完全不同踱稍。例如,承載 UI 和支持 API 的應用程序可能支持基于 cookie 的身份驗證以及對 UI 部件的登錄頁面的重定向悠抹,而基于令牌的身份驗證則具有針對 API 部件的未經(jīng)身份驗證的請求的 401 響應珠月。 每組資源都有其自己的 WebSecurityConfigurerAdapter 以及唯一的順序和自己的請求匹配器。 如果匹配規(guī)則重疊楔敌,則最早的有序過濾器鏈將獲勝啤挎。

請求匹配以進行調(diào)度和授權

安全過濾器鏈(或等效的 WebSecurityConfigurerAdapter)具有請求匹配器,該請求匹配器用于確定是否將其應用于 HTTP 請求卵凑。一旦決定應用特定的過濾器鏈庆聘,就不再應用其他過濾器鏈胜臊。但是在過濾器鏈中,可以通過在HttpSecurity 配置器中設置其他匹配器來對授權進行更細粒度的控制伙判。例:

@Configuration
@Order(SecurityProperties.BASIC_AUTH_ORDER - 10)
public class ApplicationConfigurerAdapter extends WebSecurityConfigurerAdapter {
  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.antMatcher("/foo/**")
      .authorizeRequests()
        .antMatchers("/foo/bar").hasRole("BAR")
        .antMatchers("/foo/spam").hasRole("SPAM")
        .anyRequest().isAuthenticated();
  }
}

配置 Spring Security 時最容易犯的一個錯誤是忘記這些匹配器適用于不同的流程象对,一個是整個過濾器鏈的請求匹配器,另一個是僅選擇要應用的訪問規(guī)則宴抚。

將應用程序安全規(guī)則與執(zhí)行器規(guī)則相結合

如果您將 Spring Boot Actuator 用于管理端點勒魔,則可能希望它們是安全的,默認情況下它們將是安全的菇曲。實際上冠绢,將執(zhí)行器添加到安全應用程序后,您會獲得一條僅適用于執(zhí)行器端點的附加過濾器鏈羊娃。它由僅匹配執(zhí)行器端點的請求匹配器定義唐全,并且其順序為 ManagementServerProperties.BASIC_AUTH_ORDER,該順序比默認的SecurityProperties 回退過濾器少 5 個蕊玷,因此在進行回退處理之前會經(jīng)過它邮利。

如果您希望將應用程序安全規(guī)則應用于執(zhí)行器端點,則可以添加一個比執(zhí)行器順序更早順序的過濾器鏈垃帅,并帶有一個包括所有執(zhí)行器端點的請求匹配器延届。如果您喜歡執(zhí)行器端點的默認安全性設置,那么最簡單的方法是在執(zhí)行器端點之后但在回退之前(例如 ManagementServerProperties.BASIC_AUTH_ORDER + 1)添加自己的過濾器贸诚。例:

@Configuration
@Order(ManagementServerProperties.BASIC_AUTH_ORDER + 1)
public class ApplicationConfigurerAdapter extends WebSecurityConfigurerAdapter {
  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.antMatcher("/foo/**")
     ...;
  }
}

Web 層中的 Spring Security 當前與 Servlet API 綁定在一起方庭,因此,它僅在以嵌入式或其他方式在 Servlet 容器中運行應用程序時才真正適用酱固。但是械念,它不依賴于 Spring MVC 或 Spring Web 堆棧的其余部分,因此可以在任何 servlet 應用程序中使用运悲,例如使用 JAX-RS 的 servlet 應用程序龄减。

方法安全

除了保護 Web 應用程序安全外,Spring Security 還提供了將訪問規(guī)則應用于 Java 方法執(zhí)行的支持班眯。對于 Spring Security希停,這只是“保護資源”的另一種類型。對于用戶而言署隘,這意味著使用相同的 ConfigAttribute 字符串格式(例如角色或表達式)聲明訪問規(guī)則宠能,但在代碼中的其他位置。第一步是啟用方法安全性磁餐,例如在應用程序的頂級配置中:

@SpringBootApplication
@EnableGlobalMethodSecurity(securedEnabled = true)
public class SampleSecureApplication {
}

然后我們可以直接修飾方法資源违崇,例如:

@Service
public class MyService {

  @Secured("ROLE_USER")
  public String secure() {
    return "Hello Security";
  }

}

此示例是一種使用安全方法的服務。如果 Spring 創(chuàng)建了這種類型的 @Bean,則它將被代理亦歉,并且在實際執(zhí)行該方法之前恤浪,調(diào)用者將必須通過安全攔截器。如果訪問被拒絕肴楷,則調(diào)用者將獲得 AccessDeniedException 而不是實際的方法結果水由。

方法上還可以使用其他注釋來強制執(zhí)行安全性約束,尤其是 @PreAuthorize@PostAuthorize赛蔫,它們可以使您編寫分別包含對方法參數(shù)和返回值的引用的表達式砂客。

結合使用 Web 安全性和方法安全性并不少見。過濾器鏈提供了用戶體驗功能呵恢,例如身份驗證和重定向到登錄頁面等鞠值,并且方法安全性在更精細的級別上提供了保護。

使用線程

Spring Security 從根本上講是線程綁定的渗钉,因為它需要使當前經(jīng)過身份驗證的主體可供各種下游使用者使用彤恶。基本構件是 SecurityContext鳄橘,它可以包含一個 Authentication(當用戶登錄時声离,它將是經(jīng)過顯式身份驗證的Authentication)。您始終可以通過 SecurityContextHolder 中的靜態(tài)便捷方法來訪問和操作 SecurityContext瘫怜,而該方法又可以簡單地操作 TheadLocal术徊,例如:

SecurityContext context = SecurityContextHolder.getContext();
Authentication authentication = context.getAuthentication();
assert(authentication.isAuthenticated);

用戶應用程序代碼執(zhí)行此操作并不常見,但是鲸湃,如果你需要編寫一個自定義的身份驗證過濾器赠涮,它會很有用(盡管即使如此,Spring Security 中也可以使用基類來避免使用 SecurityContextHolder)暗挑。

如果需要訪問 Web 端點中當前已認證的用戶笋除,則可以在 @RequestMapping 中使用方法參數(shù)。例如:

@RequestMapping("/foo")
public String foo(@AuthenticationPrincipal User user) {
  ... // do stuff with user
}

該注釋將當前的身份驗證 (Authentication) 從 SecurityContext 中拉出炸裆,并對其調(diào)用 getPrincipal() 方法以產(chǎn)生方法參數(shù)株憾。身份驗證中的主體類型取決于用于驗證身份驗證的 AuthenticationManager,因此這是獲得對用戶數(shù)據(jù)的類型安全引用的有用的小技巧晒衩。

如果使用 Spring Security,則 HttpServletRequest 中的 Principal 將為 Authentication 類型墙歪,因此您也可以直接使用它:

@RequestMapping("/foo")
public String foo(Principal principal) {
  Authentication authentication = (Authentication) principal;
  User = (User) authentication.getPrincipal();
  ... // do stuff with user
}

如果您需要編寫在不使用 Spring Security 時可以工作的代碼听系,那么這有時會很有用(您在加載 Authentication 類時需要更加謹慎)。

異步處理安全方法

由于 SecurityContext 是線程綁定的虹菲,因此靠胜,如果要執(zhí)行任何調(diào)用安全方法的后臺處理,例如使用 @Async,您需要確保傳播上下文浪漠。

這歸結為將 SecurityContext 包裝為在后臺執(zhí)行的任務(Runnable陕习,Callable 等)。Spring Security 提供了一些幫助程序址愿,例如 RunnableCallable 的包裝器该镣。要將 SecurityContext 傳播到 @Async 方法,您需要提供 AsyncConfigurer 并確保 Executor 具有正確的類型:

@Configuration
public class ApplicationConfiguration extends AsyncConfigurerSupport {

  @Override
  public Executor getAsyncExecutor() {
    return new DelegatingSecurityContextExecutorService(Executors.newFixedThreadPool(5));
  }

}
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末响谓,一起剝皮案震驚了整個濱河市损合,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌娘纷,老刑警劉巖嫁审,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異赖晶,居然都是意外死亡律适,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進店門遏插,熙熙樓的掌柜王于貴愁眉苦臉地迎上來捂贿,“玉大人,你說我怎么就攤上這事涩堤【祢眩” “怎么了?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵胎围,是天一觀的道長吁系。 經(jīng)常有香客問我,道長白魂,這世上最難降的妖魔是什么汽纤? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮福荸,結果婚禮上蕴坪,老公的妹妹穿的比我還像新娘。我一直安慰自己敬锐,他們只是感情好背传,可當我...
    茶點故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著台夺,像睡著了一般径玖。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上颤介,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天梳星,我揣著相機與錄音赞赖,去河邊找鬼。 笑死冤灾,一個胖子當著我的面吹牛前域,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播韵吨,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼匿垄,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了学赛?” 一聲冷哼從身側響起年堆,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎盏浇,沒想到半個月后变丧,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡绢掰,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年痒蓬,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片滴劲。...
    茶點故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡攻晒,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出班挖,到底是詐尸還是另有隱情鲁捏,我是刑警寧澤,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布萧芙,位于F島的核電站给梅,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏双揪。R本人自食惡果不足惜动羽,卻給世界環(huán)境...
    茶點故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望渔期。 院中可真熱鬧运吓,春花似錦、人聲如沸疯趟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽信峻。三九已至宅静,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間站欺,已是汗流浹背姨夹。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留矾策,地道東北人磷账。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像贾虽,于是被迫代替她去往敵國和親逃糟。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,724評論 2 354

推薦閱讀更多精彩內(nèi)容