Apache Shiro 集成-spring
Shiro 的JavaBean 兼容性使得它非常适合通过Spring XML 或其他基于Spring 的配置机制。Shiro 应用程序需要一个具有单例SecurityManager 实例的应用程序。请注意,这不会是一个静态的单例,但应该只有一个应用程序能够使用的实例,无论它是否是静态单例的。
Standalone 应用程序
这里是在Spring 应用程序中启用应用程序单例SecurityManager 的最简单的方法:
<!-- Define the realm you want to use to connect to your back-end security datasource: --> <bean id="myRealm" class="..."> ... </bean> <bean id="securityManager" class="org.apache.shiro.mgt.DefaultSecurityManager"> <!-- Single realm app. If you have multiple realms, use the 'realms' property instead. --> <property name="realm" ref="myRealm"/> </bean> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/> <!-- For simplest integration, so that all SecurityUtils.* methods work in all cases, --> <!-- make the securityManager bean a static singleton. DO NOT do this in web --> <!-- applications - see the 'Web Applications' section below instead. --> <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> <property name="staticMethod" value="org.apache.shiro.SecurityUtils.setSecurityManager"/> <property name="arguments" ref="securityManager"/> </bean> |
Web 应用程序
Shiro 拥有对Spring Web 应用程序的一流支持。在Web 应用程序中,所有Shiro 可访问的请求必须通过一个主要的Shiro 过滤器。该过滤器本身是极为强大的,允许临时的自定义过滤器链基于任何URL 路径表达式执行。
以下是如何在基于Spring web 应用程序中配置Shiro。除了其他Spring web.xml 中的元素(ContextLoaderListener,Log4jConfigListener 等等),定义下面的过滤器及过滤器映射:
web.xml
<!-- The filter-name matches name of a 'shiroFilter' bean inside applicationContext.xml --> <filter> <filter-name>shiroFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <init-param> <param-name>targetFilterLifecycle</param-name> <param-value>true</param-value> </init-param> </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> </filter-mapping> |
在你的applicationContext.xml 文件中,定义web 支持的SecurityManager 和'shiroFilter' bean 将会被web.xml 引用。
applicationContext.xml
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager"/> <!-- override these for application-specific URLs if you like: <property name="loginUrl" value="/login.jsp"/> <property name="successUrl" value="/home.jsp"/> <property name="unauthorizedUrl" value="/unauthorized.jsp"/> --> <!-- The 'filters' property is not necessary since any declared javax.servlet.Filter bean --> <!-- defined will be automatically acquired and available via its beanName in chain --> <!-- definitions, but you can perform instance overrides or name aliases here if you like: --> <!-- <property name="filters"> <util:map> <entry key="anAlias" value-ref="someFilter"/> </util:map> </property> --> <property name="filterChainDefinitions"> <value> # some example chain definitions: /admin/** = authc, roles[admin] /docs/** = authc, perms[document:read] /** = authc # more URL-to-FilterChain definitions here </value> </property> </bean> <!-- Define any javax.servlet.Filter beans you want anywhere in this application context. --> <!-- They will automatically be acquired by the 'shiroFilter' bean above and made available --> <!-- to the 'filterChainDefinitions' property. Or you can manually/explicitly add them --> <!-- to the shiroFilter's 'filters' Map if desired. See its JavaDoc for more details. --> <bean id="someFilter" class="..."/> <bean id="anotherFilter" class="..."> ... </bean> ... <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <!-- Single realm app. If you have multiple realms, use the 'realms' property instead. --> <property name="realm" ref="myRealm"/> <!-- By default the servlet container sessions will be used. Uncomment this line to use shiro's native sessions (see the JavaDoc for more): --> <!-- <property name="sessionMode" value="native"/> --> </bean> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/> <!-- Define the Shiro Realm implementation you want to use to connect to your back-end --> <!-- security datasource: --> <bean id="myRealm" class="..."> ... </bean> |
Enabling Shiro Annotations
在Standalone应用程序和Web 应用程序中,你可能想为安全检查使用Shiro 的注释(例如,@RequiresRoles,@RequiresPermissions 等等)。这需要Shiro 的Spring AOP 集成来扫描合适的注解类以及执行必要的安全逻辑。
以下是如何使用这些注解的。只需添加这两个bean 定义到applicationContext.xml 中:
<!-- Enable Shiro Annotations for Spring-configured beans. Only run after --> <!-- the lifecycleBeanProcessor has run: --> <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"/> <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> <property name="securityManager" ref="securityManager"/> </bean> |
Secure Spring Remoting
Shiro 的Spring 远程支持有两部分:配置客户端远程调用和配置服务器接收及处理远程调用。
Server-side Configuration
当一个远程调用方法到达启用Shiro 的服务器时,与该RPC 调用关联的Subject 在线程执行时必须绑定到访问的接收线程。这是通过在applicationContext.xml 中定义SecureRemotInvocationExecutor bean 来完成的:
<!-- Secure Spring remoting: Ensure any Spring Remoting method invocations --> <!-- can be associated with a Subject for security checks. --> <bean id="secureRemoteInvocationExecutor" class="org.apache.shiro.spring.remoting.SecureRemoteInvocationExecutor"> <property name="securityManager" ref="securityManager"/> </bean> |
当你定义这个bean 之后,你必须将其插入到任何你正在用来export/expose 你服务的远程Exporter。Exporter 实现是根据使用的远程处理机制/协议来定义的。请参阅Sping 的Remoting 章节关于定义Exporter bean 的内容。
例如,如果使用基于HTTP 的远程调用(注意secureRemoteInvocationExecutor bean 的相关属性):
<bean name="/someService" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter"> <property name="service" ref="someService"/> <property name="serviceInterface" value="com.pkg.service.SomeService"/> <property name="remoteInvocationExecutor" ref="secureRemoteInvocationExecutor"/> </bean> |
Client-side Configuration
当远程调用被执行后,Subject 的识别信息必须附加到远程调用的负载上使服务器知道是谁作出了该调用。若客户端是一个基于Spring 的客户端,该关联是通过Shiro 的SecureRemoteInvocationFactory 来完成的:
<bean id="secureRemoteInvocationFactory" class="org.apache.shiro.spring.remoting.SecureRemoteInvocationFactory"> |
在你定义好这个bean 后,你需要将它插入到你正在使用的基于特定协议的Spring remoting ProxyFactoryBean 中。
例如,如果你正在使用基于HTTP 的远程调用(注意上面定义的secureRemoteInvocationFactory bean 的相关属性):
<bean id="someService" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
<property name="serviceUrl" value="http://host:port/remoting/someService"/>
<property name="serviceInterface" value="com.pkg.service.SomeService"/>
<property name="remoteInvocationFactory" ref="secureRemoteInvocationFactory"/>
</bean>