[英]Spring SessionRegistryImpl not getting correct sessionId
我正在嘗試做一個訪問日志。 到目前為止,我可以使用此類成功記錄會話的開始:
public class CustomAuthenticationProcessingFilter extends J2eePreAuthenticatedProcessingFilter {
@Autowired
AccessLogService accessLogService;
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
if (authentication.isAuthenticated()) {
String authenticatedUser = authentication.getName();
WebAuthenticationDetails wad = (WebAuthenticationDetails) authentication.getDetails();
accessLogService.addAccessLog("IP: " + wad.getRemoteAddress(), authenticatedUser, request.getSession().getId());
}
super.successfulAuthentication(request, response, authentication);
}
}
很好 對於注銷部分,我有此類:
public class CustomSecurityContextLogoutHandler extends SecurityContextLogoutHandler {
@Autowired
private SessionRegistry sessionRegistry;
@Autowired
private AccessLogDAO accessLogDAO;
private boolean deleteLtpaCookies = Boolean.FALSE;
public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
if (authentication != null && authentication.getPrincipal() != null) {
List<SessionInformation> sessions = sessionRegistry.getAllSessions(((User) authentication.getPrincipal()), false);
if (sessions != null) {
for (SessionInformation sessionInformation : sessions) {
List<String> sessionsToClose = new ArrayList<String>();
sessionsToClose.add(sessionInformation.getSessionId());
accessLogDAO.closeAccessLog(sessionsToClose);
sessionInformation.expireNow();
}
}
}
}
但是當我這樣做
List<SessionInformation> sessions = sessionRegistry.getAllSessions(((User) authentication.getPrincipal()), false)
會話為空。 當我調試SessionRegistryImpl時,我發現問題出在getAllSessions的第一行:
final Set<String> sessionsUsedByPrincipal = principals.get(principal);
問題在於, sessionUsedByPrincipal獲得的sessionId與存儲在數據庫中的任何sessionId不同。 任何想法為什么會這樣? 我將不勝感激任何意見或幫助。
編輯
答案很有效,但記錄了兩次。 這是我的應用程序更重要的部分
<sec:http auto-config='false' use-expressions="true" authentication-manager-ref="authenticationManager" entry-point-ref="authenticationProcessingFilterEntryPoint">
<sec:custom-filter position="CONCURRENT_SESSION_FILTER" ref="concurrencyFilter" />
<sec:custom-filter position="PRE_AUTH_FILTER" ref="preAuthFilter"/>
<sec:custom-filter position="LOGOUT_FILTER" ref="logoutFilter"/>
<sec:session-management session-authentication-strategy-ref="sas"/>
</sec:http>
<sec:authentication-manager alias="authenticationManager">
<sec:authentication-provider ref="preAuthenticatedAuthenticationProvider" />
</sec:authentication-manager>
<bean id="preAuthenticatedAuthenticationProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
<property name="preAuthenticatedUserDetailsService" ref="preAuthenticatedUserDetailsService"/>
</bean>
<bean id="preAuthenticatedUserDetailsService" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedGrantedAuthoritiesUserDetailsService"/>
<bean id="concurrencyFilter" class="org.springframework.security.web.session.ConcurrentSessionFilter">
<property name="sessionRegistry" ref="sessionRegistry" />
<property name="expiredUrl" value="/login.faces" />
</bean>
<bean id="sessionRegistry" class="org.springframework.security.core.session.SessionRegistryImpl" />
<bean id="sas" class="org.springframework.security.web.authentication.session.ConcurrentSessionControlStrategy">
<constructor-arg name="sessionRegistry" ref="sessionRegistry" />
<property name="maximumSessions" value="-1" />
<property name="exceptionIfMaximumExceeded" value="true" />
</bean>
<bean id="simpleAttributes2GrantedAuthoritiesMapper" class="org.springframework.security.core.authority.mapping.SimpleAttributes2GrantedAuthoritiesMapper">
<property name="convertAttributeToUpperCase" value="true"/>
</bean>
<bean id="webXmlMappableAttributesRetriever" class="org.springframework.security.web.authentication.preauth.j2ee.WebXmlMappableAttributesRetriever"/>
<bean id="j2eeBasedPreAuthenticatedWebAuthenticationDetailsSource" class="org.springframework.security.web.authentication.preauth.j2ee.J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource">
<property name="mappableRolesRetriever" ref="webXmlMappableAttributesRetriever"/>
<property name="userRoles2GrantedAuthoritiesMapper" ref="simpleAttributes2GrantedAuthoritiesMapper"/>
</bean>
<bean id="preAuthFilter" class="org.springframework.security.web.authentication.preauth.j2ee.J2eePreAuthenticatedProcessingFilter">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="authenticationDetailsSource" ref="j2eeBasedPreAuthenticatedWebAuthenticationDetailsSource"/>
</bean>
<bean id="authenticationProcessingFilterEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<constructor-arg value="/login.faces"/>
<property name="forceHttps" value="false"/>
</bean>
<bean id="logoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter">
<constructor-arg value="/login.faces"/>
<constructor-arg>
<list>
<bean class="cr.go.nov.proy.web.util.AccessLogHandler"/>
</list>
</constructor-arg>
</bean>
我沒有寫它,也沒有完全理解它,只是添加了我需要的東西。 也許您可以看看是否有某種原因導致此行為。 謝謝你的幫助。
對於初學者,我建議創建一個偵聽AuthenticationSuccessEvent
和InteractiveAuthenticationSuccessEvent
事件的ApplicationListener
,以開始記錄您的訪問日志。
要注銷,請創建專用的LogoutHandler
而不是擴展現有的注銷。
將會使用的session-id是WebAuthenticationDetails
一部分,因此我也建議您使用它而不是解決它。 如果沒有會話,您的代碼將強制創建會話。
public class AccessLogHandler implements ApplicationListener<AbstractAuthenticationEvent>, LogoutHandler {
@Autowired
private SessionRegistry sessionRegistry;
@Autowired
private AccessLogService accessLogService;
public void onApplicationEvent(AbstractAuthenticationEvent event) {
if (event instanceof AuthenticationSuccessEvent || event instanceof InteractiveAuthenticationSuccessEvent) {
Authentication authentication = event.getAuthentication();
WebAuthenticationDetails details = (WebAuthenticationDetails) authentication.getDetails();
accessLogService.addAccessLog("IP: " + details.getRemoteAddress(), authentication.getName(), details.getSessionId());
}
}
public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
WebAuthenticationDetails details = (WebAuthenticationDetails) authentication.getDetails();
accessLogService.closeAccessLog(Collections.singletonList(details.getSessionId());
SessionInformation si = sessionRegistry.getSessionInformation(details.getSessionId());
if (si != null) {
si.expireNow();
}
}
}
這樣的事情應該可以工作,您可以刪除擴展類,剩下基本配置。 ApplicationListener
是自動注冊的, LogoutHandler
您需要將LogoutFilter
添加到需要顯式配置的LogoutFilter
中。 但是從您已經擴展了另一個LogoutHandler
的事實來看,這已經是您要做的事情。
您的配置也很復雜,例如登錄,可以使用名稱空間配置會話控制。 以下配置應與您自己的配置相同(可能還要更多)。
<sec:http auto-config='false' use-expressions="true" authentication-manager-ref="authenticationManager" >
<sec:custom-filter position="PRE_AUTH_FILTER" ref="preAuthFilter"/>
<sec:custom-filter position="LOGOUT_FILTER" ref="logoutFilter"/>
<sec:login-form login-page="/login.faces" />
<sec:session-management>
<sec:concurrency-control max-sessions="-1" session-registry-alias="sessionRegistry" error-if-maximum-exceeded="true" expired-url="/login.faces"/>
</sec:session-management>
</sec:http>
<sec:authentication-manager alias="authenticationManager">
<sec:authentication-provider ref="preAuthenticatedAuthenticationProvider" />
</sec:authentication-manager>
<bean id="preAuthenticatedAuthenticationProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
<property name="preAuthenticatedUserDetailsService" ref="preAuthenticatedUserDetailsService"/>
</bean>
<bean id="preAuthenticatedUserDetailsService" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedGrantedAuthoritiesUserDetailsService"/>
<bean id="j2eeBasedPreAuthenticatedWebAuthenticationDetailsSource" class="org.springframework.security.web.authentication.preauth.j2ee.J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource">
<property name="mappableRolesRetriever">
<bean class="org.springframework.security.web.authentication.preauth.j2ee.WebXmlMappableAttributesRetriever"/>
</property>
<property name="userRoles2GrantedAuthoritiesMapper">
<bean class="org.springframework.security.core.authority.mapping.SimpleAttributes2GrantedAuthoritiesMapper">
<property name="convertAttributeToUpperCase" value="true"/>
</bean>
</property>
</bean>
<bean id="preAuthFilter" class="org.springframework.security.web.authentication.preauth.j2ee.J2eePreAuthenticatedProcessingFilter">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="authenticationDetailsSource" ref="j2eeBasedPreAuthenticatedWebAuthenticationDetailsSource"/>
</bean>
<bean id="logoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter">
<constructor-arg value="/login.faces"/>
<constructor-arg>
<list>
<bean class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"/>
<bean class="cr.go.nov.proy.web.util.AccessLogHandler"/>
</list>
</constructor-arg>
</bean>
在您的配置中,您不會注冊任何SessionAuthenticationStrategy
,這也意味着沒有會話正在SessionRegistry
中注冊。 由於RegisterSessionAuthenticationStrategy
會解決這一問題。 注意-這假設您正在使用Spring Security 3.2!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.