前端鑒權的兄弟們:cookie帆调、session奠骄、token、jwt番刊、單點登錄

本文你將看到:

  • 基于 HTTP 的前端鑒權背景
  • cookie 為什么是最方便的存儲方案含鳞,有哪些操作 cookie 的方式
  • session 方案是如何實現的,存在哪些問題
  • token 方案是如何實現的芹务,如何進行編碼和防篡改蝉绷?jwt 是做什么的?refresh token 的實現和意義
  • session 和 token 有什么異同和優(yōu)缺點
  • 單點登錄是什么枣抱?實現思路和在瀏覽器下的處理

從狀態(tài)說起

「HTTP 無狀態(tài)」

我們知道熔吗,HTTP 是無狀態(tài)的。也就是說佳晶,HTTP 請求方和響應方間無法維護狀態(tài)桅狠,都是一次性的,它不知道前后的請求都發(fā)生了什么。

但有的場景下中跌,我們需要維護狀態(tài)咨堤。最典型的,一個用戶登陸微博漩符,發(fā)布一喘、關注、評論嗜暴,都應是在登錄后的用戶狀態(tài)下的津滞。

「標記」

那解決辦法是什么呢?::標記::灼伤。

在學校或公司咪鲜,入學入職那一天起狐赡,會錄入你的身份、賬戶信息疟丙,然后給你發(fā)個卡颖侄,今后在園區(qū)內,你的門禁享郊、打卡览祖、消費都只需要刷這張卡。

「前端存儲」

這就涉及到一發(fā)炊琉、一存展蒂、一帶,發(fā)好辦苔咪,登陸接口直接返回給前端锰悼,存儲就需要前端想辦法了。

前提是团赏,你要把卡帶在身上箕般。

前端的存儲方式有很多。

  • 最矬的舔清,掛到全局變量上丝里,但這是個「體驗卡」,一次刷新頁面就沒了
  • 高端點的体谒,存到 cookie杯聚、localStorage 等里,這屬于「會員卡」抒痒,無論怎么刷新械媒,只要瀏覽器沒清掉或者過期,就一直拿著這個狀態(tài)。

前端存儲這里不展開了纷捞。

有地方存了痢虹,請求的時候就可以拼到參數里帶給接口了。


基石:cookie

可是前端好麻煩啊主儡,又要自己存奖唯,又要想辦法帶出去,有沒有不用操心的糜值?

有丰捷,cookie。

cookie 也是前端存儲的一種寂汇,但相比于 localStorage 等其他方式病往,借助 HTTP 頭、瀏覽器能力骄瓣,cookie 可以做到前端無感知停巷。

一般過程是這樣的:

  • 在提供標記的接口,通過 HTTP 返回頭的 Set-Cookie 字段榕栏,直接「種」到瀏覽器上
  • 瀏覽器發(fā)起請求時畔勤,會自動把 cookie 通過 HTTP 請求頭的 Cookie 字段,帶給接口

「配置:Domain / Path」

你不能拿清華的校園卡進北大扒磁。

cookie 是要限制::「空間范圍」::的庆揪,通過 Domain(域)/ Path(路徑)兩級。

Domain屬性指定瀏覽器發(fā)出 HTTP 請求時妨托,哪些域名要附帶這個 Cookie缸榛。如果沒有指定該屬性,瀏覽器會默認將其設為當前 URL 的一級域名兰伤,比如 www.example.com 會設為 example.com仔掸,而且以后如果訪問example.com的任何子域名,HTTP 請求也會帶上這個 Cookie医清。如果服務器在Set-Cookie字段指定的域名起暮,不屬于當前域名,瀏覽器會拒絕這個 Cookie会烙。

Path屬性指定瀏覽器發(fā)出 HTTP 請求時负懦,哪些路徑要附帶這個 Cookie。只要瀏覽器發(fā)現柏腻,Path屬性是 HTTP 請求路徑的開頭一部分纸厉,就會在頭信息里面帶上這個 Cookie。比如五嫂,PATH屬性是/颗品,那么請求/docs路徑也會包含該 Cookie肯尺。當然,前提是域名必須一致躯枢。

—— Cookie — JavaScript 標準參考教程(alpha)

「配置:Expires / Max-Age」

你畢業(yè)了卡就不好使了则吟。

cookie 還可以限制::「時間范圍」::,通過 Expires锄蹂、Max-Age 中的一種氓仲。

