Shiro學(xué)習(xí)day-71:Shiro安全框架

一、Shiro框架介紹

1.什么是Shiro坝咐?

Apache Shiro是一個(gè)強(qiáng)大易用的Java安全框架铃剔,提供了認(rèn)證撒桨、授權(quán)、加密和 會(huì)話管理等功能键兜。

  • Shiro應(yīng)用場景:

對(duì)于任何一個(gè)應(yīng)用程序凤类,Shiro都可以提供全面的安全管理服務(wù)。其不僅可 以用在JavaSE環(huán)境普气,也可以用在JavaEE環(huán)境谜疤。

2.Shiro的架構(gòu)圖:

  • 從外部看shiro:


    shiro.png
  • 從Shiro內(nèi)部看Shiro的框架:


    Shiro.png
  • Shiro中常見的英文名詞:

Subject:主體;
Security:安全现诀;
Realm:領(lǐng)域夷磕,范圍;
Authenticator:認(rèn)證器赶盔;
Authentication:認(rèn)證企锌;
Authorizer:授權(quán)器;
Authorization:授權(quán)于未;
Cryptography:密碼;
Credential:證書陡鹃、憑證烘浦;
Matcher:匹配器;
Principal:身份萍鲸。

二闷叉、Shiro環(huán)境搭建

1.Shiro中的配置文件:

shiro.ini文件放在classpath下,shiro會(huì)自動(dòng)查找。其中格式是key/value 鍵值對(duì)配置脊阴。INI配置文件一般適用于用戶少且不需要在運(yùn)行時(shí)動(dòng)態(tài)創(chuàng)建的 情景下使用握侧。 ini文件中主要配置有四大類:main蚯瞧,users,roles品擎,urls埋合。

shiro.ini

(1)[mian]:

main主要配置shiro的一些對(duì)象,例如securityManager 萄传,Realm甚颂, authenticator,authcStrategy 等等秀菱。

image.png

(2)[users]:

[users]允許你配置一組靜態(tài)的用戶振诬,包含用戶名,密碼衍菱,角色赶么,一個(gè)用戶 可以有多個(gè)角色,可以配置多個(gè)角色脊串。

image.png

(3)[roles]:

[roles]將角色和權(quán)限關(guān)聯(lián)起來辫呻,格式為:角色名=權(quán)限字符串1,權(quán)限字符 串2…..洪规。

image.png

(4)印屁、[roles]

[roles]將角色和權(quán)限關(guān)聯(lián)起來,格式為:角色名=權(quán)限字符串1斩例,權(quán)限字符 串2…..雄人。

image.png

2.Shiro環(huán)境搭建實(shí)現(xiàn)簡單的認(rèn)證:

認(rèn)證:驗(yàn)證用戶是否合法 在 shiro 中,用戶需要提供principals (身份)和credentials(憑證) 給shiro念赶,從而實(shí)現(xiàn)對(duì)用戶身份的驗(yàn)證础钠。

  • principals:

身份,即主體的標(biāo)識(shí)屬性叉谜,可以是任何東西旗吁,如用戶名、郵箱等停局,唯一即可很钓。 例如:用戶名/郵箱/手機(jī)號(hào)等。

  • .credentials

憑證董栽,即只有主體知道的安全值码倦,如密碼/數(shù)字證書等。 最常見的principals和credentials組合就是用戶名/密碼锭碳。

  • 實(shí)現(xiàn)簡單的認(rèn)證:
    (1)導(dǎo)入jar包:


    jar

(2)shiro.ini:

[users]
root = 1234

(3)測試:

package com.zlw.test;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.junit.Test;

//實(shí)現(xiàn)簡單認(rèn)證
public class AuthenticationTest {

    @Test
    public void testAuthentication() {
        //1.構(gòu)建SecurityManager工廠
        IniSecurityManagerFactory securityManagerFactory = new IniSecurityManagerFactory("classpath:shiro.ini");
        //2.通過securityManagerFactory工廠獲取SecurityManager實(shí)例
        SecurityManager securityManager = securityManagerFactory.getInstance();
        //3.將securityManager設(shè)置到運(yùn)行環(huán)境中
        SecurityUtils.setSecurityManager(securityManager);
        //4.獲取subject實(shí)例
        Subject subject = SecurityUtils.getSubject();
        //5.創(chuàng)建用戶名和密碼驗(yàn)證令牌Token
        UsernamePasswordToken token = new UsernamePasswordToken("root","1234");
        //6.進(jìn)行身份驗(yàn)證
        subject.login(token);
        //7.判斷是否驗(yàn)證通過
        System.out.println("驗(yàn)證是否通過:"+subject.isAuthenticated());
    }
}
結(jié)果

