day18項目【權(quán)限管理和配置服務(wù)】-01 整合Spring Security

01-整合Spring Security

一冷溃、Spring Security介紹

1、框架介紹

Spring?是一個非常流行和成功的Java應(yīng)用開發(fā)框架振惰。Spring Security?基于?Spring?框架松申,提供了一套?Web?應(yīng)用安全性的完整解決方案检眯。一般來說凿叠,Web?應(yīng)用的安全性包括用戶認證Authentication)和用戶授權(quán)(Authorization兩個部分涩笤。

(1)用戶認證指的是:驗證某個用戶是否為系統(tǒng)中的合法主體,也就是說用戶能否訪問該系統(tǒng)盒件。用戶認證一般要求用戶提供用戶名和密碼蹬碧。系統(tǒng)通過校驗用戶名和密碼來完成認證過程。

(2)用戶授權(quán)指的是驗證某個用戶是否有權(quán)限執(zhí)行某個操作炒刁。在一個系統(tǒng)中恩沽,不同用戶所具有的權(quán)限是不同的。比如對一個文件來說切心,有的用戶只能進行讀取,而有的用戶可以進行修改片吊。一般來說绽昏,系統(tǒng)會為不同的用戶分配不同的角色,而每個角色則對應(yīng)一系列的權(quán)限俏脊。

Spring Security其實就是用filter全谤,多請求的路徑進行過濾。

(1)如果是基于Session爷贫,那么Spring-security會對cookie里的sessionid進行解析认然,找到服務(wù)器存儲的sesion信息,然后判斷當(dāng)前用戶是否符合請求的要求漫萄。

(2)如果是token卷员,則是解析出token,然后將當(dāng)前請求加入到Spring-security管理的權(quán)限信息中去

2腾务、認證與授權(quán)實現(xiàn)思路

如果系統(tǒng)的模塊眾多毕骡,每個模塊都需要就行授權(quán)與認證,所以我們選擇基于token的形式進行授權(quán)與認證,用戶根據(jù)用戶名密碼認證成功未巫,然后獲取當(dāng)前用戶角色的一系列權(quán)限值窿撬,并以用戶名為key,權(quán)限列表為value的形式存入redis緩存中叙凡,根據(jù)用戶名相關(guān)信息生成token返回劈伴,瀏覽器將token記錄到cookie中每次調(diào)用api接口都默認將token攜帶到header請求頭中握爷,Spring-security解析header頭獲取token信息跛璧,解析token獲取當(dāng)前用戶名,根據(jù)用戶名就可以從redis中獲取權(quán)限列表饼拍,這樣Spring-security就能夠判斷當(dāng)前請求是否有權(quán)限訪問

二赡模、整合Spring Security

1、在common下創(chuàng)建spring_security模塊

2师抄、在spring_security引入相關(guān)依賴

? ? <dependencies>

? ? ? ? <dependency>

? ? ? ? ? ? <groupId>com.atguigu</groupId>

? ? ? ? ? ? <artifactId>common_utils</artifactId>

? ? ? ? ? ? <version>0.0.1-SNAPSHOT</version>

? ? ? ? </dependency>

? ? ? ? <!-- Spring Security依賴 -->

? ? ? ? <dependency>

? ? ? ? ? ? <groupId>org.springframework.boot</groupId>

? ? ? ? ? ? <artifactId>spring-boot-starter-security</artifactId>

? ? ? ? </dependency>

? ? ? ? <dependency>

? ? ? ? ? ? <groupId>io.jsonwebtoken</groupId>

? ? ? ? ? ? <artifactId>jjwt</artifactId>? //生成token需要使用到j(luò)wt

? ? ? ? </dependency>

? ? </dependencies>

3漓柑、在service_acls引入spring_security依賴

????????<dependency>

? ? ? ? ? ? <groupId>com.atguigu</groupId>

? ? ? ? ? ? <artifactId>spring_security</artifactId>

? ? ? ? ? ? <version>0.0.1-SNAPSHOT</version>

? ? ? ? </dependency>

4、復(fù)制工具類到common_utils

5叨吮、創(chuàng)建spring security核心配置類

Spring Security的核心配置就是繼承WebSecurityConfigurerAdapter并注解@EnableWebSecurity的配置辆布。

這個配置指明了用戶名密碼的處理方式、請求路徑的開合茶鉴、登錄登出控制等和安全相關(guān)的配置锋玲。

package com.atguigu.serurity.config;

import com.atguigu.serurity.filter.TokenAuthenticationFilter;

import com.atguigu.serurity.filter.TokenLoginFilter;

import com.atguigu.serurity.security.DefaultPasswordEncoder;

import com.atguigu.serurity.security.TokenLogoutHandler;

import com.atguigu.serurity.security.TokenManager;

import com.atguigu.serurity.security.UnauthorizedEntryPoint;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.context.annotation.Configuration;

import org.springframework.data.redis.core.RedisTemplate;

import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;

import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;

import org.springframework.security.config.annotation.web.builders.HttpSecurity;

import org.springframework.security.config.annotation.web.builders.WebSecurity;

import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;

import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

import org.springframework.security.core.userdetails.UserDetailsService;

/**

* <p>

* Security配置類

* </p>

*

* @author qy

* @since 2019-11-18

*/

@Configuration? //表示配置類

@EnableWebSecurity

@EnableGlobalMethodSecurity(prePostEnabled = true)

public class TokenWebSecurityConfig extends WebSecurityConfigurerAdapter {

? ? private UserDetailsService userDetailsService;

? ? private TokenManager tokenManager;

? ? private DefaultPasswordEncoder defaultPasswordEncoder;

? ? private RedisTemplate redisTemplate;


? ? @Autowired

? ? public TokenWebSecurityConfig(UserDetailsService userDetailsService, DefaultPasswordEncoder defaultPasswordEncoder,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? TokenManager tokenManager, RedisTemplate redisTemplate) {

? ? ? ? this.userDetailsService = userDetailsService;

? ? ? ? this.defaultPasswordEncoder = defaultPasswordEncoder;

? ? ? ? this.tokenManager = tokenManager;

? ? ? ? this.redisTemplate = redisTemplate;

? ? }

? ? /**

? ? * 配置設(shè)置

? ? * @param http

? ? * @throws Exception

? ? */

? ? @Override

? ? protected void configure(HttpSecurity http) throws Exception {

? ? ? ? http.exceptionHandling()

? ? ? ? ? ? ? ? .authenticationEntryPoint(new UnauthorizedEntryPoint())

? ? ? ? ? ? ? ? .and().csrf().disable()

? ? ? ? ? ? ? ? .authorizeRequests()

? ? ? ? ? ? ? ? .anyRequest().authenticated()

????????????????//設(shè)置退出請求地址,這個地址是由spring security做到的涵叮,因此這個地址理論上可以隨便寫

? ? ? ? ? ? ? ? .and().logout().logoutUrl("/admin/acl/index/logout")

? ? ? ? ? ? ? ? .addLogoutHandler(new TokenLogoutHandler(tokenManager,redisTemplate)).and()

? ? ? ? ? ? ? ? .addFilter(new TokenLoginFilter(authenticationManager(), tokenManager, redisTemplate))

? ? ? ? ? ? ? ? .addFilter(new TokenAuthenticationFilter(authenticationManager(), tokenManager, redisTemplate)).httpBasic();

? ? }

? ? /**

? ? * 密碼處理

? ? * @param auth

? ? * @throws Exception

? ? */

? ? @Override

? ? public void configure(AuthenticationManagerBuilder auth) throws Exception {

? ? ? ? auth.userDetailsService(userDetailsService).passwordEncoder(defaultPasswordEncoder);

? ? }

? ? /**

? ? * 配置哪些請求不攔截

? ? * @param web

? ? * @throws Exception

? ? */

? ? @Override

? ? public void configure(WebSecurity web) throws Exception {

//? ? ? ? web.ignoring().antMatchers("/api/**",

//? ? ? ? ? ? ? ? "/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**"

//? ? ? ? ? ? ? );

? ? ? ? web.ignoring().antMatchers("/*/**");

? ? }

}

5惭蹂、創(chuàng)建認證授權(quán)相關(guān)的工具類

(1)DefaultPasswordEncoder:密碼處理的方法

@Component

public class DefaultPasswordEncoder implements PasswordEncoder {

? ? public DefaultPasswordEncoder() {

? ? ? ? this(-1);

? ? }

? ? public DefaultPasswordEncoder(int strength) {}

? ? public String encode(CharSequence rawPassword) {

? ? ? ? return MD5.encrypt(rawPassword.toString());

? ? }

? ? public boolean matches(CharSequence rawPassword, String encodedPassword) {

? ? ? ? return encodedPassword.equals(MD5.encrypt(rawPassword.toString()));

? ? }

}

(2)TokenManager:token操作的工具類

@Component

public class TokenManager {

? ? private long tokenExpiration = 24*60*60*1000;

? ? private String tokenSignKey = "123456";

? ? public String createToken(String username) {

? ? ? ? String token = Jwts.builder().setSubject(username)

? ? ? ? ? ? ? ? .setExpiration(new Date(System.currentTimeMillis() + tokenExpiration))

? ? ? ? ? ? ? ? .signWith(SignatureAlgorithm.HS512, tokenSignKey).compressWith(CompressionCodecs.GZIP).compact();

? ? ? ? return token;

? ? }

? ? public String getUserFromToken(String token) {

? ? ? ? String user = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token).getBody().getSubject();

? ? ? ? return user;

? ? }

? ? public void removeToken(String token) {

? ? ? ? //jwttoken無需刪除,客戶端扔掉即可割粮。

? ? }

}

