SpringBoot集成Shiro篇(八)

點(diǎn)擊上方藍(lán)色字體屡萤,關(guān)注我們



這篇文章我們來(lái)學(xué)習(xí)如何使用Spring Boot集成Apache Shiro蔚约。安全應(yīng)該是互聯(lián)網(wǎng)公司的一道生命線(xiàn)娇澎,幾乎任何的公司都會(huì)涉及到這方面的需求逐工。這篇文章會(huì)先介紹一下Apache Shiro描融,在結(jié)合Spring Boot給出使用案例铝噩。


Shiro的由來(lái)


對(duì)于一個(gè)真正為其存在提供良好案例的框架,以及因此您使用它的理由窿克,它應(yīng)該滿(mǎn)足其他替代方案無(wú)法滿(mǎn)足的需求骏庸。為了理解這一點(diǎn)毛甲,我們需要了解Shiro的歷史以及創(chuàng)建時(shí)的替代方案。

在2008年進(jìn)入Apache軟件基金會(huì)之前具被,Shiro已經(jīng)有5年的歷史玻募,之前被稱(chēng)為JSecurity項(xiàng)目,該項(xiàng)目始于2003年初一姿。2003年七咧,Java應(yīng)用程序開(kāi)發(fā)人員的通用安全替代方案并不多 - Java認(rèn)證和授權(quán)服務(wù),也稱(chēng)為JAAS叮叹。JAAS存在許多缺點(diǎn) - 雖然其身份驗(yàn)證功能在某種程度上是可以容忍的艾栋,但授權(quán)方面使用起來(lái)很麻煩且令人沮喪。此外蛉顽,JAAS嚴(yán)重依賴(lài)于虛擬機(jī)級(jí)安全性問(wèn)題蝗砾,例如,確定是否應(yīng)允許在JVM中加載類(lèi)携冤。作為一名應(yīng)用程序開(kāi)發(fā)人員悼粮,我更關(guān)心應(yīng)用程序最終用戶(hù)可以做什么,而不是我的代碼可以在JVM中做什么噪叙。

由于我當(dāng)時(shí)正在使用的應(yīng)用程序矮锈,我還需要訪(fǎng)問(wèn)一個(gè)干凈的霉翔,與容器無(wú)關(guān)的會(huì)話(huà)機(jī)制睁蕾。當(dāng)時(shí)游戲中唯一的會(huì)話(huà)選擇是HttpSessions,它需要一個(gè)Web容器债朵,或EBJ 2.1 Stateful Session Beans子眶,它需要一個(gè)EJB容器。我需要一些可以與容器分離的東西序芦,可以在我選擇的任何環(huán)境中使用臭杰。

最后,存在加密問(wèn)題谚中。有時(shí)候我們都需要保證數(shù)據(jù)安全渴杆,但除非你是加密專(zhuān)家,否則Java密碼體系結(jié)構(gòu)很難理解宪塔。API充滿(mǎn)了檢查異常磁奖,并且使用起來(lái)很麻煩。我希望有一個(gè)更清潔的開(kāi)箱即用的解決方案某筐,可以根據(jù)需要輕松加密和解密數(shù)據(jù)比搭。

因此,從2003年初的安全狀況來(lái)看南誊,您可以很快意識(shí)到在單一身诺,有凝聚力的框架中沒(méi)有任何東西可以滿(mǎn)足所有這些要求蜜托。正因?yàn)槿绱耍琂Security霉赡,以及后來(lái)的Apache Shiro誕生了橄务。

什么是Shiro?


Apache Shiro是一個(gè)功能強(qiáng)大且易于使用的Java安全框架穴亏,可執(zhí)行身份驗(yàn)證仪糖,授權(quán),加密和會(huì)話(huà)管理迫肖,并可用于保護(hù)任何應(yīng)用程序 - 從命令行應(yīng)用程序锅劝,移動(dòng)應(yīng)用程序到最大的Web和企業(yè)應(yīng)用程序。


