Spring-Security-教程(二)--基于數(shù)據(jù)庫(kù)信息進(jìn)行驗(yàn)證

介紹

本篇文章將講解使用Spring Security + Mybatis + Mysql數(shù)據(jù)庫(kù)實(shí)現(xiàn)簡(jiǎn)單的登錄校驗(yàn)郊尝,以及密碼加密校驗(yàn)峻贮。

博客地址:https://blog.ffspace.cn
項(xiàng)目代碼:https://github.com/Bootcap/spring-security-study-session

一什黑、創(chuàng)建數(shù)據(jù)庫(kù)和需要的表結(jié)構(gòu)

1.1 創(chuàng)建數(shù)據(jù)庫(kù)
create database user;
use user;
1.2 創(chuàng)建user_info表盛嘿,執(zhí)行sql腳本生成
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

DROP TABLE IF EXISTS `user_info`;
CREATE TABLE `user_info`  (
  `user_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵削锰,自增',
  `user_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用戶名',
  `user_password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用戶密碼',
  `user_roles` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用戶角色',
  PRIMARY KEY (`user_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

INSERT INTO `user_info` VALUES (1, '1', '1', 'ROLE_USER');
INSERT INTO `user_info` VALUES (2, 'user', '123456', 'ROLE_USER');
INSERT INTO `user_info` VALUES (3, 'user2', '$2a$10$RHWoRd6hPXffZemAD7Gp6ehhf929etTHVGm7JGBeJTNQIgVURnSb.', 'ROLE_USER');

SET FOREIGN_KEY_CHECKS = 1;

二妹卿、修改配置

2.1 修改pom.xml

在上篇文章所需jar包的基礎(chǔ)上引入mysql和mybatis相關(guān)包。查看完整pom.xml

<!-- Mybatis -->
 <dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>1.3.2</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
2.2 修改application.yml

在上篇文章resources/application.yml的基礎(chǔ)上增加"數(shù)據(jù)源配置"和"日志配置"

# 端口號(hào)
server:
  port: 8080

spring:
  # thymeleaf配置
  thymeleaf:
    enabled: true
    encoding: UTF-8
    mode: HTML
    servlet:
      content-type: text/html
    prefix: classpath:/templates/
    suffix: .html
  # 數(shù)據(jù)源配置
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/user?useUnicode=true&characterEncoding=utf8&useSSL=false # 修改為自己數(shù)據(jù)庫(kù)所在ip地址
    driver-class-name: com.mysql.jdbc.Driver
    username: root # 默認(rèn)用戶名渣玲,修改為自己的數(shù)據(jù)庫(kù)用戶名
    password: # 填寫自己的密碼

logging:
  level:
    root: INFO
    org.springframework.web: INFO
    org.springframework.security: INFO

三逗概、創(chuàng)建CRUD操作的相關(guān)類

經(jīng)過(guò)上面的配置修改后,還需要有一套完整的CRUD操作忘衍,本篇文章僅介紹注冊(cè)和登錄校驗(yàn)仗谆,因此只有注冊(cè)和登錄校驗(yàn)操作指巡。

3.1 創(chuàng)建數(shù)據(jù)庫(kù)實(shí)體類(UserInfo.java)

路徑:com/bootcap/session/security/entity/UserInfo.java

package com.bootcap.session.security.entity;

/**
 * 數(shù)據(jù)庫(kù)實(shí)體類
 * 2018-12-10 16:21
 */
public class UserInfo {
    private Integer id;
    private String userName;
    private String password;
    private String roles;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getRoles() {
        return roles;
    }

    public void setRoles(String roles) {
        this.roles = roles;
    }

    @Override
    public String toString() {
        return "UserInfo{" +
                "id=" + id +
                ", userName='" + userName + '\'' +
                ", password='" + password + '\'' +
                ", roles='" + roles + '\'' +
                '}';
    }
}

3.2 創(chuàng)建映射文件(UserInfoMapper.java)

【提示】: 本文直接使用mybatis的注解形式進(jìn)行
sql編寫

路徑:
com/bootcap/session/security/mapper/UserInfoMapper.java

package com.bootcap.session.security.mapper;

import com.bootcap.session.security.entity.UserInfo;
import org.apache.ibatis.annotations.*;

/**
 * UserInfo映射類
 * 2018-12-10 16:26
 * 兩個(gè)注解區(qū)別,網(wǎng)絡(luò)上說(shuō)是使用該@Repository注解需要配置xml映射文件隶垮,但是小編更改后并未出現(xiàn)異常。
 */
// @Mapper
@Repository
public interface UserInfoMapper {

    /**
     * 新增
     * @param userInfo
     * @return
     */
    @Insert("insert into user_info(user_name,user_password,user_roles) values(#{userName},#{password}, #{roles})")
    int insert(UserInfo userInfo);

    /**
     * 查詢
     */
    @Select("select user_name as userName,user_password as password,user_roles as roles,user_id as id from user_info where user_name = #{userName}")
    UserInfo selectByUserName(@Param("userName") String userName);
}
3.3 創(chuàng)建業(yè)務(wù)層類(UserInfoService.java)

路徑:com/bootcap/session/security/mapper/UserInfoService.java

package com.bootcap.session.security.service;

import com.bootcap.session.security.constant.RolesContant;
import com.bootcap.session.security.entity.UserInfo;
import com.bootcap.session.security.mapper.UserInfoMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

/**
 * service業(yè)務(wù)層
 * 2018-12-10 16:37
 */
@Service
public class UserInfoService {

    @Autowired
    UserInfoMapper userInfoMapper;

    /**
     * 新增用戶
     * @param userInfo
     * @return
     */
    public boolean insert(UserInfo userInfo) {
        UserInfo userInfo1 = userInfoMapper.selectByUserName(userInfo.getUserName());
        if (userInfo1 != null){
            return false;
        }
        userInfo.setRoles(RolesContant.USER);
        // 加密保存密碼到數(shù)據(jù)庫(kù)
        userInfo.setPassword(new BCryptPasswordEncoder().encode(userInfo.getPassword()));
        int result = userInfoMapper.insert(userInfo);
        return result == 1;
    }

    /**
     * 查詢用戶
     * @param username
     * @return
     */
    public UserInfo selectUserInfo(String username) {
        return userInfoMapper.selectByUserName(username);
    }

}

【說(shuō)明】: 由于業(yè)務(wù)代碼使用了常量類秘噪,因此需要?jiǎng)?chuàng)建一個(gè)枚舉類RolesContant.java狸吞,內(nèi)容如下: public static final String USER = "ROLE_USER";