(3)TokenLogoutHandler:退出實現(xiàn)

public class TokenLogoutHandler implements LogoutHandler {

? ? private TokenManager tokenManager;

? ? private RedisTemplate redisTemplate;

? ? public TokenLogoutHandler(TokenManager tokenManager, RedisTemplate redisTemplate) {

? ? ? ? this.tokenManager = tokenManager;

? ? ? ? this.redisTemplate = redisTemplate;

? ? }

? ? @Override

? ? public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {

? ? ? ? String token = request.getHeader("token");

? ? ? ? if (token != null) {

? ? ? ? ? ? tokenManager.removeToken(token);

? ? ? ? ? ? //清空當(dāng)前用戶緩存中的權(quán)限數(shù)據(jù)

? ? ? ? ? ? String userName = tokenManager.getUserFromToken(token);

? ? ? ? ? ? redisTemplate.delete(userName);

? ? ? ? }

? ? ? ? ResponseUtil.out(response, R.ok());

? ? }

}

(4)UnauthorizedEntryPoint:未授權(quán)統(tǒng)一處理

public class UnauthorizedEntryPoint implements AuthenticationEntryPoint {

? ? @Override

? ? public void commence(HttpServletRequest request, HttpServletResponse response,

? ? ? ? ? ? ? ? ? ? ? ? AuthenticationException authException) throws IOException, ServletException {

? ? ? ? ResponseUtil.out(response, R.error());

? ? }

}

6盾碗、創(chuàng)建認證授權(quán)實體類

(1)SecutityUser

package com.atguigu.serurity.entity;

import lombok.Data;

import lombok.extern.slf4j.Slf4j;

import org.springframework.security.core.GrantedAuthority;

import org.springframework.security.core.authority.SimpleGrantedAuthority;

import org.springframework.security.core.userdetails.UserDetails;

import org.springframework.util.StringUtils;

import java.util.ArrayList;

import java.util.Collection;

import java.util.List;

/**

* <p>

* 安全認證用戶詳情信息

* </p>

*

* @author qy

* @since 2019-11-08

*/

@Data

@Slf4j

public class SecurityUser implements UserDetails {

? ? //當(dāng)前登錄用戶

? ? private transient User currentUserInfo;

? ? //當(dāng)前權(quán)限

? ? private List<String> permissionValueList;

? ? public SecurityUser() {

? ? }

? ? public SecurityUser(User user) {

? ? ? ? if (user != null) {

? ? ? ? ? ? this.currentUserInfo = user;

? ? ? ? }

? ? }

? ? @Override

? ? public Collection<? extends GrantedAuthority> getAuthorities() {

? ? ? ? Collection<GrantedAuthority> authorities = new ArrayList<>();

? ? ? ? for(String permissionValue : permissionValueList) {

? ? ? ? ? ? if(StringUtils.isEmpty(permissionValue)) continue;

? ? ? ? ? ? SimpleGrantedAuthority authority = new SimpleGrantedAuthority(permissionValue);

? ? ? ? ? ? authorities.add(authority);

? ? ? ? }

? ? ? ? return authorities;

? ? }

? ? @Override

? ? public String getPassword() {

? ? ? ? return currentUserInfo.getPassword();

? ? }

? ? @Override

? ? public String getUsername() {

? ? ? ? return currentUserInfo.getUsername();

? ? }

? ? @Override

? ? public boolean isAccountNonExpired() {

? ? ? ? return true;

? ? }

? ? @Override

? ? public boolean isAccountNonLocked() {

? ? ? ? return true;

? ? }

? ? @Override

? ? public boolean isCredentialsNonExpired() {

? ? ? ? return true;

? ? }

? ? @Override

? ? public boolean isEnabled() {

? ? ? ? return true;

? ? }

}

(2)User用戶實體類:存儲用戶信息

package com.atguigu.serurity.entity;

import io.swagger.annotations.ApiModel;

import io.swagger.annotations.ApiModelProperty;

import lombok.Data;

import java.io.Serializable;

/**

* <p>

* 用戶實體類

* </p>

*

* @author qy

* @since 2019-11-08

*/

@Data

@ApiModel(description = "用戶實體類")

public class User implements Serializable {

????private static final long serialVersionUID = 1L;

????@ApiModelProperty(value = "微信openid")

????private String username;

????@ApiModelProperty(value = "密碼")

????private String password;

????@ApiModelProperty(value = "昵稱")

????private String nickName;

????@ApiModelProperty(value = "用戶頭像")

????private String salt;

????@ApiModelProperty(value = "用戶簽名")

????private String token;

}

7、創(chuàng)建認證和授權(quán)的filter

(1)TokenLoginFilter:認證的filter

package com.atguigu.serurity.filter;

import com.atguigu.commonutils.R;

import com.atguigu.commonutils.ResponseUtil;

import com.atguigu.serurity.entity.SecurityUser;

import com.atguigu.serurity.entity.User;

import com.atguigu.serurity.security.TokenManager;

import com.fasterxml.jackson.databind.ObjectMapper;

import org.springframework.data.redis.core.RedisTemplate;

import org.springframework.security.authentication.AuthenticationManager;

import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;

import org.springframework.security.core.Authentication;

import org.springframework.security.core.AuthenticationException;

import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.FilterChain;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import java.io.IOException;

import java.util.ArrayList;

/**

* <p>

* 登錄過濾器舀瓢,繼承UsernamePasswordAuthenticationFilter廷雅,對用戶名密碼進行登錄校驗

* </p>

*

* @author qy

* @since 2019-11-08

*/

public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {

? ? private AuthenticationManager authenticationManager;

? ? private TokenManager tokenManager;

? ? private RedisTemplate redisTemplate;

? ? public TokenLoginFilter(AuthenticationManager authenticationManager, TokenManager tokenManager, RedisTemplate redisTemplate) {

? ? ? ? this.authenticationManager = authenticationManager;

? ? ? ? this.tokenManager = tokenManager;

? ? ? ? this.redisTemplate = redisTemplate;

? ? ? ? this.setPostOnly(false);

????????//設(shè)置登錄請求地址,這個地址是由spring security做到的京髓,因此這個地址理論上可以隨便寫

? ? ? ? this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/admin/acl/login","POST"));

? ? }


? ? //得到輸入的用戶名和密碼

? ? @Override

? ? public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res)

? ? ? ? ? ? throws AuthenticationException {

? ? ? ? try {

? ? ? ? ? ? User user = new ObjectMapper().readValue(req.getInputStream(), User.class);

? ? ? ? ? ? return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword(), new ArrayList<>()));

? ? ? ? } catch (IOException e) {

? ? ? ? ? ? throw new RuntimeException(e);

? ? ? ? }

? ? }


? ? /**

? ? * 登錄成功

? ? * @param req

? ? * @param res

? ? * @param chain

? ? * @param auth

? ? * @throws IOException

? ? * @throws ServletException

? ? */

? ? @Override

? ? protected void successfulAuthentication(HttpServletRequest req, HttpServletResponse res, FilterChain chain,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Authentication auth) throws IOException, ServletException {

? ? ? ? SecurityUser user = (SecurityUser) auth.getPrincipal();

? ? ? ? String token = tokenManager.createToken(user.getCurrentUserInfo().getUsername());

? ? ? ? redisTemplate.opsForValue().set(user.getCurrentUserInfo().getUsername(), user.getPermissionValueList());

? ? ? ? ResponseUtil.out(res, R.ok().data("token", token));

? ? }

? ? /**

? ? * 登錄失敗

? ? * @param request

? ? * @param response

? ? * @param e

? ? * @throws IOException

? ? * @throws ServletException

? ? */

? ? @Override

? ? protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? AuthenticationException e) throws IOException, ServletException {

? ? ? ? ResponseUtil.out(response, R.error());

? ? }

}

(2)TokenAuthenticationFilter:

授權(quán)filter

package com.atguigu.serurity.filter;

import com.atguigu.commonutils.R;

import com.atguigu.commonutils.ResponseUtil;

import com.atguigu.serurity.security.TokenManager;

import org.springframework.data.redis.core.RedisTemplate;

import org.springframework.security.authentication.AuthenticationManager;

import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;

import org.springframework.security.core.GrantedAuthority;

import org.springframework.security.core.authority.SimpleGrantedAuthority;

import org.springframework.security.core.context.SecurityContextHolder;

import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import org.springframework.util.StringUtils;

import javax.servlet.FilterChain;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import java.io.IOException;

import java.util.ArrayList;

import java.util.Collection;

import java.util.List;

/**

* <p>

* 訪問過濾器

* </p>

*

* @author qy

* @since 2019-11-08

*/

public class TokenAuthenticationFilter extends BasicAuthenticationFilter {

? ? private TokenManager tokenManager;

? ? private RedisTemplate redisTemplate;

? ? public TokenAuthenticationFilter(AuthenticationManager authManager, TokenManager tokenManager,RedisTemplate redisTemplate) {

? ? ? ? super(authManager);

? ? ? ? this.tokenManager = tokenManager;

? ? ? ? this.redisTemplate = redisTemplate;

? ? }

? ? @Override

? ? protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain)

? ? ? ? ? ? throws IOException, ServletException {

? ? ? ? logger.info("================="+req.getRequestURI());

? ? ? ? if(req.getRequestURI().indexOf("admin") == -1) {

? ? ? ? ? ? chain.doFilter(req, res);

? ? ? ? ? ? return;

? ? ? ? }

? ? ? ? UsernamePasswordAuthenticationToken authentication = null;

? ? ? ? try {

? ? ? ? ? ? authentication = getAuthentication(req);

? ? ? ? } catch (Exception e) {

? ? ? ? ? ? ResponseUtil.out(res, R.error());

? ? ? ? }

? ? ? ? if (authentication != null) {

? ? ? ? ? ? SecurityContextHolder.getContext().setAuthentication(authentication);

? ? ? ? } else {

? ? ? ? ? ? ResponseUtil.out(res, R.error());

? ? ? ? }

? ? ? ? chain.doFilter(req, res);

? ? }


? ? private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {

? ? ? ? // token置于header里

? ? ? ? String token = request.getHeader("token");

? ? ? ? if (token != null && !"".equals(token.trim())) {

? ? ? ? ? ? String userName = tokenManager.getUserFromToken(token);

? ? ? ? ? ? List<String> permissionValueList = (List<String>) redisTemplate.opsForValue().get(userName);

? ? ? ? ? ? Collection<GrantedAuthority> authorities = new ArrayList<>();

? ? ? ? ? ? for(String permissionValue : permissionValueList) {

? ? ? ? ? ? ? ? if(StringUtils.isEmpty(permissionValue)) continue;

? ? ? ? ? ? ? ? SimpleGrantedAuthority authority = new SimpleGrantedAuthority(permissionValue);

? ? ? ? ? ? ? ? authorities.add(authority);

? ? ? ? ? ? }

? ? ? ? ? ? if (!StringUtils.isEmpty(userName)) {

? ? ? ? ? ? ? ? return new UsernamePasswordAuthenticationToken(userName, token, authorities);

? ? ? ? ? ? }

? ? ? ? ? ? return null;

? ? ? ? }

? ? ? ? return null;

? ? }

}



02-創(chuàng)建查詢用戶類和前端對接

一航缀、創(chuàng)建自定義查詢用戶類

(1)在service_acls模塊創(chuàng)建,因為其他模板不會用到堰怨。

查詢登錄和用戶權(quán)限類:UserDetailsServiceImpl ?implements UserDetailsService

二芥玉、后端接口和前端頁面對接

1、在前端項目中下載依賴

npm install --save vuex-persistedstate

2备图、替換相關(guān)文件

3飞傀、在node_modules文件夾中替換element-ui依賴

(1)修改router文件夾里面index. js 里面路徑和vue文件地址皇型。

(2)修改數(shù)據(jù)庫菜單表路徑和頁面地址。

(3)修改前端項目請求地址是網(wǎng)關(guān)地址砸烦。

測試:


輸入用戶名和密碼:

權(quán)限管理整合springsecuri ty代碼執(zhí)行過程:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末弃鸦,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子幢痘,更是在濱河造成了極大的恐慌唬格,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件颜说,死亡現(xiàn)場離奇詭異购岗,居然都是意外死亡,警方通過查閱死者的電腦和手機门粪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門喊积,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人玄妈,你說我怎么就攤上這事乾吻。” “怎么了拟蜻?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵绎签,是天一觀的道長。 經(jīng)常有香客問我酝锅,道長诡必,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任搔扁,我火速辦了婚禮爸舒,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘稿蹲。我一直安慰自己扭勉,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布场绿。 她就那樣靜靜地躺著剖效,像睡著了一般嫉入。 火紅的嫁衣襯著肌膚如雪焰盗。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天咒林,我揣著相機與錄音熬拒,去河邊找鬼。 笑死垫竞,一個胖子當(dāng)著我的面吹牛澎粟,可吹牛的內(nèi)容都是我干的蛀序。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼活烙,長吁一口氣:“原來是場噩夢啊……” “哼徐裸!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起啸盏,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤重贺,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后回懦,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體气笙,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年怯晕,在試婚紗的時候發(fā)現(xiàn)自己被綠了潜圃。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡舟茶,死狀恐怖谭期,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情稚晚,我是刑警寧澤崇堵,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站客燕,受9級特大地震影響鸳劳,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜也搓,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一赏廓、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧傍妒,春花似錦幔摸、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至嗦玖,卻和暖如春患雇,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背宇挫。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工苛吱, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人器瘪。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓翠储,卻偏偏與公主長得像绘雁,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子援所,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,916評論 2 344