Shiro的特性

Authentication(認(rèn)證), Authorization(授權(quán)), Session Management(會(huì)話(huà)管理), Cryptography(加密)被 Shiro 框架的開(kāi)發(fā)團(tuán)隊(duì)稱(chēng)之為應(yīng)用安全的四大基石蟆湖。

Authentication(認(rèn)證):用戶(hù)身份識(shí)別故爵,通常被稱(chēng)為用戶(hù)“登錄”。

Authorization(授權(quán)):訪(fǎng)問(wèn)控制隅津。比如某個(gè)用戶(hù)是否具有某個(gè)操作的使用權(quán)限诬垂。

Session Management(會(huì)話(huà)管理):特定于用戶(hù)的會(huì)話(huà)管理,甚至在非web 或 EJB 應(yīng)用程序。

Cryptography(加密):在對(duì)數(shù)據(jù)源使用加密算法加密的同時(shí)伦仍,保證易于使用结窘。


Shiro表結(jié)構(gòu)


user_info 用戶(hù)表

sys_user_role 用戶(hù)角色關(guān)聯(lián)表 (一對(duì)多的關(guān)系,一個(gè)角色對(duì)應(yīng)多個(gè)用戶(hù))

sys_permission 權(quán)限表

sys_role_permission 角色權(quán)限關(guān)聯(lián)表 (多對(duì)多關(guān)系)

sys_role 角色表



開(kāi)始搭建


pom文件

?<dependencies>
????<dependency>
????????<groupId>org.springframework.boot</groupId>
????????<artifactId>spring-boot-starter-data-jpa</artifactId>
????</dependency>
????<dependency>
????????<groupId>org.springframework.boot</groupId>
????????<artifactId>spring-boot-starter-thymeleaf</artifactId>
????</dependency>
????<dependency>
????????<groupId>net.sourceforge.nekohtml</groupId>
????????<artifactId>nekohtml</artifactId>
????????<version>1.9.22</version>
????</dependency>
????<dependency>
????????<groupId>org.springframework.boot</groupId>
????????<artifactId>spring-boot-starter-web</artifactId>
????</dependency>

???<!--?shiro?關(guān)鍵包-->
????<dependency>
????????<groupId>org.apache.shiro</groupId>
????????<artifactId>shiro-spring</artifactId>
????????<version>1.4.0</version>
????</dependency>
????<dependency>
????????<groupId>mysql</groupId>
????????<artifactId>mysql-connector-java</artifactId>
????????<scope>runtime</scope>
????</dependency>
</dependencies>

配置文件

spring.datasource.url=jdbc:mysql://localhost:3306/test??
serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

spring.jpa.properties.hibernate.hbm2ddl.auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.show-sql=?true
spring.thymeleaf.cache=false

創(chuàng)建用戶(hù)類(lèi)

@Entity
public?class?UserInfo?implements?Serializable?{
??????@Id
??????@GeneratedValue
??????private?Integer?uid;
??????@Column(unique?=true)
??????private?String?username;//帳號(hào)
??????private?String?name;//名稱(chēng)(昵稱(chēng)或者真實(shí)姓名充蓝,不同系統(tǒng)不同定義)
??????private?String?password;?//密碼;
??????private?String?salt;//加密密碼的鹽
??????private?byte?state;//用戶(hù)狀態(tài),0:創(chuàng)建未認(rèn)證(比如沒(méi)有激活隧枫,沒(méi)有輸入驗(yàn)證碼等等)--等待驗(yàn)證的用戶(hù)?,?1:正常狀態(tài),2:用戶(hù)被鎖定.
??????@ManyToMany(fetch=?FetchType.EAGER)//立即從數(shù)據(jù)庫(kù)中進(jìn)行加載數(shù)據(jù);
??????@JoinTable(name?=?"SysUserRole",?joinColumns?=?{?@JoinColumn(name?=?"uid")?},?inverseJoinColumns?={@JoinColumn(name?=?"roleId")?})
??????private?List<SysRole>?roleList;//?一個(gè)用戶(hù)具有多個(gè)角色
??????//?省略setget方法

}