3.Shiro內(nèi)置的JDBCRealm:

Shiro默認(rèn)使用自帶的IniRealm袁稽,IniRealm從ini配置文件中讀取用戶的信息。 大部分情況下需要從系統(tǒng)的數(shù)據(jù)庫中讀取用戶信息擒抛,所以需要使用JDBCRealm或自定義Realm推汽;:使用JDBCRealm提供數(shù)據(jù)源补疑,從而實(shí)現(xiàn)認(rèn)證 。
在JDBCRealm中限定了表中的表名和字段歹撒。

(1)創(chuàng)建users表莲组,(字段為username,password):


users

(2)導(dǎo)入jar包:


jar

(3)配置shiro.ini:
[main]
#配置Realm
jdbcRealm = org.apache.shiro.realm.jdbc.JdbcRealm

#配置數(shù)據(jù)源
dataSource = com.mchange.v2.c3p0.ComboPooledDataSource
dataSource.driverClass = com.mysql.jdbc.Driver
dataSource.jdbcUrl = jdbc:mysql:///shiro
dataSource.user = root
dataSource.password = root

jdbcRealm.dataSource = $dataSource

#將Realm注入給SecurityManager
securityManager.realm = $jdbcRealm

(4)測試:

package com.zlw.test;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.junit.Test;

public class AuthenticationTest {
    
    @Test
    public void testAuthentication() {
        //1.構(gòu)建SecurityManager工廠
        IniSecurityManagerFactory securityManagerFactory = new IniSecurityManagerFactory("classpath:shiro.ini");
        //2.通過securityManagerFactory工廠獲取SecurityManager實(shí)例
        SecurityManager securityManager = securityManagerFactory.getInstance();
        //3.將SecurityManager設(shè)置到運(yùn)行環(huán)境中
        SecurityUtils.setSecurityManager(securityManager);
        //4.獲取歐subject實(shí)例
        Subject subject = SecurityUtils.getSubject();
        //5.創(chuàng)建用戶名密碼驗(yàn)證令牌Token
        UsernamePasswordToken token = new UsernamePasswordToken("victor", "123456");
        //6.進(jìn)行身份驗(yàn)證
        subject.login(token);
        //7.判斷是否認(rèn)證通過
        System.out.println(subject.isAuthenticated());
    }
}
結(jié)果

4.自定義Realm提供數(shù)據(jù)源:

自定義Realm栈妆,可以注入給securityManager更加靈活的安全數(shù)據(jù)源通過實(shí)現(xiàn)Realm接口胁编,或根據(jù)需求繼承他的相應(yīng)子類即可。使用自定義Realm提供數(shù)據(jù)源鳞尔,從而實(shí)現(xiàn)認(rèn)證 嬉橙。

(1)創(chuàng)建數(shù)據(jù)庫表(自定義表名,字段名):

CREATE TABLE `user` (
  `userid` int(5) NOT NULL AUTO_INCREMENT,
  `username` varchar(30) DEFAULT NULL,
  `pwd` varchar(30) DEFAULT NULL,
  PRIMARY KEY (`userid`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

(2)導(dǎo)入jar包:


jar

(3)自定義Realm繼承AuthenticatingRealm類:

package com.zlw.realm;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.realm.AuthenticatingRealm;

public class CustomRealm extends AuthenticatingRealm{

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        PreparedStatement pstm = null;
        Connection conn = null;
        ResultSet rs = null;
        String username = token.getPrincipal().toString();

        String principal = null;
        String credentials = null;
         SimpleAuthenticationInfo simpleAuthenticationInfo = null;
        
        try {
            //加載驅(qū)動(dòng)
            Class.forName("com.mysql.jdbc.Driver");
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/shiro", "root", "root");
           //創(chuàng)建對(duì)象
            pstm = conn.prepareStatement("select *from user where username=?");
            pstm.setString(1,username);
            //執(zhí)行sql
            rs = pstm.executeQuery();
            while(rs.next()) {
                principal = rs.getString("username");
                credentials = rs.getString("pwd");
            }
            
            simpleAuthenticationInfo = new SimpleAuthenticationInfo(principal, credentials,"customRealm");
            
        } catch (SQLException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }finally {
            try {
                rs.close();
                pstm.close();
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return simpleAuthenticationInfo;
    }
}

(4)測試:

package com.zlw.test;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.junit.Test;

public class Test01 {

    @Test
    public void testAuthentication() {
        // 1.構(gòu)建SecurityManager工廠
        IniSecurityManagerFactory securityManagerFactory = new IniSecurityManagerFactory();
        // 2.通過securityManagerFactory工廠獲取SecurityManager實(shí)例
        SecurityManager securityManager = securityManagerFactory.getInstance();
        // 3.將SecurityManager設(shè)置到運(yùn)行環(huán)境中
        SecurityUtils.setSecurityManager(securityManager);
        // 4.獲取歐subject實(shí)例
        Subject subject = SecurityUtils.getSubject();
        // 5.創(chuàng)建用戶名密碼驗(yàn)證令牌Token
        UsernamePasswordToken token = new UsernamePasswordToken("admin", "1234");
        // 6.進(jìn)行身份驗(yàn)證
        subject.login(token);
        // 7.判斷是否認(rèn)證通過
        System.out.println(subject.isAuthenticated());
    }
}
結(jié)果

三寥假、MD5加密

1.常見 的加密算法:

  • 對(duì)稱加密算法(加密與解密密鑰相同):


    示例
  • 非對(duì)稱加密算法(加密密鑰和解密密鑰不同):


    示例
  • 對(duì)稱與非對(duì)稱算法比較:


    示例
  • 散列算法比較:


    示例

2.使用DM5加密:

  • 加鹽:

使用MD5存在一個(gè)問題市框,相同的password生產(chǎn)的Hash值是相同的,如 果兩個(gè)用戶設(shè)置了相同的密碼糕韧,那么數(shù)據(jù)庫當(dāng)就會(huì)存儲(chǔ)相同的值枫振,這樣是極 不安全的。
加Salt可以一定程度上解決這一問題萤彩。所謂加Salt方法粪滤,就是加點(diǎn) “佐料”。其基本想法是這樣的:當(dāng)用戶首次提供密碼時(shí)(通常是注冊時(shí))雀扶, 由系統(tǒng)自動(dòng)往這個(gè)密碼里撒一些“佐料”杖小,然后再散列。而當(dāng)用戶登錄時(shí)愚墓, 系統(tǒng)為用戶提供的代碼撒上同樣的“佐料”予权,然后散列,再比較散列值浪册,來 確定密碼是否正確扫腺。
原理 :給原文加入隨機(jī)數(shù)生成新的MD5值。

  • 迭代:

對(duì)加密的動(dòng)作進(jìn)行重復(fù)反饋過程的活動(dòng)村象;加密的次數(shù)笆环。

  • 代碼示例:
package com.zlw.test;

import org.apache.shiro.crypto.hash.Md5Hash;
import org.junit.Test;

//MD5加密、加鹽以及迭代
public class MD5Test {

    @Test
    public void testMD5() {
        //md5加密
        Md5Hash md5 = new Md5Hash("1234556");
        System.out.println(md5);
    }
    
    @Test
    public void testMD5Hash() {
        //加鹽
        Md5Hash md5 = new Md5Hash("123456","aaa");
        System.out.println(md5);
    }
    
    @Test
    public void testMD5Hash2() {
        //迭代
        Md5Hash md5 = new Md5Hash("123456","sxt",3);
        System.out.println(md5);
    }
}
MD5加密

加鹽

迭代

3.憑證匹配器和Shiro的授權(quán):

  • 憑證匹配器:

在Realm接口的實(shí)現(xiàn)類AuthenticatingRealm中有credentialsMatcher屬性厚者。 意為憑證匹配器咧织。常用來設(shè)置加密算法及迭代次數(shù)等。

  • Shiro授權(quán):

授權(quán):又稱作為訪問控制籍救,是對(duì)資源的訪問管理的過程。即對(duì)于 認(rèn)證通過的用戶渠抹,授予他可以訪問某些資源的權(quán)限蝙昙。
Shiro 支持三種方式的授權(quán):代碼觸發(fā)闪萄、注解觸發(fā)、標(biāo)簽觸發(fā) 奇颠。

授權(quán)示例

4.使用MD5加密和Shiro授權(quán)實(shí)現(xiàn)菜單授權(quán):

(1)創(chuàng)建數(shù)據(jù)庫:

  • users表:


    示例
  • roles角色表(角色和user是一對(duì)多關(guān)系):


    示例
  • Menus菜單表(菜單和角色是多對(duì)多關(guān)系):


    示例
  • 角色和菜單的中間表:


    示例

    (2)導(dǎo)入jar包:


    jar

    (3)自定義Realm繼承AuthorizingRealm類败去;重寫doGetAuthenticationInfo(AuthenticationToken token):認(rèn)證的方法;doGetAuthorizationInfo(PrincipalCollection collection):授權(quán)方法烈拒;
package com.zlw.realm;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.Set;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;

/**
 * AuthenticatingRealm:認(rèn)證使用的Realm,只包含認(rèn)證的方法圆裕,認(rèn)證時(shí)調(diào)用doGetAuthenticationInfo方法
 * AuthorizingRealm:授權(quán)使用的Realm,繼承了AuthenticatingRealm, 包含認(rèn)證和授權(quán)的方法,
 *       認(rèn)證時(shí)調(diào)用doGetAuthenticationInfo方法,授權(quán)時(shí)調(diào)用doGetAuthorizationInfo方法
 * 
 * 自定義Realm的實(shí)現(xiàn)步驟: 我們通過自定義Realm從指定的數(shù)據(jù)源中獲取數(shù)據(jù) 
 * 1.自定義Realm,繼承AuthorizingRealm類
 * 2.重寫認(rèn)證和授權(quán)的方法 doGetAuthenticationInfo(AuthenticationToken token):認(rèn)證的方法
 * doGetAuthorizationInfo(PrincipalCollection arg0):授權(quán)方法
 * 3.在配置文件(shiro.ini)中配置自定義的realm customRealm = com.sxt.realm.CustomRealm
 * securityManager.realm = $customRealm
 * 
 * @author zhang
 *
 */
public class CustomRealm extends AuthorizingRealm {

    // 授權(quán)方法
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) {
        Connection conn = null;
        PreparedStatement pstm = null;
        ResultSet rs = null;
        String username = token.getPrincipal().toString();//從令牌中獲取身份信息
        String principal = null;
        String credentials = null;
        String password_salt = null;
        SimpleAuthenticationInfo simpleAuthenticationInfo = null;

        try {
            // 加載驅(qū)動(dòng)
            Class.forName("com.mysql.jdbc.Driver");
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/rbac", "root", "root");
            pstm = conn.prepareStatement("select *from users where username=?");
            pstm.setString(1, username);

            rs = pstm.executeQuery();
            while (rs.next()) {
                principal = rs.getString("username");
                credentials = rs.getString("userpwd");
                password_salt = rs.getString("salt");//獲取鹽值
            }
            simpleAuthenticationInfo = new SimpleAuthenticationInfo(principal, credentials,ByteSource.Util.bytes(password_salt), "customRealm");

        } catch (SQLException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            try {
                rs.close();
                pstm.close();
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return simpleAuthenticationInfo;
    }

    // 響應(yīng)方法
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection collection) throws AuthenticationException {
        Connection conn = null;
        PreparedStatement pstm = null;
        ResultSet rs = null;
        String userName = collection.getPrimaryPrincipal().toString();//獲取主體身份信息
        Set<String> roleNameSet = new HashSet<String>();//創(chuàng)建Set集合擁有封裝所有的菜單名稱
        Set<String> menuNameSet = new HashSet<String>();//創(chuàng)建Set集合擁有封裝所有的菜單名稱
        
        try {
            //加載驅(qū)動(dòng)
            Class.forName("com.mysql.jdbc.Driver");
            //獲取鏈接
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/rbac", "root", "root");
            String sql = "select r.roleName,m.menuName "
                    + "from users u, roles r, roles_menus rm,menus m "
                    + "where u.role_id=r.roleid "
                    + "and r.roleid=rm.roles_id "
                    + "and rm.menus_id=m.menuid "
                    + "and u.username=?";
            pstm = conn.prepareStatement(sql);
            pstm.setString(1, userName);
            rs = pstm.executeQuery();
            while (rs.next()) {
                String roleName = rs.getString("roleName");
                String menuName = rs.getString("menuName");
                roleNameSet.add(roleName);
                menuNameSet.add(menuName);
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            try {
                rs.close();
                pstm.close();
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            
        }
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        simpleAuthorizationInfo.addRoles(roleNameSet);
        simpleAuthorizationInfo.addStringPermissions(menuNameSet);
        return simpleAuthorizationInfo;
    }
}

(4)配置Shiro.ini文件:

[main]
#配置憑證配置器
credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher
#設(shè)置憑證配置器的算法名稱
credentialsMatcher.hashAlgorithmName=MD5 
#設(shè)置憑證匹配器的的迭代次數(shù)
credentialsMatcher.hashIterations=3

#配置Realm
customRealm =com.zlw.realm.CustomRealm
#設(shè)置Realm的憑證匹配器
customRealm.credentialsMatcher=$credentialsMatcher
#將Realm注入給SecurityManager
securityManager.realm = $customRealm

(5)測試:

package com.zlw.test;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.junit.Test;

public class MD5Test {
    
    @Test
    public void TestMD5() {
        //1.構(gòu)建SecurityManager工廠
        IniSecurityManagerFactory securityManagerFactory = new IniSecurityManagerFactory("classpath:shiro.ini");
        //2.通過securityManagerFactory工廠獲取SecurityManager實(shí)例
        SecurityManager securityManager = securityManagerFactory.getInstance();
        //3.將securityManager設(shè)置到運(yùn)行環(huán)境中
        SecurityUtils.setSecurityManager(securityManager);
        //4.獲取subject實(shí)例
        Subject subject = SecurityUtils.getSubject();
        //5.創(chuàng)建用戶名和密碼驗(yàn)證令牌Token
        UsernamePasswordToken token = new UsernamePasswordToken("zhangsan","123456");
        //6.進(jìn)行身份驗(yàn)證
        subject.login(token);
        //7.判斷是否驗(yàn)證通過
        System.out.println("驗(yàn)證是否通過"+subject.isAuthenticated());
        //判斷該用戶是否擁有指定的角色
        System.out.println("判斷是否擁有指定角色:"+subject.hasRole("管理員"));
        //8.判斷該用戶是否擁有指定的權(quán)限
        System.out.println("是否擁有指定權(quán)限:"+subject.isPermitted("客戶管理"));
            
    }   
}
zhangsan

admin

5.可能會(huì)遇到的異常信息:

(1)UnknownAccountException:No account found for user
用戶主體找不到荆几,用戶名錯(cuò)誤吓妆。
(2)IncorrectCredentialsException:did not match the expected credentials
用戶認(rèn)證沒有找到相匹配的憑證;用戶密碼錯(cuò)誤吨铸。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末行拢,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子诞吱,更是在濱河造成了極大的恐慌舟奠,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,607評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件房维,死亡現(xiàn)場離奇詭異沼瘫,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)咙俩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門耿戚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人暴浦,你說我怎么就攤上這事溅话。” “怎么了歌焦?”我有些...
    開封第一講書人閱讀 164,960評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵飞几,是天一觀的道長。 經(jīng)常有香客問我独撇,道長屑墨,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,750評(píng)論 1 294
  • 正文 為了忘掉前任纷铣,我火速辦了婚禮卵史,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘搜立。我一直安慰自己以躯,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,764評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著忧设,像睡著了一般刁标。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上址晕,一...
    開封第一講書人閱讀 51,604評(píng)論 1 305
  • 那天膀懈,我揣著相機(jī)與錄音,去河邊找鬼谨垃。 笑死启搂,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的刘陶。 我是一名探鬼主播胳赌,決...
    沈念sama閱讀 40,347評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼易核!你這毒婦竟也來了匈织?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,253評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤牡直,失蹤者是張志新(化名)和其女友劉穎缀匕,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體碰逸,經(jīng)...
    沈念sama閱讀 45,702評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡乡小,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,893評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了饵史。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片满钟。...
    茶點(diǎn)故事閱讀 40,015評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖胳喷,靈堂內(nèi)的尸體忽然破棺而出湃番,到底是詐尸還是另有隱情,我是刑警寧澤吭露,帶...
    沈念sama閱讀 35,734評(píng)論 5 346
  • 正文 年R本政府宣布吠撮,位于F島的核電站,受9級(jí)特大地震影響讲竿,放射性物質(zhì)發(fā)生泄漏泥兰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,352評(píng)論 3 330
  • 文/蒙蒙 一题禀、第九天 我趴在偏房一處隱蔽的房頂上張望鞋诗。 院中可真熱鬧,春花似錦迈嘹、人聲如沸削彬。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽吃警。三九已至糕篇,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間酌心,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評(píng)論 1 270
  • 我被黑心中介騙來泰國打工挑豌, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留安券,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,216評(píng)論 3 371
  • 正文 我出身青樓氓英,卻偏偏與公主長得像侯勉,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子铝阐,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,969評(píng)論 2 355

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