Apache Shiro 提供的Web支持--官网

Apache Shiro 的Web支持

配置

将Shiro集成到web项目中最简单的方式就是在web.xml中配置一个ServletContextListener和过滤器,让Web项目知道如何读取Shiro的INI配置文件。关于INI配置文件的内容,在前面有描述,这里将会讲述一些Web相关的小节

如果使用了Spring框架,将不需要考虑这一步,详情请看Spring集成Shiro的相关文档

web.xml

Shiro1.2及以后

Shiro1.2及之后的版本中,标准的Web应用程序集成Shiro,就是将下列的xml内容添加到web.xml中:

<listener>
    <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
</listener>

...

<filter>
    <filter-name>ShiroFilter</filter-name>
    <filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>ShiroFilter</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>INCLUDE</dispatcher>
    <dispatcher>ERROR</dispatcher>
</filter-mapping>

如果没有显式配置INI配置文件的位置,Shiro将会按照下面的顺序找配置文件,使用第一个找到的配置文件:

  1. /WEB-INF/shiro.ini
  2. 类路径的根路径下的shiro.ini

以上的配置其实是做了以下的事:

  • EnvironmentLoaderListener会初始化一个Shiro的WebEnvironment实例(该实例包含了Shiro需要的所有东西,包括SecurityManager),并将这个实例设置到了ServletContext中使其可用。如果需要获取这个WebEnvironment实例,可以通过WebUtils.getRequiredWebEnvironment(servletContext)获得
  • ShiroFilter将会通过WebEnvironment来执行所有的安全相关操作
  • 最后,filter-mapping定义确保了所有的请求都能经过ShiroFilter的过滤

通常需要把ShiroFilterfilter-mapping定义在所有的filter-mapping之前,确保Shiro也能作用在其他过滤器之中

ShiroFilter是一个标准的servlet过滤器,它的默认编码是ISO-8859-1,然而客户端可以通过使用请求头的Content-Type头部的charset属性来指定编码

自定义 WebEnvironment 类

EnvironmentLoaderListener将默认创建的是IniWebEnvironment实例,顾名思义是通过INI配置Shiro。如果有需要,可以在web.xml中为ServletContext指定一个context-param参数,来指定WebEnvironment

<context-param>
    <param-name>shiroEnvironmentClass</param-name>
    <param-value>com.foo.bar.shiro.MyWebEnvironment</param-value>
</context-param>

这种方式可以让我们自定义Shiro配置的格式,并将其解析为一个WebEnvironment实例,可以继承IniWebEnvironment来继续使用ini的配置格式,或者完全自定义配置格式

配置文件路径

