spring boot預設使用spring security,spring security自然不用說是一個強大的安全框架,但是用慣了shiro,一時半會用不來spring security,所以要在spring boot中自己整合shiro。說到整合shiro,網上也是有不少教程的,但是網上的教程也不是一定是對的,可能有版本等各種問題,所以說還是要自己來動手做一遍。
在我動手整合的時候出現UnavailableSecurityManagerException的錯誤:
2016-12-24 10:58:56.787 ERROR 7916 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [org.apache.shiro.UnavailableSecurityManagerException: No SecurityManager accessible to the calling code, either bound to the org.apache.shiro.util.ThreadContext or as a vm static singleton. This is an invalid application configuration.] with root cause
org.apache.shiro.UnavailableSecurityManagerException: No SecurityManager accessible to the calling code, either bound to the org.apache.shiro.util.ThreadContext or as a vm static singleton. This is an invalid application configuration.
spring整合shiro出現UnavailableSecurityManagerException在網上查出的問題都是沒有配置DelegatingFilterProxy或者DelegatingFilterProxy的配置順序錯了,對應的解決辦法就是在web.xml上新增DelegatingFilterProxy。
<filter> <filter-name>shiroFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <async-supported>true</async-supported> <init-param> <param-name>targetFilterLifecycle</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>shiroFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
可是我們現在使用的spring boot啊,才不要再用回web.xml的配置檔案呢。那到底怎麼解決呢?
我第一想法就是,使用FilterRegistrationBean註冊一個DelegatingFilterProxy:
@Bean public FilterRegistrationBean delegatingFilterProxy(){ FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(); DelegatingFilterProxy proxy = new DelegatingFilterProxy(); proxy.setTargetFilterLifecycle(true); filterRegistrationBean.setFilter(proxy); return filterRegistrationBean; }
跟上面一樣,應該沒問題吧?可這都是我的一廂情願,出錯了:
org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'delegatingFilterProxy' is expected to be of type [javax.servlet.Filter] but was actually of type [org.springframework.boot.web.servlet.FilterRegistrationBean]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:378) ~[spring-beans-4.3.3.RELEASE.jar:4.3.3.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-4.3.3.RELEASE.jar:4.3.3.RELEASE] at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1082) ~[spring-context-4.3.3.RELEASE.jar:4.3.3.RELEASE] at org.springframework.web.filter.DelegatingFilterProxy.initDelegate(DelegatingFilterProxy.java:326) ~[spring-web-4.3.3.RELEASE.jar:4.3.3.RELEASE] at org.springframework.web.filter.DelegatingFilterProxy.initFilterBean(DelegatingFilterProxy.java:235) ~[spring-web-4.3.3.RELEASE.jar:4.3.3.RELEASE] at org.springframework.web.filter.GenericFilterBean.init(GenericFilterBean.java:199) ~[spring-web-4.3.3.RELEASE.jar:4.3.3.RELEASE] at org.apache.catalina.core.ApplicationFilterConfig.initFilter(ApplicationFilterConfig.java:279) ~[tomcat-embed-core-8.5.5.jar:8.5.5] at org.apache.catalina.core.ApplicationFilterConfig.<init>(ApplicationFilterConfig.java:109) ~[tomcat-embed-core-8.5.5.jar:8.5.5] at org.apache.catalina.core.StandardContext.filterStart(StandardContext.java:4572) [tomcat-embed-core-8.5.5.jar:8.5.5] at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5215) [tomcat-embed-core-8.5.5.jar:8.5.5] at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) [tomcat-embed-core-8.5.5.jar:8.5.5] at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1403) [tomcat-embed-core-8.5.5.jar:8.5.5] at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1393) [tomcat-embed-core-8.5.5.jar:8.5.5] at java.util.concurrent.FutureTask.run(FutureTask.java:266) [na:1.8.0_25] at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_25] at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_25] at java.lang.Thread.run(Thread.java:745) [na:1.8.0_25]
看到下面這個錯誤行:
at org.springframework.web.filter.DelegatingFilterProxy.initDelegate(DelegatingFilterProxy.java:326) ~[spring-web-4.3.3.RELEASE.jar:4.3.3.RELEASE]
看到下面程式碼,我們大概可以知道,根據getTargetBeanName()來進行委派,而TargetBeanName是delegatingFilterProxy。
誒,不對啊,我shiroFilter的beanName不是這個啊,明明是shiroFilter。
protected Filter initDelegate(WebApplicationContext wac) throws ServletException { Filter delegate = wac.getBean(getTargetBeanName(), Filter.class); if (isTargetFilterLifecycle()) { delegate.init(getFilterConfig()); } return delegate; }
解決辦法
經過上面一大串推論,解決辦法就是:
@Bean public FilterRegistrationBean delegatingFilterProxy(){ FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(); DelegatingFilterProxy proxy = new DelegatingFilterProxy(); proxy.setTargetFilterLifecycle(true); proxy.setTargetBeanName("shiroFilter"); filterRegistrationBean.setFilter(proxy); return filterRegistrationBean; } @Bean("shiroFilter") public ShiroFilterFactoryBean shiroFilterFactoryBean() { ShiroFilterFactoryBean filterFactoryBean = new ShiroFilterFactoryBean(); ....... return filterFactoryBean; }
沒有寫太多shiro的整合程式碼,只寫瞭解決UnavailableSecurityManagerException問題的關鍵程式碼,如需要可以自行網上查詢。