創(chuàng)建角色類(lèi)

@Entity
public?class?SysRole?{
?????@Id@GeneratedValue
?????private?Integer?id;?//?編號(hào)
?????private?String?role;?//?角色標(biāo)識(shí)程序中判斷使用,如"admin",這個(gè)是唯一的:
?????private?String?description;?//?角色描述,UI界面顯示使用
?????private?Boolean?available?=?Boolean.FALSE;?//?是否可用,如果不可用將不會(huì)添加給用戶(hù)

??????//角色?--?權(quán)限關(guān)系:多對(duì)多關(guān)系;
?????@ManyToMany(fetch=?FetchType.EAGER)
?????@JoinTable(name="SysRolePermission",joinColumns={@JoinColumn(name="roleId")},inverseJoinColumns={@JoinColumn(name="permissionId")})
?????private?List<SysPermission>?permissions;

?????//?用戶(hù)?-?角色關(guān)系定義;
????@ManyToMany
????@JoinTable(name="SysUserRole",joinColumns={@JoinColumn(name="roleId")},inverseJoinColumns={@JoinColumn(name="uid")})
?????private?List<UserInfo>?userInfos;//?一個(gè)角色對(duì)應(yīng)多個(gè)用戶(hù)
?????//?省略setget方法
}

權(quán)限類(lèi)

@Entity
public?class?SysPermission?implements?Serializable?{
?????@Id@GeneratedValue
?????private?Integer?id;//主鍵.
?????private?String?name;//名稱(chēng).
?????@Column(columnDefinition="enum('menu','button')")
?????private?String?resourceType;//資源類(lèi)型,[menu|button]
?????private?String?url;//資源路徑.
?????private?String?permission;?//權(quán)限字符串,menu例子:role:*谓苟,button例子:role:create,role:update,role:delete,role:view
?????private?Long?parentId;?//父編號(hào)
?????private?String?parentIds;?//父編號(hào)列表
?????private?Boolean?available?=?Boolean.FALSE;
?????@ManyToMany
?????@JoinTable(name="SysRolePermission",joinColumns={@JoinColumn(name="permissionId")},inverseJoinColumns={@JoinColumn(name="roleId")})
?????private?List<SysRole>?roles;
?????//省略setget方法
}

根據(jù)以上的代碼會(huì)自動(dòng)生成user_info(用戶(hù)信息表)官脓、sys_role(角色表)、sys_permission(權(quán)限表)涝焙、sys_user_role(用戶(hù)角色表)卑笨、sys_role_permission(角色權(quán)限表)這五張表,為了方便測(cè)試我們給這五張表插入一些初始化數(shù)據(jù):

INSERT?INTO?`user_info`?(`uid`,`username`,`name`,`password`,`salt`,`state`)?VALUES?('1',?'admin',?'管理員',?'9c77d6384a1d8a1cc581424e6f0e82d8','root30ea1b94d889ccadeb9f89af63317de2',?0);
INSERT?INTO?`sys_permission`?(`id`,`available`,`name`,`parent_id`,`parent_ids`,`permission`,`resource_type`,`url`)?VALUES?(1,0,'用戶(hù)管理',0,'0/','userInfo:view','menu','userInfo/userList');
INSERT?INTO?`sys_permission`?(`id`,`available`,`name`,`parent_id`,`parent_ids`,`permission`,`resource_type`,`url`)?VALUES?(2,0,'用戶(hù)添加',1,'0/1','userInfo:add','button','userInfo/userAdd');
INSERT?INTO?`sys_permission`?(`id`,`available`,`name`,`parent_id`,`parent_ids`,`permission`,`resource_type`,`url`)?VALUES?(3,0,'用戶(hù)刪除',1,'0/1','userInfo:del','button','userInfo/userDel');
INSERT?INTO?`sys_role`?(`id`,`available`,`description`,`role`)?VALUES?(1,0,'管理員','admin');
INSERT?INTO?`sys_role`?(`id`,`available`,`description`,`role`)?VALUES?(2,0,'VIP會(huì)員','vip');
INSERT?INTO?`sys_role`?(`id`,`available`,`description`,`role`)?VALUES?(3,1,'test','test');
INSERT?INTO?`sys_role_permission`?VALUES?('1',?'1');
INSERT?INTO?`sys_role_permission`?(`permission_id`,`role_id`)?VALUES?(1,1);
INSERT?INTO?`sys_role_permission`?(`permission_id`,`role_id`)?VALUES?(2,1);
INSERT?INTO?`sys_role_permission`?(`permission_id`,`role_id`)?VALUES?(3,2);
INSERT?INTO?`sys_user_role`?(`role_id`,`uid`)?VALUES?(1,1);