Expires屬性指定一個具體的到期時間,到了指定時間以后得糜,瀏覽器就不再保留這個 Cookie敬扛。它的值是 UTC 格式。如果不設置該屬性朝抖,或者設為null啥箭,Cookie 只在當前會話(session)有效,瀏覽器窗口一旦關閉治宣,當前 Session 結束急侥,該 Cookie 就會被刪除。另外炼七,瀏覽器根據本地時間,決定 Cookie 是否過期布持,由于本地時間是不精確的豌拙,所以沒有辦法保證 Cookie 一定會在服務器指定的時間過期。

Max-Age屬性指定從現在開始 Cookie 存在的秒數题暖,比如60 * 60 * 24 * 365(即一年)按傅。過了這個時間以后,瀏覽器就不再保留這個 Cookie胧卤。

如果同時指定了Expires和Max-Age唯绍,那么Max-Age的值將優(yōu)先生效。

如果Set-Cookie字段沒有指定Expires或Max-Age屬性枝誊,那么這個 Cookie 就是 Session Cookie况芒,即它只在本次對話存在,一旦用戶關閉瀏覽器叶撒,瀏覽器就不會再保留這個 Cookie绝骚。

—— Cookie — JavaScript 標準參考教程(alpha)

「配置:Secure / HttpOnly」

有的學校規(guī)定,不帶卡套不讓刷(什么奇葩學校祠够,假設)压汪;有的學校不讓自己給卡貼貼紙。

cookie 可以限制::「使用方式」::古瓤。

Secure屬性指定瀏覽器只有在加密協議 HTTPS 下止剖,才能將這個 Cookie 發(fā)送到服務器腺阳。另一方面,如果當前協議是 HTTP穿香,瀏覽器會自動忽略服務器發(fā)來的Secure屬性亭引。該屬性只是一個開關,不需要指定值扔水。如果通信是 HTTPS 協議痛侍,該開關自動打開。

HttpOnly屬性指定該 Cookie 無法通過 JavaScript 腳本拿到魔市,主要是Document.cookie屬性主届、XMLHttpRequest對象和 Request API 都拿不到該屬性。這樣就防止了該 Cookie 被腳本讀到待德,只有瀏覽器發(fā)出 HTTP 請求時君丁,才會帶上該 Cookie。

—— Cookie — JavaScript 標準參考教程(alpha)

「HTTP 頭對 cookie 的讀寫」

回過頭來将宪,HTTP 是如何寫入和傳遞 cookie 及其配置的呢绘闷?

HTTP 返回的一個 Set-Cookie 頭用于向瀏覽器寫入「一條(且只能是一條)」cookie,格式為 cookie 鍵值 + 配置鍵值较坛。例如:

Set-Cookie: username=jimu; domain=jimu.com; path=/blog; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secure; HttpOnly 

那我想一次多 set 幾個 cookie 怎么辦印蔗?多給幾個 Set-Cookie 頭(一次 HTTP 請求中允許重復)

Set-Cookie: username=jimu; domain=jimu.comSet-Cookie: height=180; domain=me.jimu.comSet-Cookie: weight=80; domain=me.jimu.com 

HTTP 請求的 Cookie 頭用于瀏覽器把符合當前「空間、時間丑勤、使用方式」配置的所有 cookie 一并發(fā)給服務端华嘹。因為由瀏覽器做了篩選判斷,就不需要歸還配置內容了法竞,只要發(fā)送鍵值就可以耙厚。

Cookie: username=jimu; height=180; weight=80 

「前端對 cookie 的讀寫」

前端可以自己創(chuàng)建 cookie,如果服務端創(chuàng)建的 cookie 沒加HttpOnly岔霸,那恭喜你也可以修改他給的 cookie薛躬。

調用document.cookie可以創(chuàng)建、修改 cookie呆细,和 HTTP 一樣型宝,一次document.cookie能且只能操作一個 cookie。

document.cookie = 'username=jimu; domain=jimu.com; path=/blog; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secure; HttpOnly'; 

調用document.cookie也可以讀到 cookie絮爷,也和 HTTP 一樣诡曙,能讀到所有的非HttpOnlycookie。

console.log(document.cookie);// username=jimu; height=180; weight=80 

(就一個 cookie 屬性略水,為什么讀寫行為不一樣价卤?get / set 了解下)

「cookie 是維持 HTTP 請求狀態(tài)的基石」

了解了 cookie 后,我們知道 cookie 是最便捷的維持 HTTP 請求狀態(tài)的方式渊涝,大多數前端鑒權問題都是靠 cookie 解決的慎璧。當然也可以選用別的存儲方式(后面也會多多少少提到)床嫌。

