配置
将Shiro集成到任何Web应用程序的最简单方法就是是在web.xml中配置Servlet ContextListener和Filter,它们了解如何读取Shiro的INI配置。大部分INI配置格式已经在Shiro中的配置详解中提到,所以我们将在此处介绍一些特定于Web的其他部分。
web.xml
Shiro 1.2及以后
在Shiro 1.2及更高版本中,标准Web应用程序通过将添加到以下内容到XML块中来初始化Shiro:
<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>
上面写法是基于Shiro的INI配置文件出现在以下两种位置:
- /WEB-INF/shiro.ini
- shiro.ini 文件位于classpath的根目录。
以下是上面的配置详解:
-
在
EnvironmentLoaderListener
初始化Shiro的WebEnvironment
实例(包含一切Shiro操作所需要的东西,其中包括SecurityManager
),并使其在ServletContext
中可被访问。如果您需要获取此WebEnvironment
实例,可以通过WebUtils.getRequiredWebEnvironment(servletContext)
方法调用。 -
ShiroFilter将使用这个WebEnvironment来执行所有必要的安全操作来过滤请求。
-
最后,该filter-mapping定义确保所有请求都被ShiroFilter过滤。
自定义WebEnvironment类
默认情况下,EnvironmentLoaderListener
将创建一个IniWebEnvironment实例
,该实例来自于Shiro的INI的配置。您也可以在web.xml
的ServletContext context-param
中自定义一个WebEnvironment
实例:
<context-param>
<param-name>shiroEnvironmentClass</param-name>
<param-value>com.foo.bar.shiro.MyWebEnvironment</param-value>
</context-param>
这允许您自定义如何解析配置格式并将其表示为WebEnvironmen
t实例。您可以基于现有的IniWebEnvironment
实现创建一个子类,或者完全支持不同的配置格式。例如,如果有人想用XML而不是INI配置Shiro,他们可以创建一个基于XML的实现,例如com.foo.bar.shiro.XmlWebEnvironment
。
自定义配置位置
IniWebEnvironment
会在以下两个位置中读取并加载INI配置文件:
- /WEB-INF/shiro.ini
- classpath:shiro.ini
谁先背发现则会使用谁。然而,如果您想自定义INI文件的位置,可以在web.xml
中的context-param
中定义:
<context-param>
<param-name>shiroConfigLocations</param-name>
<param-value>YOUR_RESOURCE_LOCATION_HERE</param-value>
</context-param>
默认情况下,param-value
预期可以通过ServletContext.getResource
方法定义的规则进行解析。例如,/WEB-INF/some/path/shiro.ini
但您也可以使用Shiro的ResourceUtils
类去通过检测适当的资源前缀来指定特定的文件系统,类路径或URL位置,例如:
- file:/home/foobar/myapp/shiro.ini
- classpath:com/foo/bar/shiro.ini
- url:http://confighost.mycompany.com/myapp/shiro.ini
Shiro 1.1及更早版本
在1.1或更早版本的Web应用程序中启用Shiro的最简单方法是定义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配置位于类路径根目录下的shiro.ini
文件中(例如classpath:shiro.ini
)。
自定义路径
如果你不想把你的INI配置放在/WEB-INF/shiro.ini
或者classpath:shiro.ini
中,你可以自定义资源的位置并根据需要指定。添加configPath init-param
并指定资源位置:
<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>/WEB-INF/anotherFile.ini</param-value>
</init-param>
</filter>
...
Shiro 1.2及更高版本中提供了ServletContext资源路径。在1.1和更早的版本中,所有configPath定义必须指定classpath:,file:或url:前缀:
...
<init-param>
<param-name>configPath</param-name>
<param-value>url:http://configHost/myApp/shiro.ini</param-value>
</init-param>
...
内联配置
最后,还可以在不使用INI文件的情况下将您的INI配置嵌入到web.xml中。您可以使用config init-param
而不是configPath
:
<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 INI配置
除了标准[main]
,[users]
和[roles]
在配置章节中已经说明,你还可以在shiro.ini文件中指定一个特定的网络[urls]部分:
# [main], [users] and [roles] above here
...
[urls]
...
该[urls]部分允许您执行我们已经看到的Web框架中不存在的内容:为应用程序中的任何URL路径匹配定义的过滤器链的能力!
[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"]
接下来,我们详细介绍这些行的含义。
相对于等号(=)左侧的标记是Web应用程序的上下文根的Ant风格的路径表达式。
例如,假设您有以下[urls]
行:
/account/** = ssl, authc
此行指出:访问我的应用程序的请求/account或任何的它的子路径(/account/foo,/account/bar/baz等)都将触发‘SSL,authc’过滤器链”。我们将在下面介绍过滤器链。
请注意,所有路径表达式都与应用程序的上下文根无关。
过滤链定义
等号(=)右侧的标记是逗号分隔的过滤器列表,用于匹配该路径的请求。它必须符合以下格式:
filter1[optional_config1], filter2[optional_config2], ..., filterN[optional_configN]
其中:
- filterN是
[main]
节中定义的过滤器bean的名称 [optional_configN]
括号中是一个可选的的字符串,对于该特定路径的特定过滤器具有意义。如果过滤器不需要该URL路径的特定配置,您可以丢弃括号,filterN[]
只需变为filterN
。
并且因为过滤器令牌定义了链(也就是列表),所以请记住顺序很重要!请求流经过过滤器链的顺序会遵循逗号分隔的列表的顺序。
最后,如果不满足其必要条件,每个过滤器都可以自由地处理响应(例如,执行重定向,使用HTTP错误代码进行响应,直接呈现等)。否则,允许请求通过过滤器链并到达最终目标视图。
可用过滤器
可用于过滤器链定义的过滤器“池”在本[main]
节中定义。在[main]
部分中分配给它们的名称是在过滤器链定义中使用的名称。例如:
[main]
…
myFilter = com.company.web.some.FilterImplementation
myFilter.property1 = value1
…
[urls]
…
/some/path/** = myFilter
默认过滤器
运行Web应用程序时,Shiro默认将创建一些有用的Filter
实例,并自动在[main]
部分中使用它们。您可以像配置main
中的任何其他bean
一样配置它们,并在链定义中引用它们。例如:
[main]
...
# Notice how we didn't define the class for the FormAuthenticationFilter ('authc') - it is instantiated and available already:
authc.loginUrl = /login.jsp
...
[urls]
...
# make sure the end-user is authenticated. If not, redirect to the 'authc.loginUrl' above,
# and after successful authentication, redirect them back to the original account page they
# were trying to view:
/account/** = authc
...
自动可用的默认过滤器实例由DefaultFilter
枚举定义,枚举的name
字段是可用于配置的名称。他们是:
过滤器名称 | 类 |
---|---|
anon | org.apache.shiro.web.filter.authc.AnonymousFilter |
authc | org.apache.shiro.web.filter.authc.FormAuthenticationFilter |
authcBasic | org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter |
logout | org.apache.shiro.web.filter.authc.LogoutFilter |
noSessionCreation | org.apache.shiro.web.filter.session.NoSessionCreationFilter |
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.authc.UserFilter |
会话管理
Servlet容器会话
在Web环境中,Shiro的默认会话管理器SessionManager
实现是ServletContainerSessionManager
。这个非常简单的实现将所有会话管理职责(包括servlet容器支持的会话集群)委托给运行时Servlet容器。它本质上是Shiro的servlet容器的会话API的桥梁。
使用此默认值的好处是,使用现有servlet容器会话配置(超时,任何特定于容器的群集机制等)的应用程序将按预期工作。
这个默认值的缺点是你被绑定到servlet容器的特定会话行为。例如,如果要集群会话,但是在生产中使用Jetty进行测试和使用Tomcat,则特定于容器的配置(或代码)将不可移植。
Servlet容器会话超时
如果使用默认的servlet容器支持,则在Web应用程序的web.xml文件中按预期配置会话超时。例如:
<session-config>
<!-- web.xml expects the session timeout in minutes: -->
<session-timeout>30</session-timeout>
</session-config>
原生会话
如果您希望会话配置和集群的设置可以跨servlet容器移植(例如测试中的Jetty,但生产中是Tomcat或JBoss),或者您希望控制特定的会话/群集功能,则可以启用Shiro的本机会话管理。
这里的“Native”一词意味着Shiro可以在自己的企业会话管理中实现用于支持所有Subject
和HttpServletRequest
的会话并完全绕过servlet容器。但请放心–Shiro直接实现了Servlet规范的相关部分,因此任何现有的Web / http相关代码都能按预期工作,并且永远不需要“知道”Shiro在透明地管理会话。
DefaultWebSessionManager
要为Web应用程序启用本机会话管理,您需要配置一个支持本机Web的会话管理器来覆盖默认的基于servlet容器的会话管理器。您可以通过配置DefaultWebSessionManagerShiro
的实例来实现SecurityManager
。例如,在shiro.ini:
[main]
...
sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager
# configure properties (like session timeout) here if desired
# Use the configured native session manager:
securityManager.sessionManager = $sessionManager
声明后,您可以配置DefaultWebSessionManager
实例来使用本地会话选项配置,如会话超时和集群配置等。
本机会话超时
配置DefaultWebSessionManager
实例后,会话超时的配置如上文容器超市中显示的一样。
在DefaultWebSessionManager
中支持两个特定的网络配置属性:
- sessionIdCookieEnabled (布尔值)
- sessionIdCookie,一个Cookie实例。
DefaultWebSessionManager
的sessionIdCookie
默认实例是 SimpleCookie
。这个简单的实现允许您希望在http Cookie上配置的所有相关属性的JavaBeans样式属性配置。
例如,您可以设置Cookie域:
[main]
...
securityManager.sessionManager.sessionIdCookie.domain = foo.com
cookie的默认名称JSESSIONID
与servlet规范一致。此外,Shiro的cookie支持HttpOnly
属性,可以保证额外的安全性。
如果您不想使用会话cookie,可以通过将该sessionIdCookieEnabled
属性配置为false 来禁用它们。例如:
[main]
...
securityManager.sessionManager.sessionIdCookieEnabled = false
记住我的服务
如果AuthenticationToken
实现org.apache.shiro.authc.RememberMeAuthenticationToken
接口(经常使用的UsernamePasswordToken
已经实现了RememberMeAuthenticationToken
接口并支持rememberMe登录。),Shiro将执行’rememberMe'
服务。此接口指定一个方法:
boolean isRememberMe();
如果此方法返回true
,Shiro将记住最终用户在会话中的身份。
代码支持
要以编程方式使用rememberMe
,可以将支持此配置的类的值设置为true
。例如,使用标准UsernamePasswordToken
:
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
token.setRememberMe(true);
SecurityUtils.getSubject().login(token);
...
基于表单的登录
对于Web应用程序,默认情况下过滤器为FormAuthenticationFilter
。这支持读取表单/请求的参数作为“rememberMe”的布尔值。默认情况下,它期望请求参数的命名为rememberMe
:
[main]
authc.loginUrl = /login.jsp
[urls]
# your login form page here:
login.jsp = authc
在您的前端表单中,有一个名为“rememberMe”的复选框:
<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
会寻找名为username
,password
和rememberMe
的请求参数。如果这些与您在表单中使用的表单字段名称不同,则需要在FormAuthenticationFilter
上配置名称。例如,在shiro.ini:
[main]
...
authc.loginUrl = /whatever.jsp
authc.usernameParam = somethingOtherThanUsername
authc.passwordParam = somethingOtherThanPassword
authc.rememberMeParam = somethingOtherThanRememberMe
...
您可以在rememberMeManager
对象中自定义cookie的各种属性,例如:
[main]
...
securityManager.rememberMeManager.cookie.name = foo
securityManager.rememberMeManager.cookie.maxAge = blah
...
自定义 RememberMeManager
如果默认的RememberMeManager
实现不能满足您的需求,您可以像自定义SecurityManager
那样去实现一个自定义类,然后在配置文件中引用:
[main]
...
rememberMeManager = com.my.impl.RememberMeManager
securityManager.rememberMeManager = $rememberMeManager