Shiro 配置

首先要配置的是ShiroConfig類(lèi)仑撞,Apache Shiro 核心通過(guò) Filter 來(lái)實(shí)現(xiàn)赤兴,就好像SpringMvc 通過(guò)DispachServlet 來(lái)主控制一樣。 既然是使用 Filter 一般也就能猜到隧哮,是通過(guò)URL規(guī)則來(lái)進(jìn)行過(guò)濾和權(quán)限校驗(yàn)桶良,所以我們需要定義一系列關(guān)于URL的規(guī)則和訪(fǎng)問(wèn)權(quán)限。

ShiroConfig

@Configuration
public?class?ShiroConfig?{
@Bean
public?ShiroFilterFactoryBean?shirFilter(SecurityManager?securityManager)?{
????System.out.println("ShiroConfiguration.shirFilter()");
????ShiroFilterFactoryBean?shiroFilterFactoryBean?=?new?ShiroFilterFactoryBean();
????shiroFilterFactoryBean.setSecurityManager(securityManager);
????//攔截器.
????Map<String,String>?filterChainDefinitionMap?=?new?LinkedHashMap<String,String>();
????//?配置不會(huì)被攔截的鏈接?順序判斷
????filterChainDefinitionMap.put("/static/**",?"anon");
????//配置退出?過(guò)濾器,其中的具體的退出代碼Shiro已經(jīng)替我們實(shí)現(xiàn)了
????filterChainDefinitionMap.put("/logout",?"logout");
????//<!--?過(guò)濾鏈定義近迁,從上向下順序執(zhí)行艺普,一般將/**放在最為下邊?-->:這是一個(gè)坑呢,一不小心代碼就不好使了;
????//<!--?authc:所有url都必須認(rèn)證通過(guò)才可以訪(fǎng)問(wèn);?anon:所有url都都可以匿名訪(fǎng)問(wèn)-->
????filterChainDefinitionMap.put("/**",?"authc");
????//?如果不設(shè)置默認(rèn)會(huì)自動(dòng)尋找Web工程根目錄下的"/login.jsp"頁(yè)面
????shiroFilterFactoryBean.setLoginUrl("/login");
????//?登錄成功后要跳轉(zhuǎn)的鏈接
????shiroFilterFactoryBean.setSuccessUrl("/index");

????//未授權(quán)界面;
????shiroFilterFactoryBean.setUnauthorizedUrl("/403");
????shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
????return?shiroFilterFactoryBean;
}

@Bean
public?MyShiroRealm?myShiroRealm(){
????MyShiroRealm?myShiroRealm?=?new?MyShiroRealm();
????return?myShiroRealm;
}


@Bean
public?SecurityManager?securityManager(){
????DefaultWebSecurityManager?securityManager?=??new?DefaultWebSecurityManager();
????securityManager.setRealm(myShiroRealm());
????return?securityManager;
}
}

自定義realm

MyShiroRealm繼承 AuthorizingRealm,重寫(xiě)doGetAuthorizationInfo授權(quán)方法,和doGetAuthenticationInfo認(rèn)證方法。

