我正在尝试使用apache Ignite分发用户会话时开发具有Spring安全登录功能的应用程序 .
-
服务器:Apache Tomcat 8
-
Spring 季版:4.2.2.RELEASE
-
Ignite版本:2.1.0
我的应用程序中有两个错误 .
- 从应用程序注销时记录异常 . 除了该会话之外,失效按预期完成 .
12-Aug-2017 14:09:01.580 SEVERE [http-nio-8080-exec-2] org.apache.ignite.logger.java.JavaLogger.error无法更新网络会话:org java.lang.NullPointerException at org位于org.apache.ignite.cache的org.apache.ignite.cache.websession.WebSessionFilter.doFilterV2(WebSessionFilter.java:564)的.apache.ignite.cache.websession.WebSessionFilter $ RequestWrapperV2.getSession(WebSessionFilter.java:1001) .websession.WebSessionFilter.doFilterDispatch(WebSessionFilter.java:407)atg.apache.ignite.cache.websession.WebSessionFilter.doFilter(WebSessionFilter.java:383)org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java) :193)org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)org.apache.catalina.core . StandardContextValve.invoke(StandardContextValve.java:96)at org.apache.catalina.authenticator.AuthenticatorBase.invoke(Authent icatorBase.java:478)org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:80)atg.apache.catalina .valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:624)org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342) )org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:799)org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)at org.apache.coyote.AbstractProtocol $ ConnectionHandler.process( AbstractProtocol.java:861)org.apache.tomcat.util.net.NioEndpoint $ SocketProcessor.doRun(NioEndpoint.java:1455)org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)at java.util.concurrent.ThreadPoolExecutor $ Worker.run(Th readPoolExecutor.java:617)atg.apache.tomcat.util.threads.TaskThread $ WrappingRunnable.run(TaskThread.java:61)at java.lang.Thread.run(Thread.java:748)
-
当两个具有相同应用程序部署的tomcat服务器在两个不同的端口启动时,只能从一个服务器访问登录页面 . (如果我从第一个服务器页面访问登录页面按预期正常加载 . 但是如果我再次尝试从第二个服务器访问登录页面则会出错 . 但是一旦登录应用程序按预期工作并且可以从两个服务器访问分布式会话 .
-
首次访问
- 从另一台服务器进行第二次访问
我的配置文件如下 .
- Spring上下文配置
<beans xmlns.... >
<context:component-scan base-package="test.ignite.spring"/>
<mvc:annotation-driven/>
<context:property-placeholder location="classpath:system.properties" ignore-resource-not-found="true" ignore-unresolvable="true"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"/>
<property name="suffix" value=".jsp"/>
</bean>
<mvc:interceptors>
<mvc:interceptor>
<!-- Cache of HTML pages -->
<mvc:mapping path="/**"/>
<bean class="org.springframework.web.servlet.mvc.WebContentInterceptor">
<property name="cacheSeconds" value="0"/>
</bean>
</mvc:interceptor>
</mvc:interceptors>
</beans>
- 登录控制器
@Controller
public class LoginController {
@RequestMapping(value = {"login", "/"})
public String login() {
try {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (!(auth instanceof AnonymousAuthenticationToken)) {
return "home";
}
return "login";
} catch (Exception e) {
return "redirect:/error/500";
}
}
@RequestMapping(value = "/home")
public String home() {
return "home";
}
}
----UPDATED----
- Ignite configuration (整个文件内容)
<beans xmlns.... >
<bean abstract="true" id="ignite.cfg" class="org.apache.ignite.configuration.IgniteConfiguration">
<!-- Set to true to enable distributed class loading for examples, default is false. -->
<property name="peerClassLoadingEnabled" value="true"/>
<property name="cacheConfiguration">
<list>
<bean class="org.apache.ignite.configuration.CacheConfiguration">
<property name="name" value="example"/>
<property name="cacheMode" value="PARTITIONED"/>
</bean>
</list>
</property>
<!-- Enable task execution events for examples. -->
<property name="includeEventTypes">
<list>
<!--Task execution events-->
<util:constant static-field="org.apache.ignite.events.EventType.EVT_TASK_STARTED"/>
<util:constant static-field="org.apache.ignite.events.EventType.EVT_TASK_FINISHED"/>
<util:constant static-field="org.apache.ignite.events.EventType.EVT_TASK_FAILED"/>
<util:constant static-field="org.apache.ignite.events.EventType.EVT_TASK_TIMEDOUT"/>
<util:constant static-field="org.apache.ignite.events.EventType.EVT_TASK_SESSION_ATTR_SET"/>
<util:constant static-field="org.apache.ignite.events.EventType.EVT_TASK_REDUCED"/>
<!--Cache events-->
<util:constant static-field="org.apache.ignite.events.EventType.EVT_CACHE_OBJECT_PUT"/>
<util:constant static-field="org.apache.ignite.events.EventType.EVT_CACHE_OBJECT_READ"/>
<util:constant static-field="org.apache.ignite.events.EventType.EVT_CACHE_OBJECT_REMOVED"/>
</list>
</property>
<!-- Explicitly configure TCP discovery SPI to provide list of initial nodes. -->
<property name="discoverySpi">
<bean class="org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi">
<property name="ipFinder">
<!--
Ignite provides several options for automatic discovery that can be used
instead os static IP based discovery. For information on all options refer
to our documentation: http://apacheignite.readme.io/docs/cluster-config
-->
<!-- Uncomment static IP finder to enable static-based discovery of initial nodes. -->
<!--<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder">-->
<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.multicast.TcpDiscoveryMulticastIpFinder">
<property name="addresses">
<list>
<!-- In distributed environment, replace with actual host IP address. -->
<value>127.0.0.1:47500..47509</value>
</list>
</property>
</bean>
</property>
</bean>
</property>
</bean>
- Spring security configuration
<beans:beans xmlns.... >
<http auto-config="true" create-session="always" use-expressions="true" >
<form-login login-page="/login" default-target-url="/home" authentication-failure-url="/login?error" username-parameter="username" password-parameter="password" always-use-default-target="true"/>
<logout invalidate-session="true" logout-success-url="/login" delete-cookies="JSESSIONID"/>
<session-management session-fixation-protection="newSession" invalid-session-url="/" session-authentication-error-url="/login">
<concurrency-control session-registry-alias="sessionRegistry" max-sessions="10" expired-url="/" error-if-maximum-exceeded="true"/>
</session-management>
<access-denied-handler error-page="/403"/>
</http>
<authentication-manager>
<authentication-provider user-service-ref="userDetailsService">
</authentication-provider>
</authentication-manager>
</beans:beans>
- web.xml
<web-app xmlns... >
<listener>
<listener-class>org.apache.ignite.startup.servlet.ServletContextListenerStartup</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
</listener>
<filter>
<filter-name>IgniteWebSessionsFilter</filter-name>
<filter-class>org.apache.ignite.cache.websession.WebSessionFilter</filter-class>
</filter>
<!-- You can also specify a custom URL pattern. -->
<filter-mapping>
<filter-name>IgniteWebSessionsFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- Specify Ignite configuration (relative to META-INF folder or Ignite_HOME). -->
<context-param>
<param-name>IgniteConfigurationFilePath</param-name>
<param-value>example-ignite.xml</param-value>
</context-param>
<!-- Specify the name of Ignite cache for web sessions. -->
<context-param>
<param-name>IgniteWebSessionsCacheName</param-name>
<param-value>example</param-value>
</context-param>
<!--SERVLETS-->
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:mvc-dispatcher-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:mvc-dispatcher-servlet.xml,
classpath:security-config.xml
</param-value>
</context-param>
</web-app>
如果您能提供解决问题的任何解决方案/想法,我将非常感激 .
1 回答
由于您的两个部署都在localhost上,因此他们将共享
JSESSIONID
cookie . 到现在为止还挺好 .但是,Tomcat,Spring Security和Ignite之间似乎存在不匹配,导致Spring Security将来自Ignite的会话视为无效,因为它们是匿名的(即未登录) . 我还不明白这与你应该已经登录的情况有什么关系 .
您可以使用解决方法:从Spring Security配置中删除
invalid-session-url="/"
. 这将阻止重定向循环行为 . 这也将导致用户以静默方式注销,而不是在Cookie过期时被引导至/login
.我删除了之前的答案,因为它忽略了这一点 .