翻譯:CFNetwork編程指南(四)——與身份驗(yàn)證HTTP服務(wù)器通信(Communicating with Authenticating HTTP Servers)

本文描述了如何利用CFHTTPAuthentication API與需要身份驗(yàn)證的HTTP服務(wù)器通信烤黍。它解釋了如何找到匹配的驗(yàn)證對(duì)象和證書知市,并將它們應(yīng)用到HTTP請(qǐng)求傻盟,然后存儲(chǔ)以供以后使用。

一般來(lái)說嫂丙,如果一個(gè)eHTTP服務(wù)器返回一個(gè)401或407響應(yīng)你的HTTP請(qǐng)求娘赴,這表明服務(wù)器進(jìn)行身份驗(yàn)證需要證書。在CFHTTPAuthentication API中跟啤,每個(gè)證書組存儲(chǔ)在CFHTTPAuthentication 對(duì)象中诽表。因此,每個(gè)不同的身份認(rèn)證服務(wù)器和每個(gè)不同用戶連接的服務(wù)器需要一個(gè)單獨(dú)的CFHTTPAuthentication 對(duì)象隅肥。與服務(wù)器通信竿奏,你需要應(yīng)用CFHTTPAuthentication 對(duì)象到HTTP請(qǐng)求。接下來(lái)更加詳細(xì)的解釋這些步驟腥放。

處理身份驗(yàn)證

添加身份驗(yàn)證支持將允許你的應(yīng)用和身份驗(yàn)證服務(wù)器(如果服務(wù)器返回401或407響應(yīng))進(jìn)行交互泛啸。盡管HTTP身份驗(yàn)證不是一個(gè)難的概念,它是一個(gè)復(fù)雜的過程秃症。步驟如下:

1.客戶端向服務(wù)器發(fā)送一個(gè)HTTP請(qǐng)求候址。

2.服務(wù)器返回一個(gè)驗(yàn)證給客戶端。

3.客戶端將原始請(qǐng)求的證書打包并發(fā)送給服務(wù)器种柑。

4.在客戶端和服務(wù)器之間談判

5.當(dāng)服務(wù)器驗(yàn)證了客戶端身份岗仑,返回請(qǐng)求的響應(yīng)。

執(zhí)行這個(gè)過程需要多個(gè)步驟聚请。整個(gè)過程如圖4-1和4-2.

圖4-1 處理身份驗(yàn)證
圖4-2 找到一個(gè)身份驗(yàn)證對(duì)象

當(dāng)一個(gè)HTTP請(qǐng)求返回一個(gè)401或407響應(yīng)赔蒲,第一步是為客戶端找到一個(gè)有效的CFHTTPAuthentication 對(duì)象。一個(gè)身份驗(yàn)證對(duì)象包括證書和其他信息良漱,當(dāng)應(yīng)用到HTTP消息請(qǐng)求舞虱,與服務(wù)器驗(yàn)證你的身份。如果你已經(jīng)與服務(wù)器進(jìn)行過身份驗(yàn)證母市,你會(huì)有一個(gè)有效的身份驗(yàn)證對(duì)象矾兜。然而,在大多數(shù)情況下患久,你需要使用CFHTTPAuthenticationCreateFromResponse 函數(shù)來(lái)創(chuàng)建一個(gè)對(duì)象椅寺。見列表4-1.

注意:所有關(guān)于身份驗(yàn)證的示例代碼改編自ImageClient 應(yīng)用。

列表4-1 創(chuàng)建一個(gè)身份驗(yàn)證對(duì)象

<pre><code>
if (!authentication) {

CFHTTPMessageRef responseHeader =
    (CFHTTPMessageRef) CFReadStreamCopyProperty(
        readStream,
        kCFStreamPropertyHTTPResponseHeader
    );

// Get the authentication information from the response.
authentication =     

CFHTTPAuthenticationCreateFromResponse(NULL, responseHeader);

CFRelease(responseHeader);

}
</pre></code>

如果新身份驗(yàn)證對(duì)象有效蒋失,那么你已經(jīng)完成可以繼續(xù)圖4-1的第二步返帕。如果身份驗(yàn)證對(duì)象無(wú)效,然后扔掉身份驗(yàn)證對(duì)象和證書篙挽,檢查證書荆萤。關(guān)于證書的更多信息,閱讀安全證書(Security Credentials)。

