OAuth 的全方位滲透及node實(shí)現(xiàn)

背景

我們先從一個(gè)非常典型例子出發(fā)蚕泽,假如你在某網(wǎng)盤(pán)上傳了你的很多圖片晌梨,網(wǎng)盤(pán)提供了圖片存儲(chǔ),另一個(gè)某打印店提供了在線打印圖片须妻。

由于存儲(chǔ)和答應(yīng)是由兩家不同的服務(wù)商提供的仔蝌,兩家各自都提供了用戶的注冊(cè)功能,所以如果你要想在打印店上去打印你放在網(wǎng)盤(pán)的照片時(shí)荒吏,此時(shí)你會(huì)想到2種方案:

  • 假設(shè)你的賬戶密碼都不一樣敛惊,你可以先將待打印的圖片從網(wǎng)盤(pán)上下載下來(lái),然后在上傳到打印店的網(wǎng)站上绰更,之后進(jìn)行打印瞧挤。這種模式是最原始,也是效率最低下儡湾。
  • 為了省事皿伺,你可以將你網(wǎng)盤(pán)的賬戶密碼交給打印店老板,告訴他你要打印的圖片盒粮,讓他給你操作鸵鸥,省事,但是風(fēng)險(xiǎn)太大,帳號(hào)密碼都泄漏了妒穴,就不怕別人去篡改個(gè)人信息或者查看你的隱私宋税?

之前很多公司包括GoogleYahoo讼油、Microsoft都嘗試解決這個(gè)問(wèn)題杰赛,這也促使OAuth的誕生。

什么是 OAuth 矮台?

OAuthOpen Authorization)是一個(gè)開(kāi)放標(biāo)準(zhǔn)乏屯,允許用戶讓第三方應(yīng)用訪問(wèn)該用戶在某一網(wǎng)站上存儲(chǔ)的私密的資源(如照片,視頻瘦赫,聯(lián)系人列表)辰晕,而不需要將用戶名和密碼提供給第三方網(wǎng)站或分享他們數(shù)據(jù)的所有內(nèi)容,目前在全世界范圍內(nèi)得到廣泛應(yīng)用确虱。

OAuth 解決思路

OAuth客戶端(Client)打印店資源服務(wù)器(Resource Server網(wǎng)盤(pán) 之間含友,設(shè)置了一個(gè)授權(quán)層(Authorization Layer),通過(guò) 授權(quán)服務(wù)器(Authorization Server 提供用戶授權(quán)校辩。

客戶端 要想訪問(wèn) 資源服務(wù)器 必須要經(jīng)過(guò) 授權(quán)層窘问,用戶資源擁有者(Resource Owner) 可以在登錄的時(shí)候,指定授權(quán)層令牌的權(quán)限范圍和有效期宜咒,當(dāng)用戶同意授權(quán)后才向客戶端開(kāi)放用戶儲(chǔ)存的資料惠赫。

通俗來(lái)說(shuō):當(dāng)打印店要訪問(wèn)用戶的你網(wǎng)盤(pán)的圖片時(shí),通過(guò)OAuth機(jī)制故黑,打印店要向網(wǎng)盤(pán)的授權(quán)服務(wù)器請(qǐng)求授權(quán)汉形,網(wǎng)盤(pán)服務(wù)商將引導(dǎo)你在網(wǎng)盤(pán)的網(wǎng)站上登錄,并詢問(wèn)你是否將訪問(wèn)圖片的服務(wù)授權(quán)給打印店倍阐。當(dāng)你點(diǎn)擊同意后,打印店就可以訪問(wèn)你網(wǎng)盤(pán)上的圖片服務(wù)逗威。整個(gè)過(guò)程打印店沒(méi)有觸及到你網(wǎng)盤(pán)的帳號(hào)信息峰搪,安全便捷。

OAuth 授權(quán)流程

Abstract Protocol Flow

 +--------+                               +---------------+
 |        |--(A)- Authorization Request ->|   Resource    |
 |        |                               |     Owner     |
 |        |<-(B)-- Authorization Grant ---|               |
 |        |                               +---------------+
 |        |
 |        |                               +---------------+
 |        |--(C)-- Authorization Grant -->| Authorization |
 | Client |                               |     Server    |
 |        |<-(D)----- Access Token -------|               |
 |        |                               +---------------+
 |        |
 |        |                               +---------------+
 |        |--(E)----- Access Token ------>|    Resource   |
 |        |                               |     Server    |
 |        |<-(F)--- Protected Resource ---|               |
 +--------+                               +---------------+

大體流程如下:

  • Authrization Request:用戶打開(kāi)客戶端凯旭,客戶端向用戶請(qǐng)求對(duì)資源服務(wù)器的authorization grant概耻,要求用戶給予授權(quán)。
  • Authorization Grant(Get):用戶同意授權(quán)請(qǐng)求罐呼,客戶端將收到一個(gè)authorization grant授權(quán)許可鞠柄。
  • Authorization Grant(Post):客戶端向授權(quán)服務(wù)器發(fā)送它自己的客戶端身份標(biāo)識(shí)和上一步中的 authorization grant授權(quán)許可,請(qǐng)求訪問(wèn)令牌嫉柴。
  • Access Token(Get):認(rèn)證服務(wù)器對(duì)客戶端身份進(jìn)行認(rèn)證厌杜,如果認(rèn)證通過(guò)并且 authorization grant 也被驗(yàn)證通過(guò),授權(quán)服務(wù)器將為客戶端派發(fā) access token 訪問(wèn)令牌,授權(quán)階段至此全部結(jié)束夯尽。
  • Access Token(Post && Validate):客戶端向資源服務(wù)器發(fā)送access token用于驗(yàn)證并請(qǐng)求資源信息瞧壮。
  • Protected Resource(Get):資源服務(wù)器進(jìn)行請(qǐng)求驗(yàn)證,如果 access token驗(yàn)證通過(guò)匙握,資源服務(wù)器將向客戶端返回資源信息咆槽。

授權(quán)模式

根據(jù)應(yīng)用請(qǐng)求授權(quán)的方式和授權(quán)方服務(wù)支持的 Grant Type的不同,OAuth 2 定義了四種 Grant Type(授權(quán)模式)圈纺,每一種都有適用的應(yīng)用場(chǎng)景:

  • 授權(quán)碼模式(Authorization Code):最常使用的一種授權(quán)許可類(lèi)型秦忿,結(jié)合普通服務(wù)器端應(yīng)用使用。
  • 隱式授權(quán)模式(Implicit):跳過(guò)授權(quán)碼這個(gè)步驟蛾娶,適用于移動(dòng)應(yīng)用或 Web App
  • 密碼模式(Resource Owner Password Credentials):客戶端提供帳號(hào)密碼灯谣,向服務(wù)商索要授權(quán),適用于受信任客戶端應(yīng)用
  • 客戶端模式(Client Credentials):客戶端直接向服務(wù)商索取授權(quán)茫叭,適用于客戶端調(diào)用主服務(wù)API型應(yīng)用

授權(quán)碼模式(Authorization Code)

是目前互聯(lián)網(wǎng)上最常使用的一種授權(quán)模式酬屉,比如QQ,微博揍愁,Facebook和豆瓣等等呐萨,它要求第三方應(yīng)用先申請(qǐng)一個(gè)授權(quán)碼(Authorization Code),然后再用該碼獲取令牌莽囤,請(qǐng)求數(shù)據(jù)谬擦,流程如下:

 +----------+
 | Resource |
 |   Owner  |
 |          |
 +----------+
      ^
      |
     (B)
 +----|-----+                                          +---------------+
 |         -+----(A)-- User Authorization Request ---->|               |
 |  User-   |                                          | Authorization |
 |  Agent  -+----(B)-- User authenticates ------------>|     Server    |
 |          |                                          |               |
 |         -+----(C)-- Authorization Code Grant ------<|               |
 +-|----|---+                                          +---------------+
   |    |                                                 ^      v
  (A)  (C)                                                |      |
   |    |                                                 |      |
   ^    v                                                 |      |
 +---------+                                              |      |
 |         |>---(D)-- Access Token Request ---------------'      |
 |  Client |                                                     |
 |         |                                                     |
 |         |< ---(E)-- Access Token Grant -----------------------'
 +---------+       (w/ Optional Refresh Token)

User Authorization Request :用戶訪問(wèn)客戶端,客戶端構(gòu)造了一個(gè)用于請(qǐng)求authorization codeURL并引導(dǎo)用戶跳轉(zhuǎn)訪問(wèn)朽缎,鏈接格式大概如下:

https://open.server-name.com/oauth2/authorize
    ?response_type=code
    &client_id=AppID
    &redirect_uri=REDIRECT_URI
    &scope=SCOPE
    &state=STATE
  • response_type:授權(quán)模式惨远,必選,此時(shí)值固定為code
  • client_id:客戶端身份標(biāo)識(shí)话肖,一般是注冊(cè)時(shí)候的分配的 AppID
  • redirect_uri:授權(quán)成功后重定向地址北秽,必選,注意需要將uri進(jìn)行URLEncode
  • scope:授權(quán)范圍最筒,可選
  • state:客戶端的狀態(tài)值贺氓,必選,一般是隨機(jī)字符串床蜘,成功授權(quán)后回調(diào)時(shí)會(huì)原樣帶回辙培,為了防止CSRF攻擊

User authenticates:用戶決定是否給客戶端授權(quán),授權(quán)服務(wù)會(huì)提示用戶授權(quán)或拒絕應(yīng)用程序訪問(wèn)其帳戶信息

Authorization Code Grant:用戶確認(rèn)授權(quán)邢锯,授權(quán)服務(wù)器將重定向之前客戶端提供的redirect_uri地址扬蕊,并附帶codestate參數(shù),客戶端便能取到authorization code的值丹擎,鏈接格式大概如下:

https://client-name.com/redirect_url
 ?code=520DD95263C1CFEA087
 &state=STATE
  • code:授權(quán)服務(wù)器生成的authorization code尾抑,即授權(quán)碼,code 有效期較短,一般維持在 5 - 10分鐘蛮穿,授權(quán)服務(wù)器可自行配置
  • state:即客戶端之前攜帶的 state 值庶骄,可進(jìn)行檢查對(duì)比與最初設(shè)置的狀態(tài)值相匹配,防止CSRF攻擊

Access Token Request:客戶端獲取到授權(quán)碼 code 后践磅,可向服務(wù)器請(qǐng)求(post)獲取 access_token 单刁,一般來(lái)說(shuō)請(qǐng)求參數(shù)如下:

參數(shù) 是否必須 含義
grant_type 必須 授權(quán)類(lèi)型,此值固定為authorization_code
code 必須 授權(quán)碼
client_id 必須 客戶端標(biāo)識(shí)府适,一般是第三方分配的AppID
client_secret 必須 客戶端密鑰羔飞,一般是第三方分配的AppSecret
redirect_uri 必須 回調(diào)地址,與之前的 redirect_uri保持一致

Access Token Grant:服務(wù)器會(huì)驗(yàn)證客戶端傳過(guò)來(lái)的參數(shù)檐春,驗(yàn)證通過(guò)后逻淌,給客戶端返回 access token,一般返回?cái)?shù)據(jù)格式如下:

{
  "access_token":"2YotnFZFEjr1zCsicMWpAA",
  "token_type":"example"疟暖,
  "expires_in":3600,
  "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
  "scope":"user_info"
}
  • access_token:訪問(wèn)令牌
  • token_type:令牌類(lèi)型
  • expires_in:令牌過(guò)期時(shí)間
  • refresh_token:刷新令牌
  • scope:權(quán)限范圍

其中 refresh_token 用于在授權(quán)自動(dòng)續(xù)期步驟中卡儒,獲取新的Access_Token時(shí)需要提供的參數(shù)。

至此俐巴,授權(quán)流程全部結(jié)束骨望。

隱式授權(quán)模式(Implicit)

跟前面的Authorization Code模式非常相似,只是省略掉了頒發(fā)授權(quán)碼(Authorization Code)給客戶端的過(guò)程欣舵,而是直接返回訪問(wèn)令牌和可選的刷新令牌擎鸠。適用于沒(méi)有Server服務(wù)器來(lái)接受處理Authorization Code的第三方應(yīng)用,其整個(gè)流程如下:

 +----------+
 | Resource |
 |  Owner   |
 |          |
 +----------+
      ^
      |
     (B)
 +----|-----+                                         +---------------+
 |         -+----(A)-- User Authorization Request --->|               |
 |  User-   |                                         | Authorization |
 |  Agent  -|----(B)-- User Authenticates ----------->|     Server    |
 |          |                                         |               |
 |          |<---(C)-- Redirect URI With ------------<|               |
 |          |          Access Token                   +---------------+
 |          |            
 |          |                                         +---------------+
 |          |----(D)---Follow  Redirect URI --------->|   Web-Hosted  |
 |          |                                         |     Client    |
 |          |                                         |    Resource   |
 |          |<---(E)-- Send Token Extract Script ----<|               |
 |          |                                         +---------------+
 +-|--------+
   |    |
  (A)  (F) Pass Token to Application
   |    |
   ^    v
 +---------+
 |         |
 |  Client |
 |         |

User Authorization Request:客戶端提構(gòu)造了一個(gè)用于請(qǐng)求授權(quán)的鏈接缘圈,鏈接格式大概如下:

https://open.server-name.com/oauth2/authorize
    ?response_type=token
    &client_id=AppID
    &redirect_uri=REDIRECT_URI
    &scope=SCOPE
    &state=STATE

與之前的授權(quán)碼模式相比劣光,只是將 response_type 換成了 token

User Authenticates:與之前的相同,用戶決定是否給客戶端授權(quán)

Redirect URI With Access Token:用戶同意授權(quán)糟把,認(rèn)證服務(wù)器將用戶重定向到客戶端指定的重定向redirect_uri绢涡,并在uri的中添加訪問(wèn)令牌,鏈接格式大概如下:

http://client.name.com/redirect_url/#access_token=2YotnFZFEjr1zCsicMWpAA&token_type=Bearer&expires_in=3600&scope=SCOPE&state=STATE

此時(shí)的 token_type 恒為 Bearer遣疯。

要注意的是雄可,返回值放到了REDIRECT_URIhash 部分,而不是作為 ?query 參數(shù)另锋,這樣瀏覽器在訪問(wèn)重定向指定的url時(shí),就不會(huì)把這些數(shù)據(jù)發(fā)送到服務(wù)器狭归。

Follow Redirect URI:瀏覽器請(qǐng)求redirect_uri標(biāo)識(shí)的客戶端地址夭坪,此時(shí)不包含hash值,并保留access_token相關(guān)信息过椎。

Send Token Extract Script:客戶端返回一個(gè)包含 token 的頁(yè)面室梅,頁(yè)面執(zhí)行腳本獲取 redirect_uri 中的 access_token

Pass Token to Application:瀏覽器獲取的令牌發(fā)給客戶端。

至此亡鼠,授權(quán)流程全部結(jié)束赏殃。

密碼模式(Resource Owner Password Credentials)

這種模式更加簡(jiǎn)化,客戶端直接使用用戶提供的usernamepassword來(lái)直接請(qǐng)求獲取access_token信息间涵,這種模式一般適用于用戶高度信任第三方客戶端的情況仁热,其整個(gè)流程如下:

 +----------+
 | Resource |
 |  Owner   |
 |          |
 +----------+
      v
      |    
     (A) Resource Owner Password Credentials From User Input
      |
      v
 +---------+                                            +---------------+
 |         |>--(B)---- Resource Owner ----------------->|               |
 |         |         Password Credentials To Server     | Authorization |
 | Client  |                                            |     Server    |
 |         |<--(C)- Access Token Passed To Application-<|               |
 |         |       (w/ Optional Refresh Token)          |               |
 +---------+                                            +---------------+

Resource Owner Password Credentials From User Input:用戶向客戶端提供用戶名與密碼作為授權(quán)憑據(jù)。

Resource Owner Password Credentials From Client To Server:客戶端向授權(quán)服務(wù)器發(fā)送用戶輸入的授權(quán)憑據(jù)以請(qǐng)求 access token(要求客戶端必須已經(jīng)在服務(wù)器端進(jìn)行注冊(cè))勾哩,其請(qǐng)求參數(shù)主要如下:

參數(shù) 是否必須 含義
grant_type 必須 授權(quán)類(lèi)型抗蠢,此值固定為password
username 必須 用戶登陸名
passward 必須 用戶登陸密碼
scope 非必須 授權(quán)范圍

Access Token Passed To Application:授權(quán)服務(wù)器對(duì)客戶端進(jìn)行認(rèn)證并檢驗(yàn)用戶憑據(jù)的合法性,如果檢驗(yàn)通過(guò)思劳,將向客戶端返回 access token迅矛。

至此,授權(quán)流程結(jié)束潜叛。

客戶端模式(Client Credentials)

這是最簡(jiǎn)單的一種授權(quán)模式秽褒,客戶端直接已自己的名義,而不是用戶的名義直接去授權(quán)服務(wù)器發(fā)起授權(quán)威兜,獲取 access_token销斟,流程也是非常簡(jiǎn)單:

 +---------+                                  +---------------+
 |         |                                  |               |
 |         |>--(A)- Client Authentication --->| Authorization |
 | Client  |                                  |     Server    |
 |         |<--(B)---- Access Token ---------<|               |
 |         |                                  |               |
 +---------+                                  +---------------+

Client Authentication:客戶端直接發(fā)起授權(quán)請(qǐng)求,此時(shí)的 grant_type 的值為 client_credentials

Access Token:認(rèn)證服務(wù)器確認(rèn)身份后牡属,向客戶端發(fā)放 access_token

小試牛刀

鑒于授權(quán)碼模式(Authorization Code) 是目前來(lái)說(shuō)使用最為廣泛票堵,流程也時(shí)最為最完整、流程最嚴(yán)密的一種授權(quán)模式逮栅,我以它為例采用的 koa2 悴势,自定義實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的 Authorization Code 授權(quán)方案。

主要思路還是通過(guò) client 引導(dǎo)用戶點(diǎn)擊進(jìn)入授權(quán)頁(yè)措伐,在授權(quán)頁(yè)面通過(guò)確認(rèn)授權(quán)后向后端請(qǐng)求 code 特纤, 重定向到 redirect_uri , 并獲取服務(wù)端的 code侥加,之后通過(guò) code 再去請(qǐng)求服務(wù)端獲取令牌 access_token捧存,之后通過(guò) access_token 獲取用戶信息,整個(gè)效果如下圖所示:

這里我就不放代碼了担败,容易占地方N粞ā!詳情請(qǐng)戳這里

pass:代碼里面的數(shù)據(jù)都是mock的提前,還是有較多異常case未做處理吗货,旨在了解整個(gè)授權(quán)的過(guò)程和實(shí)現(xiàn)思路,僅供參考

結(jié)語(yǔ)

OAuth 的授權(quán)方案目前已經(jīng)非常成熟狈网,在整個(gè)互聯(lián)網(wǎng)行業(yè)中也是非常常見(jiàn)的宙搬,早些年做微信生態(tài)的公眾號(hào)的時(shí)候初次接觸笨腥,到現(xiàn)在的深入了解,也算是一些進(jìn)步吧勇垛。

希望閱讀完本文也能讓你對(duì) OAuth 授權(quán)有一個(gè)深刻全面的認(rèn)識(shí)脖母,或者是加深鞏固 OAuth 授權(quán)方面的知識(shí)。

理論結(jié)合實(shí)踐闲孤,才是我們做為coder應(yīng)有的追求谆级,加油!

參考資料及文獻(xiàn)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末崭放,一起剝皮案震驚了整個(gè)濱河市哨苛,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌币砂,老刑警劉巖建峭,帶你破解...
    沈念sama閱讀 218,682評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異决摧,居然都是意外死亡亿蒸,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)掌桩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)边锁,“玉大人,你說(shuō)我怎么就攤上這事波岛∶┨常” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,083評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵则拷,是天一觀的道長(zhǎng)贡蓖。 經(jīng)常有香客問(wèn)我,道長(zhǎng)煌茬,這世上最難降的妖魔是什么斥铺? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,763評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮坛善,結(jié)果婚禮上晾蜘,老公的妹妹穿的比我還像新娘。我一直安慰自己眠屎,他們只是感情好剔交,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著改衩,像睡著了一般岖常。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上燎字,一...
    開(kāi)封第一講書(shū)人閱讀 51,624評(píng)論 1 305
  • 那天腥椒,我揣著相機(jī)與錄音,去河邊找鬼候衍。 笑死笼蛛,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的蛉鹿。 我是一名探鬼主播滨砍,決...
    沈念sama閱讀 40,358評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼妖异!你這毒婦竟也來(lái)了惋戏?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,261評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤他膳,失蹤者是張志新(化名)和其女友劉穎响逢,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體棕孙,經(jīng)...
    沈念sama閱讀 45,722評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡舔亭,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蟀俊。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片钦铺。...
    茶點(diǎn)故事閱讀 40,030評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖肢预,靈堂內(nèi)的尸體忽然破棺而出矛洞,到底是詐尸還是另有隱情,我是刑警寧澤烫映,帶...
    沈念sama閱讀 35,737評(píng)論 5 346
  • 正文 年R本政府宣布沼本,位于F島的核電站,受9級(jí)特大地震影響窑邦,放射性物質(zhì)發(fā)生泄漏擅威。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評(píng)論 3 330
  • 文/蒙蒙 一冈钦、第九天 我趴在偏房一處隱蔽的房頂上張望郊丛。 院中可真熱鬧,春花似錦瞧筛、人聲如沸厉熟。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,941評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)揍瑟。三九已至,卻和暖如春乍炉,著一層夾襖步出監(jiān)牢的瞬間绢片,已是汗流浹背滤馍。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,057評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留底循,地道東北人巢株。 一個(gè)月前我還...
    沈念sama閱讀 48,237評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像熙涤,于是被迫代替她去往敵國(guó)和親阁苞。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評(píng)論 2 355