那有了存儲工具,接下來怎么做呢胸私?


應用方案:服務端 session

現在回想下厌处,你刷卡的時候發(fā)生了什么?

其實你的卡上只存了一個 id(可能是你的學號)岁疼,刷的時候物業(yè)系統(tǒng)去查你的信息阔涉、賬戶,再決定「這個門你能不能進」「這個雞腿去哪個賬戶扣錢」捷绒。

這種操作瑰排,在前后端鑒權系統(tǒng)中,叫 session暖侨。

典型的 session 登陸/驗證流程:

圖片
  • 瀏覽器登錄發(fā)送賬號密碼椭住,服務端查用戶庫,校驗用戶
  • 服務端把用戶登錄狀態(tài)存為 Session字逗,生成一個 sessionId
  • 通過登錄接口返回京郑,把 sessionId set 到 cookie 上
  • 此后瀏覽器再請求業(yè)務接口,sessionId 隨 cookie 帶上
  • 服務端查 sessionId 校驗 session
  • 成功后正常做業(yè)務處理葫掉,返回結果

「Session 的存儲方式」

顯然些举,服務端只是給 cookie 一個 sessionId,而 session 的具體內容(可能包含用戶信息俭厚、session 狀態(tài)等)户魏,要自己存一下。存儲的方式有幾種:

  • Redis(推薦):內存型數據庫套腹,redis中文官方網站绪抛。以 key-value 的形式存资铡,正合 sessionId-sessionData 的場景电禀;且訪問快。
  • 內存:直接放到變量里笤休。一旦服務重啟就沒了
  • 數據庫:普通數據庫尖飞。性能不高。

「Session 的過期和銷毀」

很簡單店雅,只要把存儲的 session 數據銷毀就可以政基。

「Session 的分布式問題」

通常服務端是集群,而用戶請求過來會走一次負載均衡闹啦,不一定打到哪臺機器上沮明。那一旦用戶后續(xù)接口請求到的機器和他登錄請求的機器不一致,或者登錄請求的機器宕機了窍奋,session 不就失效了嗎荐健?

這個問題現在有幾種解決方式酱畅。

  • 一是從「存儲」角度,把 session 集中存儲江场。如果我們用獨立的 Redis 或普通數據庫纺酸,就可以把 session 都存到一個庫里。
  • 二是從「分布」角度址否,讓相同 IP 的請求在負載均衡時都打到同一臺機器上餐蔬。以 nginx 為例,可以配置 ip_hash 來實現佑附。

但通常還是采用第一種方式樊诺,因為第二種相當于閹割了負載均衡,且仍沒有解決「用戶請求的機器宕機」的問題帮匾。

「node.js 下的 session 處理」

前面的圖很清楚了啄骇,服務端要實現對 cookie 和 session 的存取,實現起來要做的事還是很多的瘟斜。在npm中缸夹,已經有封裝好的中間件,比如 express-session - npm螺句,用法就不貼了虽惭。

這是它種的 cookie:

圖片

express-session - npm 主要實現了:

  • 封裝了對cookie的讀寫操作,并提供配置項配置字段蛇尚、加密方式芽唇、過期時間等。
  • 封裝了對session的存取操作取劫,并提供配置項配置session存儲方式(內存/redis)匆笤、存儲規(guī)則等。
  • 給req提供了session屬性谱邪,控制屬性的set/get并響應到cookie和session存取上炮捧,并給req.session提供了一些方法。

應用方案:token

session 的維護給服務端造成很大困擾惦银,我們必須找地方存放它咆课,又要考慮分布式的問題,甚至要單獨為了它啟用一套 Redis 集群扯俱。有沒有更好的辦法书蚪?

我又想到學校,在沒有校園卡技術以前迅栅,我們都靠「學生證」殊校。門衛(wèi)小哥直接對照我和學生證上的臉,確認學生證有效期读存、年級等信息为流,就可以放行了窜醉。

回過頭來想想,一個登錄場景艺谆,也不必往 session 存太多東西榨惰,那為什么不直接打包到 cookie 中呢?這樣服務端不用存了静汤,每次只要核驗 cookie 帶的「證件」有效性就可以了琅催,也可以攜帶一些輕量的信息。

這種方式通常被叫做 token虫给。

圖片