IniWebEnvironment类需要读取INI配置文件才能配置Shiro,默认情况下,这个类将会自动的从以下两个位置顺序的寻找配置文件,只要找到了配置文件就会使用它(如果同时在两个位置都有配置文件,则会使用第一个/WEB-INF/shiro.ini

  1. /WEB-INF/shiro.ini
  2. classpath:shiro.ini

可以在web.xml中配置一个context-param来指定配置文件的位置

<context-param>
    <param-name>shiroConfigLocations</param-name>
    <param-value>YOUR_RESOURCE_LOCATION_HERE</param-value>
</context-param>

默认情况下,这个参数值会按照ServletContext.getResource()方法来解析,如"/WEB-INF/some/path/shiro.ini"。Shiro的ResourceUtils类也支持"url:""file:"这样的资源路径前缀来指定路径,下面的路径也是可以使用的

  • file:/home/foobar/myapp/shiro.ini
  • classpath:com/foo/bar/shiro.ini
  • url:http://confighost.mycompany.com/myapp/shiro.ini

Shiro1.1及之前

Web应用集成Shiro1.1及之前版本,最简单的就是定义IniShiroFilter及其相关filter-mapping

<filter>
    <filter-name>ShiroFilter</filter-name>
    <filter-class>org.apache.shiro.web.servlet.IniShiroFilter</filter-class>
</filter>

...

<!-- Make sure any request you want accessible to Shiro is filtered. /* catches all -->
<!-- requests.  Usually this filter mapping is defined first (before all others) to -->
<!-- ensure that Shiro works in subsequent filters in the filter chain:             -->
<filter-mapping>
    <filter-name>ShiroFilter</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>INCLUDE</dispatcher>
    <dispatcher>ERROR</dispatcher>
</filter-mapping>

以上定义要求INI配置,且INI配置文件在类路径的根路径下,即classpath:shiro.ini。注意这里放在/WEB-INF/下面无效

配置文件路径

如果不想让INI配置文件放在classpath:shiro.ini,也可以指定一个资源文件路径。需要为ShiroFilter添加一个configPath参数

<filter>
    <filter-name>ShiroFilter</filter-name>
    <filter-class>org.apache.shiro.web.servlet.IniShiroFilter</filter-class>
    <init-param>
        <param-name>configPath</param-name>
        <param-value>classpath:anotherFile.ini</param-value>
    </init-param>
</filter>

...

请注意,ServletContext 资源路径是在Shiro1.2及之后可用的,在1.1及之前的版本中,所有的configPath定义都需要指定classpath:file:或者url:前缀,也就是说,这里不能写/WEB-INF/shiro.ini,就算写了也会没有效果。官网写的有点模糊,试了下,应该是这样

在web.xml文件中嵌入Shiro配置

可以使用名为configinit-param的参数设置,将INI配置嵌入到web.xml中,这样就不需要使用额外的ini配置文件了

<filter>
    <filter-name>ShiroFilter</filter-name>
    <filter-class>org.apache.shiro.web.servlet.IniShiroFilter</filter-class>
    <init-param><param-name>config</param-name><param-value>

    # INI Config Here

    </param-value></init-param>
</filter>
...

这种配置方式比较适用于小的,简单的应用,但出于以下原因,将其放到专门的shiro.ini文件中通常更为方便:

  • 你可能会频繁修改安全的配置,这会为web.xml增加一个版本控制噪声
  • 你可能想要将安全相关的配置从web.xml中分离出来
  • 你可能需要写很多Shiro的相关配置,如果写了太多,反而会让web.xml文件过于臃肿
  • 相同的Shiro配置需要用在多个部分时

Web相关的INI配置项

[main][users][roles]小节前面已经讲述过了,这里重点介绍Web项目特有的[urls]小节

# [main], [users] and [roles] above here
...
[urls]
...

[urls]小节允许你为你的应用程序中任何匹配的URL路径定义专门的过滤器链的能力,这比在web.xml中定义过滤器链的方式更加灵活、强大和简洁,即使只使用这个特性,它也值得一用

[urls]

URL路径表达式

[urls] 小节的每一行遵从以下格式:

_URL_Ant_Path_Expression_ = _Path_Specific_Filter_Chain_

例如:

...
[urls]

/index.html = anon
/user/create = anon
/user/** = authc
/admin/** = authc, roles[administrator]
/rest/** = authc, rest
/remoting/rpc/** = authc, perms["remote:invoke"]

等号左边的是一个Ant风格的路径表达式,注意,所有的路径表达式都是从应用程序环境中的根目录开始匹配的,也就是说,如果你的部署从www.somehost.com/myapp换成了www.anotherhost.com,配置不需要更改,依然有效。所有的路径都是相对于HttpServletRequest.getContextPath()的值

到来的请求会按照urls定义的顺序来匹配,第一个匹配的配置项则为该路径需要通过的过滤器链。假如有如下配置

/account/** = ssl, authc
/account/signup = anon

则请求路径/account/signup将永远不会被正确的处理(匿名可访问),应为第一条配置项/account/**已经匹配了这个请求,后面的就没用了

过滤器链定义

等号右边就是以逗号风格的过滤器链,它的格式如下

filter1[optional_config1], filter2[optional_config2], ..., filterN[optional_configN]
  • filterNFilter[main]小节中定义的名字
  • [optional_config]是一个带括号的可选字符串,它只对部分路径的部分过滤器有意义,如果过滤器不需要这个特定的配置,可以放弃方括号,这样filter[]就变成了filter

请求通过过滤链的顺序就是它们在配置文件中定义的顺序。

响应也会通过这个过滤器链,如果没有满足必要条件(例如执行重定向、响应带有HTTP错误代码、直接呈现等),每个过滤器都可以自由地处理响应。否则,它将允许请求继续通过链到达最终目标视图

通过[optional_configN]能够对特定路径配置做出反应,这是Shiro的独特特性,如果你想要创建一个能做到这些功能的javax.servlet.Filter实现,需要确保其继承了org.apache.shiro.web.filter.PathMatchingFilter

可用的过滤器

[main]小节中可以定义需要使用的过滤器,其中定义的名字就是在过滤器链的定义中需要使用的名字,如下所示

[main]
...
myFilter = com.company.web.some.FilterImplementation
myFilter.property1 = value1
...

[urls]
...
/some/path/** = myFilter

默认过滤器

当运行一个web应用的时候,Shiro默认会创建一些有用的过滤器实例,我们可以在[main]小节中直接使用这些实例,也可以在[main]小节中对它们进行配置,就和其他定义的bean一样

[main]
...
# 我们并没有定义FormAuthenticationFilter ('authc'),这是Shiro自动定义好的
authc.loginUrl = /login.jsp
...

[urls]
...
# 如果用户没有经过认证,则防止这个URL时将会重定向到authc.loginUrl配置的路径,之后如果用户通过了认证,则将会回到原来的页面
/account/** = authc
...

以下是Shiro自动定义好的过滤器及其在main中可用的名字

名字
anno org.apache.shiro.web.filter.authc.AnonymousFilter
authc org.apache.shiro.web.filter.authc.FormAuthenticationFilter
authcBasic org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter
authcBearer org.apache.shiro.web.filter.authc.BearerHttpAuthenticationFilter
invalidRequest org.apache.shiro.web.filter.InvalidRequestFilter
logout org.apache.shiro.web.filter.authc.LogoutFilter
noSessionCreation org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter
perms org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter
port org.apache.shiro.web.filter.authz.PortFilter
rest org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter
roles org.apache.shiro.web.filter.authz.RolesAuthorizationFilter
ssl org.apache.shiro.web.filter.authz.SslFilter
user org.apache.shiro.web.filter.zuthc.UserFilter

开启和关闭过滤器

在过滤器链中开启或关闭一个过滤器最直接的方式,就是通过将其从过滤器链定义中添加或删除其名字。但是在Shiro1.2之后新增加了一个特性,可以不用通过前面那种方式就能开启或关闭过滤器,可以通过一个配置的属性来判断是否开启过滤器,甚至也可以通过每一个请求来判断

Shiro提供了一个OncePerRequestFilter的抽象类,所有的继承它的过滤器都可以在不将其从过滤器链中删除的情况下控制其是否生效,我们也可以继承这个类来实现这个功能

一般的开启和关闭

OncePerRequestFilter的开关可以对所有的请求生效,也可以对基于某一个请求生效。设置enabled属性为true或false就可以设置它的开关,该属性的默认值为true,因此大多数过滤器都是开启状态的

[main]
...
# 配置ssl过滤器失效
ssl.enabled = false

[urls]
...
/some/path = ssl, authc
/another/path = ssl, roles[admin]
...

绝大多数情况下,URL都是配置了SSL的,如果在开发时还开启了SSL,那是很难受的,所以可以先将其关闭,在生产环境下再把它开起来

根据请求

OncePerRequestFilter还可以通过它的isEnable(request, response) 方法来对每一个请求进行检查,判断是否需要经过该过滤器过滤。该方法的默认实现是直接返回enable属性,也就是说,本质上OncePerRequestFilter就是通过isEnable方法来判断是否开启该过滤器的。我们可以通过重写这个isEnable(request, response)来进行更细致的检查

根据路径

Shiro的PathMatchingFilterOncePerRequestFilter的子类)拥有对特定路径的请求进行过滤的能力,也就是说,可以对一个请求的路径来判断是否开启过滤器。如果你的过滤器需要这种能力,则可以重写PathMatchingFilterisEnabled(request, response, path, pathConfig)方法

全局过滤器

Shiro1.6开始,可以定义一个一条全局过滤器链,它将会作用于所有的路由,包括哪些没有配置过滤器链的路由。默认情况下,这个全局过滤器链包含了invalidRequest过滤器(上面的表格中有),这个过滤器是负责过滤掉无效请求的,可以阻挡一些恶意攻击

全局过滤器链的配置和关闭如下

[main]
...
# 关闭全局过滤器链
filterChainResolver.globalFilters = null

定义一条全局过滤器链

[main]
...
filterChainResolver.globalFilters = invalidRequest, port

invalidRequest过滤器会阻塞使用非ascii字符、分号和反斜杠的请求,可以单独禁用其中的每一个,以便于向后兼容

[main]
...
invalidRequest.blockBackslash = true
invalidRequest.blockSemicolon = true
invalidRequest.blockNonAscii = true
...

如果你的应用程序允许在URL中重写jsessionid,那么必须将blockSemicolon设置为false

HSTS

SslFilter及其所有的子类,支持HSTS的概念,我们可以开启或关闭HSTS

[main]
...
# 配置ssl过滤器开启HSTS
ssl.enabled = true
ssl.hsts.enabled = true
ssl.hsts.includeSubDomains = true

[urls]
...
/some/path = ssl, authc
/another/path = ssl, roles[admin]
...

会话管理

Servlet容器会话

在Web环境下,Shiro的默认会话管理器是ServletContainerSessionManager,Shiro会把所有的会话管理都委托给Servlet容器(包括会话集群,如果Servlet容器支持的话)。这是一个Shiro的SessionAPIServlet容器的桥梁

这种方式的好处就是,应用程序可以使用Servlet容器的配置,如会话超时,容器的集群设置等等。缺点就是应用程序和Servlet容器绑定了,比如如果开发环境使用的是Jetty,生产环境使用Tomcat,那么一些特定于容器的配置将会需要更改

Servlet容器会话的超时时间

如果使用Servlet容器来管理会话的话,则可以在web.xml中配置会话超时时间

<session-config>
    <!-- 配置会话超时时间为30分钟 -->
    <session-timeout>30</session-timeout>
</session-config>

原生会话

如果想要会话的配置能够跨Servlet容器生效的话,应该使用Shiro的原生会话管理。“原生”意味着使用Shiro自己的企业会话管理,这样可以完全地支持SubjectHttpServletRequest会话,完全绕过Servlet容器。请放心,Shiro直接实现了Servlet规范的相关部分,因此任何现有的Web/HTTP相关代码都可以按预期工作,对于它们来说,Shiro是透明的

DefaultWebSessionManager

在web应用中开启Shiro的原生会话管理,只需要为SecurityManager配置一个DefaultWebSessionManager实例即可,如下

[main]
...
sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager
# 如果需要的话,在这里配置属性

# 使用配置好的原生会话管理器
securityManager.sessionManager = $sessionManager

可以为DefaultWebSessionManager实例配置所有原生会话的配置选项,如超时时间和集群配置等

原生会话的超时时间

在配置了DefaultWebSessionManager实例后,可以像前面介绍会话管理那样设置会话超时时间

会话Cookie

DefaultWebSessionManager有两个Web相关的配置属性:

  • sessionIdCookieEnabled——一个布尔属性
  • sessionIdCookie,一个Cookie实例

sessionIdCookie属性是一个Cookie实例,它作为一个模板,这个模板会被用来在运行时使用适当的会话ID值设置实际的HTTP ‘Cookie '头。

会话Cookie配置

DefaultWebSessionManagersessionIdCookie的默认是一个SimpleCookie实例,它是一个JavaBean的形式来设置相关属性值

[main]
...
securityManager.sessionManager.sessionIdCookie.domain = foo.com

查看SimpleCookie的Java文档查看更多信息

根据Servlet规范,cookie的默认名是JSESSIONID,Shiro还支持HttpOnly和SameSite标识,为了安全性,sessionIdCookie默认将会设置HttpOnlytrue,设置SameSiteLAX

关闭会话的Cookie

如果不想使用会话Cookie,可以通过sessionIdCookieEnabled属性值,将其设置为false

[main]
...
securityManager.sessionManager.sessionidCookieEnabled = false

“记住我”功能

如果AuthenticationToken实现了org.apache.shiro.authc.RememberMeAuthenticationToken接口,那Shiro将会根据接口的方法来判断是否提供”记住我“服务

boolean isRememberMe();

如果这个方法返回true,那Shiro将会跨会话的记住终端用户的标识

UsernamePasswordToken 和 记住我

最常用的UsernamePasswordToken已经实现了RememberMeAuthenticationToken接口,支持”记住我“服务

编程式配置

可以通过将登陆时使用的RememberMeAuthenticationToken或其子类的rememberMe属性值设置为true来开启”记住我“服务,如下

UsernamePasswordToken token = new UsernamePasswordToken(username, password);

token.setRememberMe(true);

SecurityUtils.getSubject().login(token);
...

基于表单的登录

在Web应用程序中,authc过滤器默认是一个FormAuthenticationFilter,它能够读取请求参数中的rememberMe参数,默认情况下参数名就是rememberMe

[main]
authc.loginUrl = /login.jsp

[urls]
# 登陆页面
login.jsp = authc
# 这样设置真的不会陷入死循环吗?

在你的Web表单中,添加一个名为rememberMecheckbox

<form ...>
    Username: <input type="text" name="username"/> <br/>
    Password: <input type="password" name="password" />
    ...
    <input type="checkbox" name="rememberMe" value="true"/> Remember Me?
    ...
</form>

默认情况下,FormAuthenticationFilter将会寻找名为usernamepasswordrememberMe的请求参数,可以配置FormAuthenticationFilter来自定义参数名字

[main]
...
authc.loginUrl=/whatever.jsp
authc.usernameParam=somethingOtherThanUsername
authc.passwordParam=somethingOtherThanPassword
authc.rememberMeParam=somethingOtherThanRememberMe
...

Cookie配置

还可以设置rememberMecookie如何生效

[main]
...
securityManager.rememberMeManager.cookie.name = foo
securityManager.rememberMeManager.cookie.maxAge = blah
...

详情可以看CookieRememberMemanagerSimpleCookieJavaDoc

自定义RememberMeManager

如果默认的RememberMeManager实现不能满足你的需求,也可以自定义

[main]
...
rememberMeManager = com.my.impl.RememberMeManager
securityManager.rememberMeManager = $rememberMeManager
...

JSP/GSP标签库

Apache Shiro提供了一个Subject可以感知的JSP/GSP标记库,允许根据当前Subject状态控制JSP,JSTL或GSP页面输出。 对于基于当前用户查看网页的特定用户的身份和授权状态,这对于个性化视图非常有用

标签库配置

JSP/GSP的标签库描述文件(TLD)是在shiro-web.jar中的META-INF/shiro.tld的,在JSP页面中添加下面这一行来使用标签

<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>

我们将会使用shiro前缀最为Shiro标签库的命名空间,当然可以使用自己喜欢的前缀

下面来介绍一些标签

guest

guest包裹的内容,只会展示给那些未登录的用户

<shiro:guest>
    这里是未登录的游客才能看到的东西
</shiro:guest>

guest标签的对立面即为user标签

user

guest相反,user标签包裹的内容只会展示给那些登录的用户,其中包括在之前的会话中被记住的用户,注意这个标签和authenticated标签是不一样的,后者更为严格

<shiro:user>
    这里是展示给登录的用户的
</shiro:user>

该标签和guest标签相反

authenticated

只有当前Subject是已认证的,才会展示该标签包裹的内容。注意它和user标签的区别,具体参考之前描述的已认证和已记住两个状态

<shiro:authenticated>
    这里是已认证的用户才能看到的
</shiro:authenticated>

该标签和notAuthenticated是相反的

notAuthenticated

该标签包裹的内容只会展示给那些未认证的Subject

<shiro:notAuthenticated>
    这里是未认证的用户才能看到的
</shiro:notAuthenticated>

该标签和authenticated相反

principal

principal 标签将会输出Subjectprincipal信息(即用户的身份信息)或者其属性。如果没有指定输出哪个标签属性,该标签将会输出principaltoString()方法,如

<shiro:principal/>

和下面的输出结果是一样的

<%= SecurityUtils.getSubject().getPrincipal().toString() %>

根据类型选择principal

principal标签默认是输出subject.getPrincipal()值,如果想要输出的不是primary principal,而是Subject的其他principal,可以通过principal的类型来选择输出

<principal type="java.lang.Integer" />

上面的标签和下面的输出是一样的

<%= SecurityUtils.getSubject().getPrincipals().oneByType(Integer.class).toString() %>

Principal的属性

如果principal是一个复杂类型的数据,而不是一个简单的字符串,我们还可以通过property属性来指定输出principal的哪个属性值

<shiro:principal property="firstName" />

下面是它的等效结果

<%= SecurityUtils.getSubject().getPrincipal().getFirstName().toString() %>

还可以结合Principal的类型进行输出

<shiro:principal type="com.foo.User" property="firstname"/>

它和下面的输出是一样的

<%= SecurityUtils.getSubject().getPrincipals().oneByType(com.foo.User.class).getFirstName().toString() %>

hasRole

该标签包裹的内容只会展示给具有特定角色的用户

<shiro:hasRole name="administrator">
    只有拥有administrator角色的用户才能看到
</shiro:hasRole>

该标签和lacksRole标签相反

lacksRole

该标签包裹的内容只会展示给不具有特定角色的用户

<shiro:lacksRole name="administrator">
    只有没有administrator角色的用户才能看到
</shiro:lacksRole>

该标签与hasRole标签相反

hasAnyRole

该标签包裹的内容,只有那些具有指定角色集合的其中一个角色才能看到

<shiro:hasAnyRoles name="developer, project manager, administrator" >
    需要具有developer,project manager,administrator至少一个角色的用户的才能看到
</shiro:hasAnyRoles>

该标签没有逻辑上相反的标签

hasPermission

参考hasRole

<shiro:hasPermission name="user:create">
    内容
</shiro:hasPermission>

lacksPermission

参考lacksRole

<shiro:lacksPermission name="user:delete">
    内容
</shiro:lacksPermission>
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容

  • 说明:本文很多观点和内容来自互联网以及各种资料,如果侵犯了您的权益,请及时联系我,我会删除相关内容。 权限管理 基...
    寇寇寇先森阅读 7,574评论 8 76
  • Shiro 会话管理 Apache Shiro 提供了一个非常独特的特性,即完整的企业级会话解决方案,既适用于最简...
    szn0108阅读 669评论 0 1
  • 前言 接上篇,关于Shiro框架的学习(一),这篇会记录下Shiro整合Web、整合SSM的过程,之后就可以直接应...
    ObjectSpace阅读 443评论 0 1
  • Simple 简单易用 Java Java Security 安全Shiro是什么? 是Apache 下的...
    12345_5854阅读 192评论 0 0
  • 1.权限的管理 1.1什么是权限管理? 基本上涉及到用户参与的系统都要有权限管理,权限管理属于系统的安全范畴,权限...
    忒无聊了叭阅读 395评论 0 0