public?class?MyShiroRealm?extends?AuthorizingRealm?{
@Resource
private?UserInfoService?userInfoService;
@Override
protected?AuthorizationInfo?doGetAuthorizationInfo(PrincipalCollection?principals)?{
????System.out.println("權(quán)限配置-->MyShiroRealm.doGetAuthorizationInfo()");
????SimpleAuthorizationInfo?authorizationInfo?=?new?SimpleAuthorizationInfo();
????UserInfo?userInfo??=?(UserInfo)principals.getPrimaryPrincipal();
????for(SysRole?role:userInfo.getRoleList()){
????????authorizationInfo.addRole(role.getRole());
????????for(SysPermission?p:role.getPermissions()){
????????????authorizationInfo.addStringPermission(p.getPermission());
????????}
????}
????return?authorizationInfo;
}

/*主要是用來(lái)進(jìn)行身份認(rèn)證的歧譬,也就是說(shuō)驗(yàn)證用戶(hù)輸入的賬號(hào)和密碼是否正確岸浑。*/
@Override
protected?AuthenticationInfo?doGetAuthenticationInfo(AuthenticationToken?token)
????????throws?AuthenticationException?{
????System.out.println("MyShiroRealm.doGetAuthenticationInfo()");
????//?獲取用戶(hù)的輸入的賬號(hào).
????String?username?=?(String)token.getPrincipal();
????//?獲取用戶(hù)的輸入的密碼
????System.out.println(token.getCredentials());
????//通過(guò)username從數(shù)據(jù)庫(kù)中查找?User對(duì)象,如果找到瑰步,沒(méi)找到.
????//實(shí)際項(xiàng)目中钞速,這里可以根據(jù)實(shí)際情況做緩存鱼炒,如果不做颈抚,Shiro自己也是有時(shí)間間隔機(jī)制娇未,2分鐘內(nèi)不會(huì)重復(fù)執(zhí)行該方法
????UserInfo?userInfo?=?userInfoService.findByUsername(username);
????System.out.println("----->>userInfo="+userInfo);
????if(userInfo?==?null){
????????return?null;
????}

????//?進(jìn)行認(rèn)證,將正確數(shù)據(jù)給shiro處理
????//?密碼不用自己比對(duì)袁滥,AuthenticationInfo認(rèn)證信息對(duì)象盖桥,一個(gè)接口,new他的實(shí)現(xiàn)類(lèi)對(duì)象SimpleAuthenticationInfo
????/*????第一個(gè)參數(shù)隨便放题翻,可以放user對(duì)象揩徊,程序可在任意位置獲取?放入的對(duì)象
?????*??第二個(gè)參數(shù)必須放密碼,
?????*??第三個(gè)參數(shù)放?當(dāng)前realm的名字嵌赠,因?yàn)榭赡苡卸鄠€(gè)realm*/
????SimpleAuthenticationInfo?authenticationInfo?=?new?SimpleAuthenticationInfo(
????????????userInfo,?//用戶(hù)名
????????????userInfo.getPassword(),?//密碼
????????????ByteSource.Util.bytes(userInfo.getSalt()),
????????????getName()??//realm?name
????);
???//清除之前的授權(quán)信息
????super.clearCachedAuthorizationInfo(authenticationInfo.getPrincipals());
????//?存入用戶(hù)對(duì)象
????SecurityUtils.getSubject().getSession().setAttribute("login",?userInfo);
????//?返回給安全管理器塑荒,securityManager,由securityManager比對(duì)數(shù)據(jù)庫(kù)查詢(xún)出的密碼和頁(yè)面提交的密碼
????//?如果有問(wèn)題姜挺,向上拋異常齿税,一直拋到控制器
????return?authenticationInfo;
}

}

AuthenticationToken

上面定義了接口源碼,主要是兩個(gè)接口炊豪,一個(gè)是獲取委托人信息凌箕,一個(gè)是獲取證明,常用的是用戶(hù)名和密碼的組合溜在。

這里AuthenticationToken只提供接口陌知,一般我們的實(shí)體類(lèi)包含了get/set方法他托,但是這里抽出了get方法掖肋,方便用戶(hù)自己擴(kuò)展所需要的實(shí)現(xiàn)。


public?interface?AuthenticationToken?extends?Serializable?{

???????Object?getPrincipal();
???????Object?getCredentials();
}


其中擴(kuò)展接口HostAuthenticationToken提供了獲取用戶(hù)客戶(hù)host的功能赏参,源代碼如下:

public?interface?HostAuthenticationToken?extends?AuthenticationToken?{
???????String?getHost();
}


RememberMeAuthenticationToken提供了記住用戶(hù)的標(biāo)識(shí):

public?interface?RememberMeAuthenticationToken?extends?AuthenticationToken?{

???????boolean?isRememberMe();

}


登錄過(guò)程其實(shí)只是處理異常的相關(guān)信息志笼,具體的登錄驗(yàn)證交給shiro來(lái)處理。

@Controller
public?class?HomeController?{

@RequestMapping({"/","/index"})
public?String?index(){
?????????return"/index";
}

@RequestMapping("/login")
public?String?login(HttpServletRequest?request,?Map<String,?Object>?map)?throws?Exception{
????System.out.println("HomeController.login()");
????//?登錄失敗從request中獲取shiro處理的異常信息把篓。
????//?shiroLoginFailure:就是shiro異常類(lèi)的全類(lèi)名.
????String?exception?=?(String)?request.getAttribute("shiroLoginFailure");
????System.out.println("exception="?+?exception);
????String?msg?=?"";
????if?(exception?!=?null)?{
????????if?(UnknownAccountException.class.getName().equals(exception))?{
????????????System.out.println("UnknownAccountException?--?>?賬號(hào)不存在:");
????????????msg?=?"UnknownAccountException?--?>?賬號(hào)不存在:";
????????}?else?if?(IncorrectCredentialsException.class.getName().equals(exception))?{
????????????System.out.println("IncorrectCredentialsException?--?>?密碼不正確:");
????????????msg?=?"IncorrectCredentialsException?--?>?密碼不正確:";
????????}?else?if?("kaptchaValidateFailed".equals(exception))?{
????????????System.out.println("kaptchaValidateFailed?--?>?驗(yàn)證碼錯(cuò)誤");
????????????msg?=?"kaptchaValidateFailed?--?>?驗(yàn)證碼錯(cuò)誤";
????????}?else?{
????????????msg?=?"else?>>?"+exception;
????????????System.out.println("else?--?>"?+?exception);
????????}
????}
????map.put("msg",?msg);
????//?此方法不處理登錄成功,由shiro進(jìn)行處理
????return?"/login";
}

@RequestMapping("/403")
public?String?unauthorizedRole(){
????System.out.println("------沒(méi)有權(quán)限-------");
????return?"403";
}
}

其它dao層和service的代碼就不貼出來(lái)了大家直接看代碼纫溃。


登錄頁(yè)面



登錄成功會(huì)跳轉(zhuǎn) index 頁(yè)面,如果錯(cuò)誤會(huì)返回錯(cuò)誤信息韧掩。

上面這些操作時(shí)候觸發(fā)MyShiroRealm.doGetAuthorizationInfo()這個(gè)方法紊浩,也就是權(quán)限校驗(yàn)的方法。

可以在數(shù)據(jù)庫(kù)中修改不同的權(quán)限進(jìn)行測(cè)試,demo中有對(duì)用戶(hù)的增刪查改坊谁,就不展示了费彼,大家可以下載demo運(yùn)行。

shiro很強(qiáng)大口芍,這僅僅是完成了登錄認(rèn)證和權(quán)限管理箍铲、用戶(hù)管理的增刪查改。


github地址:

https://github.com/xiaonongOne/springboot-shiro



?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末鬓椭,一起剝皮案震驚了整個(gè)濱河市颠猴,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌小染,老刑警劉巖翘瓮,帶你破解...
    沈念sama閱讀 212,383評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異裤翩,居然都是意外死亡春畔,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)岛都,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)律姨,“玉大人,你說(shuō)我怎么就攤上這事臼疫≡穹荩” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,852評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵烫堤,是天一觀(guān)的道長(zhǎng)荣赶。 經(jīng)常有香客問(wèn)我,道長(zhǎng)鸽斟,這世上最難降的妖魔是什么拔创? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,621評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮富蓄,結(jié)果婚禮上剩燥,老公的妹妹穿的比我還像新娘。我一直安慰自己立倍,他們只是感情好灭红,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,741評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著口注,像睡著了一般变擒。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上寝志,一...
    開(kāi)封第一講書(shū)人閱讀 49,929評(píng)論 1 290
  • 那天娇斑,我揣著相機(jī)與錄音策添,去河邊找鬼。 笑死毫缆,一個(gè)胖子當(dāng)著我的面吹牛舰攒,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播悔醋,決...
    沈念sama閱讀 39,076評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼摩窃,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了芬骄?” 一聲冷哼從身側(cè)響起猾愿,我...
    開(kāi)封第一講書(shū)人閱讀 37,803評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎账阻,沒(méi)想到半個(gè)月后蒂秘,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,265評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡淘太,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,582評(píng)論 2 327
  • 正文 我和宋清朗相戀三年姻僧,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蒲牧。...
    茶點(diǎn)故事閱讀 38,716評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡撇贺,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出冰抢,到底是詐尸還是另有隱情松嘶,我是刑警寧澤,帶...
    沈念sama閱讀 34,395評(píng)論 4 333
  • 正文 年R本政府宣布挎扰,位于F島的核電站翠订,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏遵倦。R本人自食惡果不足惜尽超,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,039評(píng)論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望梧躺。 院中可真熱鬧似谁,春花似錦、人聲如沸燥狰。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,798評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)龙致。三九已至,卻和暖如春顷链,著一層夾襖步出監(jiān)牢的瞬間目代,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,027評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留榛了,地道東北人在讶。 一個(gè)月前我還...
    沈念sama閱讀 46,488評(píng)論 2 361
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像霜大,于是被迫代替她去往敵國(guó)和親构哺。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,612評(píng)論 2 350

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

  • Shiro 簡(jiǎn)介 照例又去官網(wǎng)扒了扒介紹: Apache Shiro? is a powerful and eas...
    我沒(méi)有三顆心臟閱讀 10,364評(píng)論 7 32
  • ORA-00001: 違反唯一約束條件 (.) 錯(cuò)誤說(shuō)明:當(dāng)在唯一索引所對(duì)應(yīng)的列上鍵入重復(fù)值時(shí),會(huì)觸發(fā)此異常途茫。 O...
    我想起個(gè)好名字閱讀 5,256評(píng)論 0 9
  • 安全應(yīng)該是互聯(lián)網(wǎng)公司的一道生命線(xiàn)碟嘴,幾乎任何的公司都會(huì)涉及到這方面的需求。在Java領(lǐng)域一般有Spring Secu...
    滄海一粟謙閱讀 2,451評(píng)論 0 3
  • title: 初識(shí)Shirotags: shirocategories: shiro 若圖片無(wú)法顯示囊卜,請(qǐng)前往我的博...
    codingXiaxw閱讀 573評(píng)論 1 0
  • 今天跟十一局的王孟吃了個(gè)飯娜扇,又聽(tīng)到一個(gè)安全的事故,安全警鐘要長(zhǎng)敲栅组。 晚上開(kāi)始雀瓢,看球模式。要辛苦一個(gè)月了玉掸。旗開(kāi)得勝致燥,...
    伏伏王閱讀 134評(píng)論 0 0