不好的證書意味著服務(wù)器不接受登陸信息链韭,它將繼續(xù)監(jiān)聽新的證書偏竟。然而,如果證書是好的敞峭,但服務(wù)器仍然拒絕你的請(qǐng)求踊谋,然后服務(wù)器拒絕與你通信,你必須放棄旋讹。加上證書是不好的殖蚕,重試整個(gè)過程,先創(chuàng)建身份驗(yàn)證對(duì)象直到你得到有效的證書和有效的驗(yàn)證對(duì)象沉迹。這個(gè)過程類似于列表4-2中的代碼嫌褪。

列表4-2 查找一個(gè)有效的身份驗(yàn)證對(duì)象

<pre><code>
CFStreamError err;
if (!authentication) {

// the newly created authentication object is bad, must return
return;

} else if (!CFHTTPAuthenticationIsValid(authentication, &err)) {

// destroy authentication and credentials
if (credentials) {
    CFRelease(credentials);
    credentials = NULL;
}
CFRelease(authentication);
authentication = NULL;

// check for bad credentials (to be treated separately)
if (err.domain == kCFStreamErrorDomainHTTP &&
    (err.error == kCFStreamErrorHTTPAuthenticationBadUserName
    || err.error == kCFStreamErrorHTTPAuthenticationBadPassword))
{
    retryAuthorizationFailure(&authentication);
    return;
} else {
    errorOccurredLoadingImage(err);
}

}
</pre></code>

現(xiàn)在你有一個(gè)有效的身份驗(yàn)證對(duì)象,繼續(xù)圖4-1中的流程胚股。首先,考慮你是否需要證書裙秋。如果你不需要琅拌,則應(yīng)由身份驗(yàn)證對(duì)象到HTTP請(qǐng)求。身份驗(yàn)證對(duì)象應(yīng)用到HTTP請(qǐng)求詳見列表4-4(resumeWithCredentials)摘刑。

未存儲(chǔ)證書(在內(nèi)存中保存證書(Keeping Credentials in Memory )和在永久性倉(cāng)庫(kù)中存儲(chǔ)證書(Keeping Credentials in a Persistent Store)中有解釋)进宝,獲取有效證書的唯一方法是提示用戶。大多數(shù)情況下枷恕,證書需要用戶名和密碼党晋。通過傳遞身份驗(yàn)證對(duì)象到CFHTTPAuthenticationRequiresUserNameAndPassword 函數(shù),你可以看到用戶名和密碼是必須的徐块。如果證書需要用戶名和密碼未玻,提示用戶輸入用戶名和密碼并在證書字典里存儲(chǔ)。對(duì)于一個(gè)NTLM服務(wù)器胡控,證書還需要一個(gè)域扳剿。在你有新的證書后,你可以調(diào)用列表4-4的函數(shù)resumeWithCredentials 昼激,應(yīng)用身份驗(yàn)證對(duì)象到HTTP請(qǐng)求庇绽。整個(gè)過程見列表4-3。

注意:在代碼列表中橙困,前面有省略號(hào)的注釋表明這個(gè)功能超出了本文的范圍瞧掺,但是需要實(shí)現(xiàn)。這不同與正常的注釋描述正在發(fā)生什么功能凡傅。

列表4-3 查找證書(如果需要)并應(yīng)用它們

<pre><code>
// ...continued from Listing 4-2

else {
cancelLoad();

if (credentials) {
    resumeWithCredentials();
}
// are a user name & password needed?
else if (CFHTTPAuthenticationRequiresUserNameAndPassword(authentication))
    {
    CFStringRef realm = NULL;
    CFURLRef url = CFHTTPMessageCopyRequestURL(request);

     // check if you need an account domain so you can display it if necessary
    if (!CFHTTPAuthenticationRequiresAccountDomain(authentication)) {
        realm = CFHTTPAuthenticationCopyRealm(authentication);
    }
    // ...prompt user for user name (user), password (pass)
    // and if necessary domain (domain) to give to the server...

    // Guarantee values
    if (!user) user = CFSTR("");
    if (!pass) pass = CFSTR("");

    CFDictionarySetValue(credentials,    

kCFHTTPAuthenticationUsername, user);

    CFDictionarySetValue(credentials,    

kCFHTTPAuthenticationPassword, pass);

    // Is an account domain needed? (used currently for NTLM only)
    if (CFHTTPAuthenticationRequiresAccountDomain(authentication)) {
        if (!domain) domain = CFSTR("");
        CFDictionarySetValue(credentials,
                           kCFHTTPAuthenticationAccountDomain, domain);
    }
    if (realm) CFRelease(realm);
    CFRelease(url);
}
else {
    resumeWithCredentials();
    }

}
</pre></code>