token 的流程是這樣的:

  • 用戶登錄藤抡,服務端校驗賬號密碼,獲得用戶信息
  • 把用戶信息抹估、token 配置編碼成 token缠黍,通過 cookie set 到瀏覽器
  • 此后用戶請求業(yè)務接口,通過 cookie 攜帶 token
  • 接口校驗 token 有效性药蜻,進行正常業(yè)務接口處理

「客戶端 token 的存儲方式」

在前面 cookie 說過瓷式,cookie 并不是客戶端存儲憑證的唯一方式。token 因為它的「無狀態(tài)性」语泽,有效期贸典、使用限制都包在 token 內容里,對 cookie 的管理能力依賴較小踱卵,客戶端存起來就顯得更自由廊驼。但 web 應用的主流方式仍是放在 cookie 里,畢竟少操心惋砂。

「token 的過期」

那我們如何控制 token 的有效期呢妒挎?很簡單,把「過期時間」和數據一起塞進去西饵,驗證時判斷就好酝掩。

token 的編碼

編碼的方式豐儉由人。

「base64」

比如 node 端的 cookie-session - npm 庫

不要糾結名字罗标,其實是個 token 庫庸队,但保持了和 express-session - npm 高度一致的用法积蜻,把要存的數據掛在 session 上

默認配置下闯割,當我給他一個 userid,他會存成這樣:

圖片