3.4 創(chuàng)建控制層(UserController.java)

路徑:com/bootcap/session/security/mapper/UserController.java

package com.bootcap.session.security.controller;

/**
 * 2018-12-10 17:02
 */
@Controller
public class UserController {

    @Autowired
    UserInfoService userInfoService;

    @PostMapping("/register")
    public String doRegister(UserInfo userInfo){
        boolean insert = userInfoService.insert(userInfo);
        if (insert){
            return "redirect:sign?success";
        }
        return "redirect:sign?error";
    }

    @GetMapping("/user")
    public String user(@AuthenticationPrincipal Principal principal, Model model){
        model.addAttribute("username", principal.getName());
        return "user/user";
    }
}

四、配置Spring Security獲取數(shù)據(jù)庫(kù)數(shù)據(jù)進(jìn)行校驗(yàn)

【說(shuō)明】: 從流程圖中我們可以得到解愤,Spring Security最終使用UserDetailsService.loadUserByUsername()方法連接數(shù)據(jù)庫(kù)獲取數(shù)據(jù)并返回給校驗(yàn)類進(jìn)行校驗(yàn)凤价,因此我們需要在項(xiàng)目中實(shí)現(xiàn)該接口重归。

4.1 創(chuàng)建MyUserDetailsService.java類并實(shí)現(xiàn)UsesrDetailsService
package com.bootcap.session.security.configuration;

import com.bootcap.session.security.service.UserInfoService;
import com.bootcap.session.security.entity.UserInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
/**
 * 自定義登錄校驗(yàn)Service
 * 2018-12-10 17:23
 */
@Service
public class MyUserDetailsService implements UserDetailsService {

    @Autowired
    UserInfoService userInfoService;

    @Override
    public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
        UserInfo userInfo = userInfoService.selectUserInfo(userName);
        if (userInfo == null) {
            throw new UsernameNotFoundException("用戶不存在"); // 若不存在拋出用戶不存在異常
        }
        // 權(quán)限字符串轉(zhuǎn)化
        List<SimpleGrantedAuthority> simpleGrantedAuthorities = new ArrayList<>();
        String[] roles = userInfo.getRoles().split(",");// 獲取后的Roles必須有ROLE_前綴,否則會(huì)拋Access is denied無(wú)權(quán)限異常
        for (String role : roles) {
            simpleGrantedAuthorities.add(new SimpleGrantedAuthority(role));
        }
        // 交給security進(jìn)行驗(yàn)證并返回
        return new User(userInfo.getUserName(), userInfo.getPassword(), simpleGrantedAuthorities);
    }
}
4.2 修改WebSecurityConfig.java調(diào)用
package com.bootcap.session.security.configuration;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

/**
 * 2018-12-10 11:03
 */
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {


    @Autowired
    MyUserDetailsService myUserDetailsService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/","/index").permitAll() // permitAll被允許訪問(wèn)
                .antMatchers("/user/**").hasRole("USER")// 指定所有user頁(yè)面需要USER角色才能訪問(wèn)
            .and()
                .formLogin().loginPage("/login").defaultSuccessUrl("/user")
            .and()
                .logout().logoutUrl("/logout").logoutSuccessUrl("/login");
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//        auth.inMemoryAuthentication() // 在內(nèi)存中進(jìn)行身份驗(yàn)證
//                .passwordEncoder(new BCryptPasswordEncoder())
//                .withUser("user")
//                .password(new BCryptPasswordEncoder().encode("123456"))
//                .roles("USER");

// 修改的地方威始,將上篇文章的內(nèi)存驗(yàn)證改為獲取數(shù)據(jù)庫(kù),并使用了密碼加密         
auth.userDetailsService(myUserDetailsService).passwordEncoder(new BCryptPasswordEncoder());
    }

}
擴(kuò)展:對(duì)密碼進(jìn)行加密

1像街、修改WebSecurityConfig.configure()方法

 auth.userDetailsService(myUserDetailsService).passwordEncoder(new BCryptPasswordEncoder());

2黎棠、在UserInfoService.insert()方法對(duì)password字段進(jìn)行加密存儲(chǔ)

 public boolean insert(UserInfo userInfo) {
        UserInfo userInfo1 = userInfoMapper.selectByUserName(userInfo.getUserName());
        if (userInfo1 != null){
            return false;
        }
        userInfo.setRoles(RolesContant.USER);
        userInfo.setPassword(new BCryptPasswordEncoder().encode(userInfo.getPassword()));
        int result = userInfoMapper.insert(userInfo);
        return result == 1;
    }
4.3 修改TemplateConfig.java(用于新增的注冊(cè)頁(yè)面)
@Configuration
public class TemplateConfig implements WebMvcConfigurer {

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("index");
        registry.addViewController("/index").setViewName("index");
        registry.addViewController("/hello").setViewName("hello");
        registry.addViewController("/login").setViewName("login");
        // 新增注冊(cè)頁(yè)面
       registry.addViewController("/sign").setViewName("register");
    }
}
4.4 上述配置完成后,我們需要增加和修改幾個(gè)頁(yè)面用于測(cè)試

4.4.1 修改login.html(增加跳轉(zhuǎn)到注冊(cè)連接)

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>登錄頁(yè)面</title>
</head>
<body>
<h1>登錄頁(yè)面</h1>
<div th:if="${param.error}">
    用戶名或密碼不正確
</div>
<div th:if="${param.logout}">
    你已經(jīng)退出登錄
</div>
<form th:action="@{/login}" method="post">
    <div><label> 用戶名: <input type="text" name="username"/> </label></div>
    <div><label> 密&nbsp;&nbsp;&nbsp;碼: <input type="password" name="password"/> </label></div>
    <div>
        <input type="submit" value="登錄"/>
        <a th:href="@{/sign}">注冊(cè)</a>
    </div>
</form>
</body>
</html>

4.4.2 新增register.html注冊(cè)頁(yè)面

<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>注冊(cè)</title>
</head>
<body>
<div class="panel-body">
    <h1>注冊(cè)頁(yè)面</h1>
    <form th:action="@{/register}" method="post">
        <div>
            賬號(hào): <input type="text" name="userName" id="username" placeholder="賬號(hào)">
        </div>
        <div>
            密碼: <input type="password" class="form-control" name="password" id="password" placeholder="密碼">
        </div>
        <br>
        <div th:if="${param.error}">
            <p>注冊(cè)失敗镰绎,賬號(hào)已存在脓斩!</p>
        </div>
        <div th:if="${param.success}">
            <p>注冊(cè)成功,可以登錄了畴栖!</p>
        </div>
        <div>
            <button type="submit" class="btn btn-primary btn-block">注冊(cè)</button>
            <a href="/login">返回登錄頁(yè)面</a>
        </div>
    </form>
</div>

</body>

</html>

4.4.3 新增user.html(用于登錄后跳轉(zhuǎn)的頁(yè)面)
路徑:templates/user/user.html

<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>用戶界面</title>
</head>

<body>

<div class="container" style="margin-top: 60px">

    <div style="text-align: center; margin-top: 10%">
        <p th:text="${username}" style="margin-top: 25px; font-size: 20px; color: crimson"></p>
        <form th:action="@{/logout}" method="post">
            <button style="margin-top: 20px">退出登錄</button>
        </form>
    </div>

</div>
</body>
</html>

五随静、啟動(dòng)運(yùn)行

至此,基本修改已經(jīng)完畢吗讶,這時(shí)候可以啟動(dòng)Application.java啟動(dòng)運(yùn)行了燎猛?答案:不能!U战浴重绷!

【提示】: 本項(xiàng)目的啟動(dòng)類是在app包下,因此我們配置的mapper映射文件的@Repository注解為mybatis的注解纵寝,所以boot不會(huì)自動(dòng)注入论寨,因此需要加入@MapperScan(basePackages = "com.bootcap.session.security.mapper")

package com.bootcap.session.security.app;

/**
 * 啟動(dòng)類
 * 2018-12-10 11:03
 */
@SpringBootApplication
@ComponentScan(basePackages = {"com.bootcap.session.security"})
@MapperScan(basePackages = "com.bootcap.session.security.mapper")
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class,args);
    }
}

六、測(cè)試結(jié)果

6.1 項(xiàng)目啟動(dòng)后爽茴,瀏覽器訪問(wèn):localhost:8080/user,會(huì)發(fā)現(xiàn)直接跳轉(zhuǎn)到登錄頁(yè)


6.2 目前我們沒(méi)有賬號(hào)葬凳,點(diǎn)擊注冊(cè)按鈕進(jìn)行注冊(cè),注冊(cè)好后室奏。我們使用注冊(cè)的賬號(hào)進(jìn)行登錄 火焰,可以正常進(jìn)入user頁(yè)面


七、擴(kuò)展篇 - 自定義Filter過(guò)濾器

7.1 創(chuàng)建兩個(gè)自定義Filter過(guò)濾器(BeforeFilter.java和BeforeFilter.java)

路徑:com/bootcap/session/security/filter

package com.bootcap.session.security.filter;

/**
 * BeforeFilter
 * 2018-12-12 10:44
 */
public class BeforeFilter extends GenericFilterBean {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("在 UsernamePasswordAuthenticationFilter 前添加 BeforeLoginFilter");
        // 繼續(xù)調(diào)用 Filter 鏈
        filterChain.doFilter(servletRequest, servletResponse);
    }
}
package com.bootcap.session.security.filter;
/**
 * AfterCsrfFilter
 * 2018-12-12 10:46
 */
public class AfterCsrfFilter extends GenericFilterBean {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("在 CsrfFilter 后添加 AfterCsrfFilter");
        filterChain.doFilter(servletRequest,servletResponse);
    }
}
7.2 在WebSecurityConfig.configure()方法中加入調(diào)用
@Override
    protected void configure(HttpSecurity http) throws Exception {
         ... 省略部分代碼 ...
        // 在 UsernamePasswordAuthenticationFilter 前添加 BeforeLoginFilter
        http.addFilterBefore(new BeforeFilter(), UsernamePasswordAuthenticationFilter.class);

        // 在 CsrfFilter 后添加 AfterCsrfFilter
        http.addFilterAfter(new AfterCsrfFilter(), CsrfFilter.class);
    }
7.3 運(yùn)行程序并訪問(wèn)任意可訪問(wèn)頁(yè)面胧沫,我們能夠的到兩個(gè)過(guò)濾器的執(zhí)行順序
2018-12-12 10:49:34.607  INFO 1060 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring FrameworkServlet 'dispatcherServlet'
2018-12-12 10:49:34.607  INFO 1060 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization started
2018-12-12 10:49:34.611  INFO 1060 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization completed in 4 ms
在 CsrfFilter 后添加 AfterCsrfFilter
在 UsernamePasswordAuthenticationFilter 前添加 BeforeLoginFilter
在 CsrfFilter 后添加 AfterCsrfFilter
在 UsernamePasswordAuthenticationFilter 前添加 BeforeLoginFilter

上一篇:Spring Security 入門教程(一) - 簡(jiǎn)單的登錄認(rèn)證
下一篇:Spring Security 入門教程(三)- 基于登錄認(rèn)證記住我實(shí)例

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末昌简,一起剝皮案震驚了整個(gè)濱河市占业,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌纯赎,老刑警劉巖谦疾,帶你破解...
    沈念sama閱讀 219,427評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異犬金,居然都是意外死亡念恍,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門晚顷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)峰伙,“玉大人,你說(shuō)我怎么就攤上這事该默⊥ィ” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,747評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵栓袖,是天一觀的道長(zhǎng)匣摘。 經(jīng)常有香客問(wèn)我,道長(zhǎng)叽赊,這世上最難降的妖魔是什么恋沃? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,939評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮必指,結(jié)果婚禮上囊咏,老公的妹妹穿的比我還像新娘。我一直安慰自己塔橡,他們只是感情好梅割,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,955評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著葛家,像睡著了一般户辞。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上癞谒,一...
    開(kāi)封第一講書(shū)人閱讀 51,737評(píng)論 1 305
  • 那天底燎,我揣著相機(jī)與錄音,去河邊找鬼弹砚。 笑死双仍,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的桌吃。 我是一名探鬼主播朱沃,決...
    沈念sama閱讀 40,448評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了逗物?” 一聲冷哼從身側(cè)響起搬卒,我...
    開(kāi)封第一講書(shū)人閱讀 39,352評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎翎卓,沒(méi)想到半個(gè)月后契邀,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,834評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡莲祸,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,992評(píng)論 3 338
  • 正文 我和宋清朗相戀三年蹂安,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片锐帜。...
    茶點(diǎn)故事閱讀 40,133評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖畜号,靈堂內(nèi)的尸體忽然破棺而出缴阎,到底是詐尸還是另有隱情,我是刑警寧澤简软,帶...
    沈念sama閱讀 35,815評(píng)論 5 346
  • 正文 年R本政府宣布蛮拔,位于F島的核電站,受9級(jí)特大地震影響痹升,放射性物質(zhì)發(fā)生泄漏建炫。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,477評(píng)論 3 331
  • 文/蒙蒙 一疼蛾、第九天 我趴在偏房一處隱蔽的房頂上張望肛跌。 院中可真熱鬧,春花似錦察郁、人聲如沸衍慎。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,022評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)稳捆。三九已至,卻和暖如春麦轰,著一層夾襖步出監(jiān)牢的瞬間乔夯,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,147評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工款侵, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留末荐,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,398評(píng)論 3 373
  • 正文 我出身青樓喳坠,卻偏偏與公主長(zhǎng)得像鞠评,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子壕鹉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,077評(píng)論 2 355

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