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>