這里的 eyJ1c2VyaWQiOiJhIn0=竿拆,就是 {"userid":"abb”} 的 base64 而已宙拉。

「防篡改」

那問題來了,如果用戶 cdd 拿{"userid":"abb”}轉了個 base64丙笋,再手動修改了自己的 token 為 eyJ1c2VyaWQiOiJhIn0=谢澈,是不是就能直接訪問到 abb 的數據了煌贴?

是的。所以看情況锥忿,如果 token 涉及到敏感權限牛郑,就要想辦法避免 token 被篡改。

解決方案就是給 token 加簽名敬鬓,來識別 token 是否被篡改過淹朋。例如在 cookie-session - npm 庫中,增加兩項配置:

secret: 'iAmSecret',signed: true, 

這樣會多種一個 .sig cookie钉答,里面的值就是 {"userid":"abb”}iAmSecret通過加密算法計算出來的础芍,常見的比如HMACSHA256 類 (System.Security.Cryptography) | Microsoft Docs。

圖片

好了数尿,現在 cdd 雖然能偽造出eyJ1c2VyaWQiOiJhIn0=仑性,但偽造不出 sig 的內容,因為他不知道 secret右蹦。

「JWT」

但上面的做法額外增加了 cookie 數量诊杆,數據本身也沒有規(guī)范的格式,所以 JSON Web Token Introduction - jwt.io 橫空出世了何陆。

JSON Web Token (JWT) 是一個開放標準刽辙,定義了一種傳遞 JSON 信息的方式。這些信息通過數字簽名確奔紫祝可信宰缤。

它是一種成熟的 token 字符串生成方案,包含了我們前面提到的數據晃洒、簽名慨灭。不如直接看一下一個 JWT token 長什么樣:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyaWQiOiJhIiwiaWF0IjoxNTUxOTUxOTk4fQ.2jf3kl_uKWRkwjOP6uQRJFqMlwSABcgqqcJofFH5XCo 

這串東西是怎么生成的呢?看圖:

圖片

類型球及、加密算法的選項氧骤,以及 JWT 標準數據字段,可以參考 RFC 7519 - JSON Web Token (JWT)

node 上同樣有相關的庫實現:express-jwt - npm koa-jwt - npm

refresh token

token吃引,作為權限守護者筹陵,最重要的就是「安全」。

業(yè)務接口用來鑒權的 token镊尺,我們稱之為 access token朦佩。越是權限敏感的業(yè)務,我們越希望 access token 有效期足夠短庐氮,以避免被盜用语稠。但過短的有效期會造成 access token 經常過期,過期后怎么辦呢?

一種辦法是仙畦,讓用戶重新登錄獲取新 token输涕,顯然不夠友好,要知道有的 access token 過期時間可能只有幾分鐘慨畸。

另外一種辦法是莱坎,再來一個 token,一個專門生成 access token 的 token寸士,我們稱為 refresh token型奥。

  • access token 用來訪問業(yè)務接口,由于有效期足夠短碉京,盜用風險小厢汹,也可以使請求方式更寬松靈活
  • refresh token 用來獲取 access token,有效期可以長一些谐宙,通過獨立服務和嚴格的請求方式增加安全性烫葬;由于不常驗證,也可以如前面的 session 一樣處理

有了 refresh token 后凡蜻,幾種情況的請求流程變成這樣:

圖片

如果 refresh token 也過期了搭综,就只能重新登錄了。

session 和 token

session 和 token 都是邊界很模糊的概念划栓,就像前面說的兑巾,refresh token 也可能以 session 的形式組織維護。

狹義上忠荞,我們通常認為 session 是「種在 cookie 上蒋歌、數據存在服務端」的認證方案,token 是「客戶端存哪都行委煤、數據存在 token 里」的認證方案堂油。對 session 和 token 的對比本質上是「客戶端存 cookie / 存別地兒」、「服務端存數據 / 不存數據」的對比碧绞。

「客戶端存 cookie / 存別地兒」

存 cookie 固然方便不操心府框,但問題也很明顯:

  • 在瀏覽器端,可以用 cookie(實際上 token 就常用 cookie)讥邻,但出了瀏覽器端迫靖,沒有 cookie 怎么辦?
  • cookie 是瀏覽器在域下自動攜帶的兴使,這就容易引發(fā) CSRF 攻擊(前端安全系列(二):如何防止CSRF攻擊系宜?- 美團技術團隊)

存別的地方,可以解決沒有 cookie 的場景鲫惶;通過參數等方式手動帶蜈首,可以避免 CSRF 攻擊实抡。

「服務端存數據 / 不存數據」

  • 存數據:請求只需攜帶 id欠母,可以大幅縮短認證字符串長度欢策,減小請求體積
  • 不存數據:不需要服務端整套的解決方案和分布式處理,降低硬件成本赏淌;避免查庫帶來的驗證延遲

單點登錄

前面我們已經知道了踩寇,在同域下的客戶端/服務端認證系統(tǒng)中,通過客戶端攜帶憑證六水,維持一段時間內的登錄狀態(tài)俺孙。

但當我們業(yè)務線越來越多霉晕,就會有更多業(yè)務系統(tǒng)分散到不同域名下脖镀,就需要「一次登錄透罢,全線通用」的能力卷玉,叫做「單點登錄」斧抱。

“虛假”的單點登錄(主域名相同)

簡單的析命,如果業(yè)務系統(tǒng)都在同一主域名下队丝,比如wenku.baidu.com tieba.baidu.com忠怖,就好辦了港准≈及可以直接把 cookie domain 設置為主域名 baidu.com,百度也就是這么干的浅缸。

圖片

“真實”的單點登錄(主域名不同)

比如滴滴這么潮的公司轨帜,同時擁有didichuxing.com xiaojukeji.com didiglobal.com等域名,種 cookie 是完全繞不開的衩椒。

這要能實現「一次登錄蚌父,全線通用」,才是真正的單點登錄毛萌。

這種場景下梢什,我們需要獨立的認證服務,通常被稱為 SSO朝聋。

「一次「從 A 系統(tǒng)引發(fā)登錄嗡午,到 B 系統(tǒng)不用登錄」的完整流程」

圖片
  • 用戶進入 A 系統(tǒng),沒有登錄憑證(ticket)冀痕,A 系統(tǒng)給他跳到 SSO
  • SSO 沒登錄過荔睹,也就沒有 sso 系統(tǒng)下沒有憑證(注意這個和前面 A ticket 是兩回事),輸入賬號密碼登錄
  • SSO 賬號密碼驗證成功言蛇,通過接口返回做兩件事:一是種下 sso 系統(tǒng)下憑證(記錄用戶在 SSO 登錄狀態(tài))僻他;二是下發(fā)一個 ticket
  • 客戶端拿到 ticket,保存起來腊尚,帶著請求系統(tǒng) A 接口
  • 系統(tǒng) A 校驗 ticket吨拗,成功后正常處理業(yè)務請求
  • 此時用戶第一次進入系統(tǒng) B,沒有登錄憑證(ticket),B 系統(tǒng)給他跳到 SSO
  • SSO 登錄過劝篷,系統(tǒng)下有憑證哨鸭,不用再次登錄,只需要下發(fā) ticket
  • 客戶端拿到 ticket娇妓,保存起來像鸡,帶著請求系統(tǒng) B 接口

「完整版本:考慮瀏覽器的場景」

上面的過程看起來沒問題,實際上很多 APP 等端上這樣就夠了哈恰。但在瀏覽器下不見得好用只估。

看這里:

圖片

對瀏覽器來說,SSO 域下返回的數據要怎么存着绷,才能在訪問 A 的時候帶上蛔钙?瀏覽器對跨域有嚴格限制,cookie荠医、localStorage 等方式都是有域限制的夸楣。

這就需要也只能由 A 提供 A 域下存儲憑證的能力。一般我們是這么做的:

圖片

圖中我們通過顏色把瀏覽器當前所處的域名標記出來子漩。注意圖中灰底文字說明部分的變化豫喧。

  • 在 SSO 域下,SSO 不是通過接口把 ticket 直接返回幢泼,而是通過一個帶 code 的 URL 重定向到系統(tǒng) A 的接口上紧显,這個接口通常在 A 向 SSO 注冊時約定
  • 瀏覽器被重定向到 A 域下,帶著 code 訪問了 A 的 callback 接口缕棵,callback 接口通過 code 換取 ticket
  • 這個 code 不同于 ticket孵班,code 是一次性的,暴露在 URL 中招驴,只為了傳一下換 ticket篙程,換完就失效
  • callback 接口拿到 ticket 后,在自己的域下 set cookie 成功
  • 在后續(xù)請求中别厘,只需要把 cookie 中的 ticket 解析出來虱饿,去 SSO 驗證就好
  • 訪問 B 系統(tǒng)也是一樣

總結

  • HTTP 是無狀態(tài)的,為了維持前后請求触趴,需要前端存儲標記
  • cookie 是一種完善的標記方式氮发,通過 HTTP 頭或 js 操作,有對應的安全策略冗懦,是大多數狀態(tài)管理方案的基石
  • session 是一種狀態(tài)管理方案爽冕,前端通過 cookie 存儲 id,后端存儲數據披蕉,但后端要處理分布式問題
  • token 是另一種狀態(tài)管理方案颈畸,相比于 session 不需要后端存儲乌奇,數據全部存在前端,解放后端眯娱,釋放靈活性
  • token 的編碼技術礁苗,通常基于 base64困乒,或增加加密算法防篡改寂屏,jwt 是一種成熟的編碼方案
  • 在復雜系統(tǒng)中贰谣,token 可通過 service token娜搂、refresh token 的分權,同時滿足安全性和用戶體驗
  • session 和 token 的對比就是「用不用cookie」和「后端存不存」的對比
  • 單點登錄要求不同域下的系統(tǒng)「一次登錄吱抚,全線通用」百宇,通常由獨立的 SSO 系統(tǒng)記錄登錄狀態(tài)、下發(fā) ticket秘豹,各業(yè)務系統(tǒng)配合存儲和認證 ticket
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末携御,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子既绕,更是在濱河造成了極大的恐慌啄刹,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件凄贩,死亡現場離奇詭異誓军,居然都是意外死亡,警方通過查閱死者的電腦和手機疲扎,發(fā)現死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進店門昵时,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人椒丧,你說我怎么就攤上這事壹甥。” “怎么了壶熏?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵句柠,是天一觀的道長。 經常有香客問我棒假,道長俄占,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任淆衷,我火速辦了婚禮缸榄,結果婚禮上,老公的妹妹穿的比我還像新娘祝拯。我一直安慰自己甚带,他們只是感情好她肯,可當我...
    茶點故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著鹰贵,像睡著了一般晴氨。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上碉输,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天籽前,我揣著相機與錄音,去河邊找鬼敷钾。 笑死枝哄,一個胖子當著我的面吹牛,可吹牛的內容都是我干的阻荒。 我是一名探鬼主播挠锥,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼侨赡!你這毒婦竟也來了蓖租?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤羊壹,失蹤者是張志新(化名)和其女友劉穎蓖宦,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體油猫,經...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡稠茂,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了眨攘。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片主慰。...
    茶點故事閱讀 38,599評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖鲫售,靈堂內的尸體忽然破棺而出共螺,到底是詐尸還是另有隱情,我是刑警寧澤情竹,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布藐不,位于F島的核電站,受9級特大地震影響秦效,放射性物質發(fā)生泄漏雏蛮。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一阱州、第九天 我趴在偏房一處隱蔽的房頂上張望挑秉。 院中可真熱鬧,春花似錦苔货、人聲如沸犀概。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽姻灶。三九已至铛绰,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間产喉,已是汗流浹背捂掰。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留曾沈,地道東北人这嚣。 一個月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像晦譬,于是被迫代替她去往敵國和親疤苹。 傳聞我的和親對象是個殘疾皇子互广,可洞房花燭夜當晚...
    茶點故事閱讀 43,465評論 2 348

推薦閱讀更多精彩內容