【发布时间】:2014-08-28 12:36:26
【问题描述】:
我正在尝试创建访问日志。到目前为止,我可以使用此类成功记录会话的开始:
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)
sessions 为空。当我调试 SessionRegistryImpl 时,我发现问题出在 getAllSessions 的第一行:
final Set<String> sessionsUsedByPrincipal = principals.get(principal);
问题在于 sessionsUsedByPrincipal 获取的 sessionId 与数据库上存储的任何 sessionId 不同。 任何想法为什么会发生这种情况?我将不胜感激任何 cmets 或帮助。
编辑
答案效果很好,但它记录了两次。 这是我的 applicationContext-security
中更重要的部分<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>
不是我写的,也不是完全看懂,只是添加了我需要的东西。也许你可以看看,看看是否有什么可能导致这种行为。感谢您的帮助。
【问题讨论】:
-
Spring Security 已经为你清理了东西,你也不应该扩展
SecurityContextLogoutHandler,而是实现你自己的LogoutHandler,它将被添加(作为第一个!)到链中。但是我建议实现一个ApplicationListener来监听AuthenticationSuccessEvent以获得成功登录。WebAuthenticationDetails还包含使用的会话 ID,如果还没有会话,则不包含会话 ID(您的代码会强制创建会话!)。也不知道你为什么要让会话过期(因为 spring 会处理这个问题)。
标签: java spring session jakarta-ee logging