列表4-4 應(yīng)用身份驗(yàn)證對(duì)象到請(qǐng)求

<pre><code>
void resumeWithCredentials() {

// Apply whatever credentials we've built up to the old request
if (!CFHTTPMessageApplyCredentialDictionary(request, authentication,
                                            credentials, NULL)) {
    errorOccurredLoadingImage();
} else {
    // Now that we've updated our request, retry the load
    loadRequest();
}

}

</pre></code>

在內(nèi)存中存儲(chǔ)證書

如果你打算經(jīng)常與一個(gè)身份驗(yàn)證服務(wù)器進(jìn)行通信辟狈,重用證書可以來(lái)避免多次提示用戶服務(wù)器用戶名和密碼。本章解釋了一次性使用身份驗(yàn)證代碼(例如處理身份驗(yàn)證(Handling Authentication))需要作出的變更夏跷,在內(nèi)存中存儲(chǔ)證書以便重用上陕。

重用證書桩砰,你的代碼中需要更改三個(gè)數(shù)據(jù)結(jié)構(gòu)。

1.創(chuàng)建一個(gè)可變的數(shù)組來(lái)保存所有的身份驗(yàn)證對(duì)象释簿。
<pre><code>CFMutableArrayRef authArray;</pre></code>

代替:
<pre><code>CFHTTPAuthenticationRef authentication;</pre></code>

2.使用字典亚隅,創(chuàng)建身份驗(yàn)證對(duì)象到證書的映射。
<pre><code>CFMutableDictionaryRef credentialsDict;</pre></code>

代替:
<pre><code>CFMutableDictionaryRef credentials;</pre></code>

3.保持這些結(jié)構(gòu)在你原來(lái)修改當(dāng)前身份驗(yàn)證對(duì)象和當(dāng)前證書的地方庶溶。
<pre><code>CFDictionaryRemoveValue(credentialsDict, authentication);</pre></code>

代替:
<pre><code>CFRelease(credentials);</pre></code>

現(xiàn)在煮纵,創(chuàng)建HTTP請(qǐng)求后,在每次加載前偏螺,查找一個(gè)匹配的身份驗(yàn)證對(duì)象行疏。查找適合對(duì)象的一個(gè)簡(jiǎn)單的非優(yōu)化方法見列表4-5.

列表4-5 查找一個(gè)匹配的身份驗(yàn)證對(duì)象

<pre><code>
CFHTTPAuthenticationRef findAuthenticationForRequest {

int i, c = CFArrayGetCount(authArray);
for (i = 0; i < c; i ++) {
    CFHTTPAuthenticationRef auth = (CFHTTPAuthenticationRef)
            CFArrayGetValueAtIndex(authArray, i);
    if (CFHTTPAuthenticationAppliesToRequest(auth, request)) {
        return auth;
    }
}
return NULL;

}
</pre></code>

如果身份驗(yàn)證數(shù)組有一個(gè)匹配的身份驗(yàn)證對(duì)象,然后檢查證書倉(cāng)庫(kù)是否有正確的證書可用套像。這樣做可以防止你需要再次提示用戶輸入用戶名和密碼酿联。調(diào)用CFDictionaryGetValue 函數(shù)可以查找證書,如列表4-6所示夺巩。

列表4-6 搜索證書倉(cāng)庫(kù)
<pre><code>credentials = CFDictionaryGetValue(credentialsDict, authentication);</pre></code>

然后應(yīng)用你的匹配的身份驗(yàn)證對(duì)象和證書到你原始的HTTP請(qǐng)求并重新發(fā)送贞让。

警告:在接收到服務(wù)器驗(yàn)證前,不要應(yīng)用證書到HTTP請(qǐng)求柳譬。在你上次認(rèn)證后喳张,服務(wù)器可能改變,你可能會(huì)有一個(gè)安全風(fēng)險(xiǎn)美澳。

有了這些變更销部,你的應(yīng)用可以在內(nèi)存中存儲(chǔ)身份驗(yàn)證對(duì)象和證書以便未來(lái)使用。

在永久性倉(cāng)庫(kù)中存儲(chǔ)證書

在內(nèi)存中存儲(chǔ)證書可以防止用戶在特定應(yīng)用啟動(dòng)時(shí)重新輸入服務(wù)器用戶名和密碼制跟。然而舅桩,當(dāng)應(yīng)用退出,這些證書被釋放雨膨。為了避免丟失證書江咳,將它們保存到永久性倉(cāng)庫(kù),這樣每個(gè)服務(wù)器證書只需要生成一次哥放。推薦用鑰匙鏈來(lái)存儲(chǔ)證書歼指。即使你有很多個(gè)鑰匙鏈,本文檔中的鑰匙鏈指的是用戶默認(rèn)的鑰匙鏈甥雕。使用鑰匙鏈表明你存儲(chǔ)的身份驗(yàn)證信息可以用于其他試圖訪問同一個(gè)服務(wù)器的應(yīng)用中踩身,反之亦然。

在鑰匙鏈中存儲(chǔ)和檢索證書需要兩個(gè)函數(shù):一個(gè)用于查找證書字典用于身份驗(yàn)證社露,另一個(gè)保存最近請(qǐng)求的證書挟阻。本文中這些函數(shù)聲明如下:
<pre><code>
CFMutableDictionaryRef findCredentialsForAuthentication(

CFHTTPAuthenticationRef auth);

void saveCredentialsForRequest(void);
</pre></code>

findCredentialsForAuthentication 函數(shù)首先檢查內(nèi)存中的證書字典本地緩存是否有證書。如何實(shí)現(xiàn)見列表4-6。

如果內(nèi)存中沒有證書的緩存附鸽,然后搜索鑰匙鏈脱拼。使用SecKeychainFindInternetPassword函數(shù)搜索鑰匙鏈。該函數(shù)需要大量的參數(shù)坷备。參數(shù)和一段簡(jiǎn)短的描述HTTP身份驗(yàn)證證書如何使用它們熄浓,如下:

keychainOrArray

NULL 指定用戶默認(rèn)鑰匙鏈列表。

serverNameLength

serverName的長(zhǎng)度省撑,通常是strlen(serverName)``赌蔑。

serverName

從HTTP請(qǐng)求解析到的服務(wù)器名稱

securityDomainLength

安全域的長(zhǎng)度,或0表示沒有域竟秫。在示例代碼中娃惯, realm ? strlen(realm) : 0向賬戶傳遞兩種情形。

securityDomain

利用CFHTTPAuthenticationCopyRealm 函數(shù)獲取身份驗(yàn)證對(duì)象范圍

accountNameLength

accountName的長(zhǎng)度肥败。由于accountNameNULL趾浅,值為0

accountName

當(dāng)讀取鑰匙鏈記錄時(shí)沒有賬戶名,該字段為NULL馒稍。

pathLength

path的長(zhǎng)度皿哨,如果沒有路徑則為0.在示例代碼中,path ? strlen(path) : 0向賬戶傳遞兩種情形筷黔。

path

利用CFURLCopyPath 函數(shù)從身份驗(yàn)證對(duì)象獲取路徑。

port

利用CFURLGetPortNumber函數(shù)獲取端口號(hào)仗颈。

protocol

代表協(xié)議類型的字符串佛舱,例如HTTP或HTTPS。通過CFURLCopyScheme 函數(shù)獲取協(xié)議類型挨决。

authenticationType

利用CFHTTPAuthenticationCopyMethod函數(shù)獲取身份驗(yàn)證類型请祖。

passwordLength

0,因?yàn)樵谧x取鑰匙鏈記錄時(shí)不需要密碼脖祈。

passwordData

NULL肆捕,因?yàn)樵谧x取鑰匙鏈記錄時(shí)不需要密碼。

itemRef

查找到正確的鑰匙鏈記錄盖高,返回鑰匙鏈記錄引用對(duì)象SecKeychainItemRef慎陵。

當(dāng)正確的調(diào)用,代碼如列表4-7所示喻奥。

列表4-7 搜索鑰匙鏈

<pre><code>
didFind =

SecKeychainFindInternetPassword(NULL,
                                strlen(host), host,
                                realm ? strlen(realm) : 0, realm,
                                0, NULL,
                                path ? strlen(path) : 0, path,
                                port,
                                protocolType,
                                authenticationType,
                                0, NULL,
                                &itemRef);

</pre></code>

假設(shè)SecKeychainFindInternetPassword 成功返回席纽,創(chuàng)建一個(gè)包含單獨(dú)鑰匙鏈屬性(SecKeychainAttribute)的鑰匙鏈屬性列表(SecKeychainAttributeList)。鑰匙鏈實(shí)現(xiàn)列表將包含用戶名和密碼撞蚕。為了加載鑰匙鏈屬性列表润梯,調(diào)用SecKeychainItemCopyContent 函數(shù)并將SecKeychainFindInternetPassword返回的鑰匙鏈記錄引用對(duì)象(itemRef)傳遞給它。該函數(shù)將用賬號(hào)的用戶名和密碼void \**填充到鑰匙鏈屬性中。

用戶名和密碼可以用來(lái)創(chuàng)建一組新證書纺铭。列表4-8展示了這個(gè)過程寇钉。

列表4-8 從鑰匙鏈價(jià)值服務(wù)器證書。

<pre><code>
if (didFind == noErr) {

SecKeychainAttribute     attr;
SecKeychainAttributeList attrList;
UInt32                   length;
void                     *outData;

// To set the account name attribute
attr.tag = kSecAccountItemAttr;
attr.length = 0;
attr.data = NULL;

attrList.count = 1;
attrList.attr = &attr;

if (SecKeychainItemCopyContent(itemRef, NULL, &attrList,     

&length, &outData)== noErr) {

    // attr.data is the account (username) and outdata is the password
    CFStringRef username =
        CFStringCreateWithBytes(kCFAllocatorDefault, attr.data,
                                attr.length, kCFStringEncodingUTF8, false);
    CFStringRef password =
        CFStringCreateWithBytes(kCFAllocatorDefault, outData, length,
                                kCFStringEncodingUTF8, false);
    SecKeychainItemFreeContent(&attrList, outData);

    // create credentials dictionary and fill it with the user name & password
    credentials =
        CFDictionaryCreateMutable(NULL, 0,
                                  &kCFTypeDictionaryKeyCallBacks,
                                  &kCFTypeDictionaryValueCallBacks);
    CFDictionarySetValue(credentials, kCFHTTPAuthenticationUsername,
                         username);
    CFDictionarySetValue(credentials, kCFHTTPAuthenticationPassword,
                         password);

    CFRelease(username);
    CFRelease(password);
}
CFRelease(itemRef);

}
</pre></code>

如果你可以先存儲(chǔ)證書到鑰匙鏈中舶赔,從鑰匙鏈中檢索證書才有用扫倡。首先,查看證書是否已經(jīng)存儲(chǔ)在鑰匙鏈中顿痪。調(diào)用SecKeychainFindInternetPassword镊辕,傳遞用戶名到accountName ,傳遞accountName 的長(zhǎng)度到accountNameLength``蚁袭。

如果記錄存在征懈,修改它來(lái)改變密碼。設(shè)置鑰匙鏈屬性的數(shù)據(jù)字段包含用戶名揩悄,主要你可以修改正確的屬性卖哎。然后調(diào)用SecKeychainItemModifyContent 函數(shù)并傳遞鑰匙鏈記錄引用對(duì)象(itemRef),鑰匙鏈屬性列表和新密碼删性。通過修改鑰匙鏈記錄而非重寫亏娜,鑰匙鏈記錄會(huì)正確的更新其他相關(guān)數(shù)據(jù)也將保留。記錄如列表4-9所示蹬挺。

列表4-9 修改鑰匙鏈記錄
<pre><code>
// Set the attribute to the account name

attr.tag = kSecAccountItemAttr;

attr.length = strlen(username);

attr.data = (void*)username;

// Modify the keychain entry

SecKeychainItemModifyContent(itemRef, &attrList, strlen(password),

(void *)password);
</pre></code>

如果記錄不存在维贺,你將需要從頭開始創(chuàng)建它。SecKeychainAddInternetPassword 函數(shù)完成該任務(wù)巴帮。它的參數(shù)與SecKeychainFindInternetPassword相同溯泣,但與調(diào)用SecKeychainFindInternetPassword相比,你提供用戶名和密碼給SecKeychainAddInternetPassword 榕茧。釋放鑰匙鏈記錄引用對(duì)象成功后調(diào)用SecKeychainAddInternetPassword 垃沦,除非你需要在其他地方使用。見列表4-10函數(shù)調(diào)用用押。

列表4-10 存儲(chǔ)一個(gè)新的鑰匙鏈記錄

<pre><code>
SecKeychainAddInternetPassword(NULL,

                           strlen(host), host,
                           realm ? strlen(realm) : 0, realm,
                           strlen(username), username,
                           path ? strlen(path) : 0, path,
                           port,
                           protocolType,
                           authenticationType,
                           strlen(password), password,
                           &itemRef);

</pre></code>

身份驗(yàn)證防火墻

身份驗(yàn)證防火墻與身份驗(yàn)證服務(wù)器非常相似肢簿,處理必須檢查每個(gè)失敗的HTTP請(qǐng)求的代理身份驗(yàn)證和服務(wù)器身份驗(yàn)證。這以為著蜻拨,你需要單獨(dú)存儲(chǔ)(本地和永久)代理服務(wù)器和源服務(wù)器池充。因此,失敗的HTTP響應(yīng)的過程如下:

  • 確定響應(yīng)的狀態(tài)碼是否為407(代理懷疑)缎讼。如果是纵菌,檢查當(dāng)?shù)卮韨}(cāng)庫(kù)和永久性代理倉(cāng)庫(kù)查找一個(gè)匹配的身份驗(yàn)證對(duì)象和證書。如果這些都沒有一個(gè)匹配的對(duì)象和證書休涤,然后請(qǐng)求用戶證書咱圆。應(yīng)用身份驗(yàn)證對(duì)象到HTTP請(qǐng)求并重試笛辟。

  • 確定響應(yīng)的狀態(tài)碼是否為401(服務(wù)器懷疑)。如果是序苏,遵循與407響應(yīng)相同的過程手幢,但是用原始服務(wù)器存儲(chǔ)。

使用代理服務(wù)器有些細(xì)微的差別忱详。首先围来,鑰匙鏈調(diào)用的參數(shù)來(lái)自于代理主機(jī)和端口,而非一個(gè)源服務(wù)器的URL匈睁。第二监透,當(dāng)要求用戶輸入用戶名和密碼,確保清楚的提示是什么密碼航唆。

通過這些指令胀蛮,你的應(yīng)用應(yīng)該可以使用身份驗(yàn)證防火墻。

官方原文地址:

https://developer.apple.com/library/ios/documentation/Networking/Conceptual/CFNetwork/CFHTTPAuthenticationTasks/CFHTTPAuthenticationTasks.html#//apple_ref/doc/uid/TP30001132-CH8-SW1

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末糯钙,一起剝皮案震驚了整個(gè)濱河市粪狼,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌任岸,老刑警劉巖再榄,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異享潜,居然都是意外死亡困鸥,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門剑按,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)疾就,“玉大人,你說我怎么就攤上這事吕座∨耙耄” “怎么了?”我有些...
    開封第一講書人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)篙骡。 經(jīng)常有香客問我驮审,道長(zhǎng),這世上最難降的妖魔是什么窿撬? 我笑而不...
    開封第一講書人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上撇叁,老公的妹妹穿的比我還像新娘。我一直安慰自己畦贸,他們只是感情好陨闹,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開白布楞捂。 她就那樣靜靜地躺著,像睡著了一般趋厉。 火紅的嫁衣襯著肌膚如雪寨闹。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,970評(píng)論 1 284
  • 那天君账,我揣著相機(jī)與錄音繁堡,去河邊找鬼。 笑死乡数,一個(gè)胖子當(dāng)著我的面吹牛椭蹄,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播净赴,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼绳矩,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了劫侧?” 一聲冷哼從身側(cè)響起埋酬,我...
    開封第一講書人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎烧栋,沒想到半個(gè)月后写妥,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡审姓,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年珍特,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片魔吐。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡扎筒,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出酬姆,到底是詐尸還是另有隱情嗜桌,我是刑警寧澤,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布辞色,位于F島的核電站骨宠,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏相满。R本人自食惡果不足惜层亿,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望立美。 院中可真熱鬧匿又,春花似錦、人聲如沸建蹄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至痛单,卻和暖如春击费,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背桦他。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來(lái)泰國(guó)打工蔫巩, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人快压。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓圆仔,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親蔫劣。 傳聞我的和親對(duì)象是個(gè)殘疾皇子坪郭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345

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