《跟我學(xué)Shiro》學(xué)習(xí)筆記 第二章:身份驗(yàn)證

前言

上一章主要對(duì)Shiro功能,運(yùn)行原理,架構(gòu)設(shè)計(jì)進(jìn)行了介紹缓熟,這一章我們主要學(xué)習(xí)Shiro的身份驗(yàn)證。本章的代碼我會(huì)上傳至GitHub摔笤,鏈接見文末够滑。

身份驗(yàn)證:即在應(yīng)用中誰能證明他就是他本人。一般提供如他們的身份ID一些標(biāo)識(shí)信息來表明他就是他本人吕世,如提供身份證彰触,用戶名/密碼來證明。

在shiro中命辖,用戶需要提供principals (身份)和credentials(證明)給shiro况毅,從而應(yīng)用能驗(yàn)證用戶身份:

principals:身份,即主體的標(biāo)識(shí)屬性尔艇,可以是任何東西俭茧,如用戶名、郵箱等漓帚,唯一即可母债。一個(gè)主體可以有多個(gè)principals,但只有一個(gè)Primary principals尝抖,一般是用戶名/密碼/手機(jī)號(hào)毡们。

credentials:證明/憑證,即只有主體知道的安全值昧辽,如密碼/數(shù)字證書等衙熔。

最常見的principals和credentials組合就是用戶名/密碼了。接下來先進(jìn)行一個(gè)基本的身份認(rèn)證搅荞。

2.1環(huán)境準(zhǔn)備

引入相關(guān)依賴

<dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.9</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.10</version>
        </dependency>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.0.13</version>
        </dependency>

        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.1.3</version>
        </dependency>
    
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>1.2.2</version>
        </dependency>
    </dependencies>

2.2登錄/登出

  1. 首先準(zhǔn)備一些 用戶身份/憑據(jù)(shiro.ini)

    [users]  
    zhang=123  
    wang=123  
    

    這里使用ini配置文件红氯,[users]指定了兩個(gè)主體:zhang/123框咙、wang/123。

  2. 測(cè)試用例(com.zhaojun.shiro.chapter2.LoginLogoutTest)

     @Test
        public void testHelloWorld() {
            //1. 獲取SecurityManagerFactory痢甘,此處使用ini配置文件初始化SecurityManager
            Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
            /*
             2. 得到SecurityManager實(shí)例喇嘱,并綁定到SecurityUtils上
             接著獲取SecurityManager并綁定到SecurityUtils,這是一個(gè)全局設(shè)置塞栅,設(shè)置一次即可
             SecurityManager是在org.apache.shiro.mgt包下
             */
            SecurityManager securityManager = factory.getInstance();
            SecurityUtils.setSecurityManager(securityManager);
            /*
               3. 得到Subject及創(chuàng)建用戶名/密碼身份驗(yàn)證Token(即用戶身份/憑證)
               通過SecurityUtils得到Subject者铜,其會(huì)自動(dòng)綁定到當(dāng)前線程;
               如果在web環(huán)境在請(qǐng)求結(jié)束時(shí)需要解除綁定放椰;然后獲取身份驗(yàn)證的Token作烟,如用戶名/密碼
             */
            Subject subject = SecurityUtils.getSubject();
            UsernamePasswordToken token = new UsernamePasswordToken("wang", "123");
    
            try {
                /*
                   4. 登錄,即驗(yàn)證身份
                   調(diào)用subject.login方法進(jìn)行登錄砾医,其會(huì)自動(dòng)委托給SecurityManager.login方法進(jìn)行登錄
                 */
                subject.login(token);
                log.info("用戶登錄成功");
            } catch (AuthenticationException e) {
                /*
                如果身份驗(yàn)證失敗請(qǐng)捕獲AuthenticationException或其子類拿撩,常見的如: DisabledAccountException(禁用的帳號(hào))、
                LockedAccountException(鎖定的帳號(hào))如蚜、UnknownAccountException(錯(cuò)誤的帳號(hào))压恒、
                ExcessiveAttemptsException(登錄失敗次數(shù)過多)、IncorrectCredentialsException (錯(cuò)誤的憑證)怖亭、
                ExpiredCredentialsException(過期的憑證)等,具體請(qǐng)查看其繼承關(guān)系坤检;對(duì)于頁面的錯(cuò)誤消息展示兴猩,
                最好使用如“用戶名/密碼錯(cuò)誤”而不是“用戶名錯(cuò)誤”/“密碼錯(cuò)誤”,防止一些惡意用戶非法掃描帳號(hào)庫
                 */
                log.error("身份驗(yàn)證失敗:{}", e.getLocalizedMessage());
            }
    
            Assert.assertEquals(true, subject.isAuthenticated());
    
            //6. 退出
            subject.logout();
        }
    

    從以上代碼可以總結(jié)出身份驗(yàn)證的步驟:

    1. 收集用戶身份/憑證早歇,即如用戶名/密碼倾芝;
    2. 調(diào)用Subject.login進(jìn)行登錄,如果失敗將得到相應(yīng)的AuthenticationException異常箭跳,根據(jù)異常提示用戶錯(cuò)誤信息晨另;否則登錄成功;
    3. 最后調(diào)用Subject.logout進(jìn)行退出操作谱姓。

    如上測(cè)試的幾個(gè)問題:

    1. 用戶名/密碼硬編碼在ini配置文件借尿,以后需要改成如數(shù)據(jù)庫存儲(chǔ),且密碼需要加密存儲(chǔ)屉来;
    2. 用戶身份Token可能不僅僅是用戶名/密碼路翻,也可能還有其他的,如登錄時(shí)允許用戶名/郵箱/手機(jī)號(hào)同時(shí)登錄茄靠。

    2.3身份認(rèn)證流程

身份認(rèn)證流程圖

流程如下:

  1. 首先調(diào)用Subject.login(token)進(jìn)行登錄茂契,其會(huì)自動(dòng)委托給Security Manager,調(diào)用之前必須通過SecurityUtils. setSecurityManager()設(shè)置慨绳;
  2. SecurityManager負(fù)責(zé)真正的身份驗(yàn)證邏輯掉冶;它會(huì)委托給Authenticator進(jìn)行身份驗(yàn)證真竖;
  3. Authenticator才是真正的身份驗(yàn)證者,Shiro API中核心的身份認(rèn)證入口點(diǎn)厌小,此處可以自定義插入自己的實(shí)現(xiàn)恢共;
  4. Authenticator可能會(huì)委托給相應(yīng)的AuthenticationStrategy進(jìn)行多Realm身份驗(yàn)證,默認(rèn)ModularRealmAuthenticator會(huì)調(diào)用AuthenticationStrategy進(jìn)行多Realm身份驗(yàn)證召锈;
  5. Authenticator會(huì)把相應(yīng)的token傳入Realm旁振,從Realm獲取身份驗(yàn)證信息,如果沒有返回/拋出異常表示身份驗(yàn)證失敗了涨岁。此處可以配置多個(gè)Realm拐袜,將按照相應(yīng)的順序及策略進(jìn)行訪問。

2.4Realm

Realm:域梢薪,Shiro從從Realm獲取安全數(shù)據(jù)(如用戶蹬铺、角色、權(quán)限)秉撇,就是說SecurityManager要驗(yàn)證用戶身份甜攀,那么它需要從Realm獲取相應(yīng)的用戶進(jìn)行比較以確定用戶身份是否合法;也需要從Realm得到用戶相應(yīng)的角色/權(quán)限進(jìn)行驗(yàn)證用戶是否能進(jìn)行操作琐馆;可以把Realm看成DataSource规阀,即安全數(shù)據(jù)源。如我們之前的ini配置方式將使用org.apache.shiro.realm.text.IniRealm瘦麸。

org.apache.shiro.realm.Realm接口如下:

String getName(); //返回一個(gè)唯一的Realm名字  
boolean supports(AuthenticationToken token); //判斷此Realm是否支持此Token  
AuthenticationInfo getAuthenticationInfo(AuthenticationToken token)  
 throws AuthenticationException;  //根據(jù)Token獲取認(rèn)證信息  

2.4.1單Realm配置

  1. 自定義Realm實(shí)現(xiàn):

    @Slf4j
    public class MyRealm1 implements Realm {
        public String getName() {
            return "myRealm1";
        }
    
        public boolean supports(AuthenticationToken authenticationToken) {
            //僅支持UsernamePasswordToken類型的token
            return authenticationToken instanceof UsernamePasswordToken;
        }
    
        public AuthenticationInfo getAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
            String username = (String) authenticationToken.getPrincipal();
    
            String password = new String((char[])authenticationToken.getCredentials());
    
            log.info("username:{},password:{}",username,password);
    
            if(!"zhang".equals(username)){
                log.info("用戶名錯(cuò)誤");
                throw new UnknownAccountException();
            }
    
            if(!"123".equals(password)){
                log.info("密碼錯(cuò)誤");
                throw new IncorrectCredentialsException();
            }
            //若身份認(rèn)證成功谁撼,返回一個(gè)AuthenticationInfo實(shí)現(xiàn)
            return new SimpleAuthenticationInfo(username,password,getName());
        }
    }
    
  2. ini配置文件指定自定義Realm實(shí)現(xiàn)(shiro-realm.ini)

    #申明一個(gè)realm
    myRealm1= com.zhaojun.shiro.chapter2.realm.MyRealm1
    #指定securityManager的realms實(shí)現(xiàn)
    securityManager.realms=$myRealm1
    

    通過$name來引入之前的realm定義

  3. 測(cè)試用例請(qǐng)參考com.zhaojun.shiro.chapter2.LoginLogoutTest的testCustomRealm測(cè)試方法,只需要把之前的shiro.ini配置文件改成shiro-realm.ini即可滋饲。

2.4.2多Realm配置

  1. ini配置文件(shiro-multi-realm.ini)

    #申明多個(gè)realm
    myRealm1= com.zhaojun.shiro.chapter2.realm.MyRealm1
    myRealm2= com.zhaojun.shiro.chapter2.realm.MyRealm2
    #指定securityManager的realms實(shí)現(xiàn)
    securityManager.realms=$myRealm1,$myRealm2
    

    securityManager會(huì)按照realms指定的順序進(jìn)行身份認(rèn)證厉碟。此處我們使用顯示指定順序的方式指定了Realm的順序,如果刪除“securityManager.realms=$myRealm1$myRealm2”屠缭,那么securityManager會(huì)按照realm聲明的順序進(jìn)行使用(即無需設(shè)置realms屬性箍鼓,其會(huì)自動(dòng)發(fā)現(xiàn)),當(dāng)我們顯示指定realm后呵曹,其他沒有指定realm將被忽略款咖,如“securityManager.realms=$myRealm1”,那么myRealm2不會(huì)被自動(dòng)設(shè)置進(jìn)去奄喂。

  2. 測(cè)試用例請(qǐng)參考com.zhaojun.shiro.chapter2.LoginLogoutTest的testCustomMultiRealm測(cè)試方法之剧,只需要把之前的shiro.ini配置文件改成shiro-multi-realm.ini即可。

2.4.3Shiro默認(rèn)提供的Realm

Realm繼承關(guān)系

以后一般繼承AuthorizingRealm(授權(quán))即可砍聊;其繼承了AuthenticatingRealm(即身份驗(yàn)證)背稼,而且也間接繼承了CachingRealm(帶有緩存實(shí)現(xiàn))。其中主要默認(rèn)實(shí)現(xiàn)如下:

org.apache.shiro.realm.text.IniRealm:[users]部分指定用戶名/密碼及其角色玻蝌;[roles]部分指定角色即權(quán)限信息蟹肘;

org.apache.shiro.realm.text.PropertiesRealm: user.username=password,role1,role2指定用戶名/密碼及其角色词疼;role.role1=permission1,permission2指定角色及權(quán)限信息;

org.apache.shiro.realm.jdbc.JdbcRealm:通過sql查詢相應(yīng)的信息帘腹,如“select password from users where username = ?”獲取用戶密碼贰盗,“select password, password_salt from users where username = ?”獲取用戶密碼及鹽;“select role_name from user_roles where username = ?”獲取用戶角色阳欲;“select permission from roles_permissions where role_name = ?”獲取角色對(duì)應(yīng)的權(quán)限信息舵盈;也可以調(diào)用相應(yīng)的api進(jìn)行自定義sql;

2.4.4JdbcRealm使用

  1. 引入數(shù)據(jù)庫相關(guān)依賴

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.25</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>0.2.23</version>
    </dependency>
    
  2. 新建數(shù)據(jù)庫shiro球化,并新建三張表秽晚,users(用戶名/密碼)、user_roles(用戶/角色)筒愚、roles_permissions(角色/權(quán)限)赴蝇。具體請(qǐng)參照/shiro-example-chapter2/src/main/sql/shiro.sql。并添加一條用戶記錄:zhang/123巢掺。

  3. ini配置(shiro-jdbc-realm.ini)

    jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm
    dataSource=com.alibaba.druid.pool.DruidDataSource
    dataSource.driverClassName=com.mysql.jdbc.Driver
    dataSource.url=jdbc:mysql://localhost:3306/shiro
    dataSource.username=root
    dataSource.password=123
    jdbcRealm.dataSource=$dataSource
    securityManager.realms=$jdbcRealm
    
  4. 測(cè)試用例參照com.zhaojun.shiro.chapter2.LoginLogoutTest的testJDBCRealm方法句伶。與之前的方法基本一致,只是替換引用的配置文件即可陆淀。

    JdbcRealm會(huì)自己進(jìn)行數(shù)據(jù)庫查詢考余,JdbcRealm.java相關(guān)源碼如下:

    //查詢語句
    protected String authenticationQuery = "select password from users where username = ?";
    
    //獲取認(rèn)證信息
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
            UsernamePasswordToken upToken = (UsernamePasswordToken)token;
            String username = upToken.getUsername();
            if (username == null) {
                throw new AccountException("Null usernames are not allowed by this realm.");
            } else {
                Connection conn = null;
                SimpleAuthenticationInfo info = null;
    
                try {
                    String salt;
                    try {
                        conn = this.dataSource.getConnection();
                        String password = null;
                        salt = null;
                        switch(this.saltStyle) {
                        case NO_SALT:
                            password = this.getPasswordForUser(conn, username)[0];
                            break;
                        case CRYPT:
                            throw new ConfigurationException("Not implemented yet");
                        case COLUMN:
                            String[] queryResults = this.getPasswordForUser(conn, username);
                            password = queryResults[0];
                            salt = queryResults[1];
                            break;
                        case EXTERNAL:
                            password = this.getPasswordForUser(conn, username)[0];
                            salt = this.getSaltForUser(username);
                        }
                    //查詢結(jié)果為空,拋出賬戶錯(cuò)誤異常
                        if (password == null) {
                            throw new UnknownAccountException("No account found for user [" + username + "]");
                        }
                   //若查詢結(jié)果不為空轧苫,則創(chuàng)建一個(gè)用戶認(rèn)證信息
                        info = new SimpleAuthenticationInfo(username, password.toCharArray(), this.getName());
                        if (salt != null) {
                            info.setCredentialsSalt(Util.bytes(salt));
                        }
                    } catch (SQLException var12) {
                        salt = "There was a SQL error while authenticating user [" + username + "]";
                        if (log.isErrorEnabled()) {
                            log.error(salt, var12);
                        }
    
                        throw new AuthenticationException(salt, var12);
                    }
                } finally {
                    JdbcUtils.closeConnection(conn);
                }
    
                return info;
            }
        }
    //通過用戶名查詢密碼楚堤,判斷用戶是否存在
    private String[] getPasswordForUser(Connection conn, String username) throws SQLException {
            boolean returningSeparatedSalt = false;
            String[] result;
            switch(this.saltStyle) {
            case NO_SALT:
            case CRYPT:
            case EXTERNAL:
                result = new String[1];
                break;
            case COLUMN:
            default:
                result = new String[2];
                returningSeparatedSalt = true;
            }
    
            PreparedStatement ps = null;
            ResultSet rs = null;
    
            try {
                ps = conn.prepareStatement(this.authenticationQuery);
                ps.setString(1, username);
                //執(zhí)行查詢
                rs = ps.executeQuery();
    
                for(boolean foundResult = false; rs.next(); foundResult = true) {
                    if (foundResult) {
                        throw new AuthenticationException("More than one user row found for user [" + username + "]. Usernames must be unique.");
                    }
    
                    result[0] = rs.getString(1);
                    if (returningSeparatedSalt) {
                        result[1] = rs.getString(2);
                    }
                }
            } finally {
                JdbcUtils.closeResultSet(rs);
                JdbcUtils.closeStatement(ps);
            }
    
            return result;
        }
    

2.5Authenticator及AuthenticationStrategy

Authenticator的職責(zé)是驗(yàn)證用戶帳號(hào),是Shiro API中身份驗(yàn)證核心的入口點(diǎn):

   public AuthenticationInfo authenticate(AuthenticationToken authenticationToken)  
               throws AuthenticationException;   

如果驗(yàn)證成功浸剩,將返回AuthenticationInfo驗(yàn)證信息钾军;此信息中包含了身份及憑證鳄袍;如果驗(yàn)證失敗將拋出相應(yīng)的AuthenticationException實(shí)現(xiàn)绢要。

SecurityManager接口繼承了Authenticator,另外還有一個(gè)ModularRealmAuthenticator實(shí)現(xiàn)拗小,其委托給多個(gè)Realm進(jìn)行驗(yàn)證重罪,驗(yàn)證規(guī)則通過AuthenticationStrategy接口指定,默認(rèn)提供的實(shí)現(xiàn):

FirstSuccessfulStrategy:只要有一個(gè)Realm驗(yàn)證成功即可哀九,只返回第一個(gè)Realm身份驗(yàn)證成功的認(rèn)證信息剿配,其他的忽略;

AtLeastOneSuccessfulStrategy:只要有一個(gè)Realm驗(yàn)證成功即可阅束,和FirstSuccessfulStrategy不同呼胚,返回所有Realm身份驗(yàn)證成功的認(rèn)證信息;

AllSuccessfulStrategy:所有Realm驗(yàn)證成功才算成功息裸,且返回所有Realm身份驗(yàn)證成功的認(rèn)證信息蝇更,如果有一個(gè)失敗就失敗了沪编。

ModularRealmAuthenticator默認(rèn)使用AtLeastOneSuccessfulStrategy策略。

假設(shè)我們有三個(gè)realm:

myRealm1: 用戶名/密碼為zhang/123時(shí)成功年扩,且返回身份/憑據(jù)為zhang/123蚁廓;

myRealm2: 用戶名/密碼為wang/123時(shí)成功,且返回身份/憑據(jù)為wang/123厨幻;

myRealm3: 用戶名/密碼為zhang/123時(shí)成功相嵌,且返回身份/憑據(jù)為zhang@163.com/123,和myRealm1不同的是返回時(shí)的身份變了况脆;

  1. ini配置文件(shiro-authenticator-all-success.ini)

    #指定securityManager的authenticator實(shí)現(xiàn)
    authenticator=org.apache.shiro.authc.pam.ModularRealmAuthenticator
    securityManager.authenticator=$authenticator
    
    #指定securityManager.authenticator的authenticationStrategy
    allSuccessfulStrategy=org.apache.shiro.authc.pam.AllSuccessfulStrategy
    securityManager.authenticator.authenticationStrategy=$allSuccessfulStrategy
    
    #申明多個(gè)realm
    myRealm1= com.zhaojun.shiro.chapter2.realm.MyRealm1
    myRealm2= com.zhaojun.shiro.chapter2.realm.MyRealm2
    myRealm3= com.zhaojun.shiro.chapter2.realm.MyRealm3
    #指定securityManager的realms實(shí)現(xiàn)
    securityManager.realms=$myRealm1,$myRealm2,$myRealm3
    
  2. 測(cè)試代碼(com.zhaojun.shiro.chapter2.AuthenticatorTest)

    private void login(String configFile){
            //獲取SecurityManager工廠饭宾,使用配置文件初始化工廠
            Factory<SecurityManager> factory = new IniSecurityManagerFactory(configFile);
            //得到SecurityManager實(shí)例,并綁定到SecurityUtils
            SecurityManager securityManager = factory.getInstance();
            SecurityUtils.setSecurityManager(securityManager);
    
            //獲取Subject
            Subject subject = SecurityUtils.getSubject();
    
            //創(chuàng)建Token
            UsernamePasswordToken token = new UsernamePasswordToken("zhang","123");
    
            //登錄
            subject.login(token);
        }
    
        @Test
        public void testAllSuccessfulStrategy(){
            login("classpath:shiro-authenticator-all-success.ini");
            Subject subject = SecurityUtils.getSubject();
    
            //得到一個(gè)身份集合
            PrincipalCollection principals = subject.getPrincipals();
            List list = principals.asList();
            for(Object i : list){
                log.info(i.toString());
            }
        }
    

    這時(shí)程序會(huì)拋出UnknownAccountException異常漠另,因?yàn)槲覀冇玫氖茿llSuccessfulStrategy捏雌,需要所有Realm驗(yàn)證成功才算成功。

    1. 新建配置文件(shiro-authenticator-least-one-success.ini)

      #指定securityManager的authenticator實(shí)現(xiàn)
      authenticator=org.apache.shiro.authc.pam.ModularRealmAuthenticator
      securityManager.authenticator=$authenticator
      
      #指定securityManager.authenticator的authenticationStrategy
      atLeastOneSuccessfulStrategy=org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy
      securityManager.authenticator.authenticationStrategy=$atLeastOneSuccessfulStrategy
      
      #申明多個(gè)realm
      myRealm1= com.zhaojun.shiro.chapter2.realm.MyRealm1
      myRealm2= com.zhaojun.shiro.chapter2.realm.MyRealm2
      myRealm3= com.zhaojun.shiro.chapter2.realm.MyRealm3
      #指定securityManager的realms實(shí)現(xiàn)
      securityManager.realms=$myRealm1,$myRealm2,$myRealm3
      
    2. 測(cè)試代碼(com.zhaojun.shiro.chapter2.AuthenticatorTest)

        @Test
          public void testAtLeastOneSuccessfulStrategy(){
              login("classpath:shiro-authenticator-least-one-success.ini");
              Subject subject = SecurityUtils.getSubject();
      
              //得到一個(gè)身份集合
              PrincipalCollection principals = subject.getPrincipals();
              List list = principals.asList();
              for(Object i : list){
                  log.info(i.toString());
              }
          }
      

      可以看到輸出日志,返回了兩個(gè)身份信息

      00:40:32.294 [main] INFO  c.z.shiro.chapter2.AuthenticatorTest - zhang
      00:40:32.294 [main] INFO  c.z.shiro.chapter2.AuthenticatorTest - zhang@163.com
      

    到此笆搓,身份驗(yàn)證就基本搞定了性湿,重點(diǎn)是身份驗(yàn)證的基本流程,以及常用的Realm的用法满败,如何自定義Realm和常用的認(rèn)證策略肤频。


張開濤的博客:http://jinnianshilongnian.iteye.com/category/305053

我的博客:https://zhaojun0193.github.io

本文代碼地址:https://github.com/zhaojun0193/shiro-example

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市算墨,隨后出現(xiàn)的幾起案子宵荒,更是在濱河造成了極大的恐慌,老刑警劉巖净嘀,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件报咳,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡挖藏,警方通過查閱死者的電腦和手機(jī)暑刃,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來膜眠,“玉大人岩臣,你說我怎么就攤上這事∠颍” “怎么了架谎?”我有些...
    開封第一講書人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)辟躏。 經(jīng)常有香客問我谷扣,道長(zhǎng),這世上最難降的妖魔是什么捎琐? 我笑而不...
    開封第一講書人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任会涎,我火速辦了婚禮涯曲,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘在塔。我一直安慰自己幻件,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開白布蛔溃。 她就那樣靜靜地躺著绰沥,像睡著了一般。 火紅的嫁衣襯著肌膚如雪贺待。 梳的紋絲不亂的頭發(fā)上徽曲,一...
    開封第一講書人閱讀 49,144評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音麸塞,去河邊找鬼秃臣。 笑死,一個(gè)胖子當(dāng)著我的面吹牛哪工,可吹牛的內(nèi)容都是我干的奥此。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼雁比,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼稚虎!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起偎捎,我...
    開封第一講書人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤蠢终,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后茴她,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體寻拂,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年丈牢,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了祭钉。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡赡麦,死狀恐怖朴皆,靈堂內(nèi)的尸體忽然破棺而出帕识,到底是詐尸還是另有隱情泛粹,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布肮疗,位于F島的核電站晶姊,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏伪货。R本人自食惡果不足惜们衙,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一钾怔、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蒙挑,春花似錦宗侦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至馋袜,卻和暖如春男旗,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背欣鳖。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工察皇, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人泽台。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓什荣,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親怀酷。 傳聞我的和親對(duì)象是個(gè)殘疾皇子溃睹,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

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

  • 身份驗(yàn)證,即在應(yīng)用中誰能證明他就是他本人胰坟。一般提供如他們的身份ID一些標(biāo)識(shí)信息來表明他就是他本人因篇,如提供身份證,用...
    小孩真笨閱讀 527評(píng)論 0 0
  • 文章轉(zhuǎn)載自:http://blog.csdn.net/w1196726224/article/details/53...
    wangzaiplus閱讀 3,388評(píng)論 0 3
  • 構(gòu)建一個(gè)互聯(lián)網(wǎng)應(yīng)用笔横,權(quán)限校驗(yàn)管理是很重要的安全措施竞滓,這其中主要包含: 認(rèn)證 - 用戶身份識(shí)別,即登錄 授權(quán) - 訪...
    zhuke閱讀 3,491評(píng)論 0 30
  • 說明:本文很多觀點(diǎn)和內(nèi)容來自互聯(lián)網(wǎng)以及各種資料吹缔,如果侵犯了您的權(quán)益商佑,請(qǐng)及時(shí)聯(lián)系我,我會(huì)刪除相關(guān)內(nèi)容厢塘。 權(quán)限管理 基...
    寇寇寇先森閱讀 7,578評(píng)論 8 76
  • 妗子昨天晚上12點(diǎn)10分走了茶没,帶著渾身的病痛和晚年的凄涼,這似乎是一個(gè)相對(duì)美好的結(jié)局晚碾。至少她不用成天疼痛地嗷嗷叫了...
    綠蘿花123閱讀 706評(píng)論 3 3