簡體   English   中英

Spring SessionRegistryImpl沒有獲得正確的sessionId

[英]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>

我沒有寫它,也沒有完全理解它,只是添加了我需要的東西。 也許您可以看看是否有某種原因導致此行為。 謝謝你的幫助。

對於初學者,我建議創建一個偵聽AuthenticationSuccessEventInteractiveAuthenticationSuccessEvent事件的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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM