2017-02-10 121 views
-1

我的環境:的Spring Security - 用戶驗證有時會失敗,並且用戶將被重定向到登錄頁面

  • 的Java 6
  • 的Servlet 2.5
  • 的Weblogic 12.1
  • Spring MVC的4.3.4.RELEASE
  • Spring Security 4.2.0.RELEASE

我已經實施了CustomAuthenticationProvider爲了根據Oracle數據庫對用戶進行身份驗證:用戶實際上是db用戶,因此我嘗試連接數據庫以檢查用戶/密碼,並且如果結果比我負載權限更好。

除登錄錯誤之外,配置工作正常。如果用戶輸入錯誤的用戶名或密碼,則應用程序會在同一頁面中顯示錯誤消息,但進一步正確的嘗試不會讓用戶登錄。而是被重定向到登錄頁面。如果用戶再次嘗試,則問題仍然存在。一分鐘後,同樣的嘗試,沒有頁面重新加載,是成功的。

正如我所說的,只有在登錄錯誤後纔會出現問題。如果用戶在第一次嘗試或註銷後正確輸入其憑據,則不會出現問題。如果他在登錄錯誤後執行此操作,則會出現問題。此外,無可厚非發生在我的開發環境(本地應用程序服務器和各種瀏覽器)但問題顯示出來,每次上分期environemnt(相同的應用程序服務器,但中央和IE9,IE10-EDGE)。我真的不明白是什麼造成了差異。

我把我的CustomAuthenticationProvider很多日誌,我可以比在兩種情況下(正面和負面的登錄)的用戶名和密碼已成功接受和UsernamePasswordAuthenticationToken已創建看到。然後,用戶應該被重定向到默認目標URL這是我的應用程序根目錄/(我設置總是使用默認的目標 = TRUE)。出於一個我不明白的原因,當問題發生時,重定向失敗,因爲Spring Security認爲用戶尚未獲得授權來訪問安全路徑,並將其重定向到登錄頁面。

我已經檢查了這兩種情況下的登錄表單提交請求,它們實際上是相同的,除了傳遞的JSESSIONID。但是,從響應頭中可以看到,登錄成功,JSESSIONID cookie已設置,否定情況下沒有「設置cookie」。

儘管事實上提交的用戶名和密碼是相同的,爲什麼會有這種差異?什麼可以有所作爲? 我的猜測是,一個錯誤的登錄嘗試留下了一些骯髒的東西。影響下次嘗試的東西。 Whan可以嗎?爲什麼這個問題只發生在我的本地環境中?我錯過了什麼?

這是CustomAuthenticationProvider執行:

@Component 
public class CustomAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider { 

private Logger log = LogManager.getLogger(CustomAuthenticationProvider.class); 

@Autowired 
private UserService userService; 

@Autowired 
private SecurityService securityService; 

@Autowired 
private Messages messages; 

@Value("${login.test.mode}") 
private String testMode; 

@Value("${login.test.mode.userid}") 
private String testModeUserid; 

public Authentication authenticate(Authentication authentication) throws AuthenticationException { 
    String username = authentication.getName(); 
    String password = (String) authentication.getCredentials(); 

    log.debug("##### SECURITY ##### Test mode status: " + testMode); 

    // test mode uses its own configured user, ignoring login credentials, if username is empty 
    if (Constants.FLAG_YES.equals(testMode) && StringUtils.isEmpty(username)) { 
     username = testModeUserid; 
    } 

    GddbUserDetails gddbUserDetails = userService.findGddbUserDetailsByUsername(username); 
    UserRole userRole = userService.findUserRolesByUsername(username); 

    if (gddbUserDetails == null) { 
     log.debug("##### SECURITY ##### Utente non trovato in anagrafica GDDB: " + username); 
     throw new BadCredentialsException(messages.get("user.not.found.gddb")); 
    } else { 
     log.debug("##### SECURITY ##### OK Utente trovato in anagrafica GDDB: " + username); 
    } 

    // perform checks only if test mode is disabled 
    if (!Constants.FLAG_YES.equals(testMode)) { 
     // GDDB state check 
     if (!Constants.USER_STATO_ACTIVE.equals(gddbUserDetails.getStato())) { 
      log.debug("##### SECURITY ##### Utente presente in anagrafica GDDB ma disabilitato: " + username); 
      throw new BadCredentialsException(messages.get("user.not.enabled.gddb")); 
     } else { 
      log.debug("##### SECURITY ##### Utente presente in anagrafica GDDB e abilitato: " + username); 
     } 
     // dbetichette user existence check 
     if (userRole == null) { 
      log.debug("##### SECURITY ##### Utente non presente in anagrafica DBEtichette: " + username); 
      throw new BadCredentialsException(messages.get("user.not.enabled.locally")); 
     } else { 
      log.debug("##### SECURITY ##### Utente presente in anagrafica DBEtichette: " + username); 
     } 
     // dbetichette user activation check 
     if (!Constants.FLAG_YES.equals(userRole.getActive())) { 
      log.debug("##### SECURITY ##### Utente disabilitato in anagrafica DBEtichette: " + username); 
      throw new BadCredentialsException(messages.get("user.not.enabled.locally")); 
     } else { 
      log.debug("##### SECURITY ##### Utente abilitato in anagrafica DBEtichette: " + username); 
     } 

     // oracle user password check 
     String usernamePasswordCheckResult = securityService.checkUserPassword(username, password); 
     log.debug("##### SECURITY ##### usernamePasswordCheckResult: " + usernamePasswordCheckResult); 

     if (Constants.SECURITY_ACCOUNT_LOCKED.equals(usernamePasswordCheckResult)) { 
      log.debug("##### SECURITY ##### Utente presente su DB ma bloccato: " + username); 
      throw new BadCredentialsException(messages.get("user.blocked")); 
     } else if (Constants.SECURITY_PASSWORD_EXPIRED.equals(usernamePasswordCheckResult)) { 
      log.debug("##### SECURITY ##### Password dell'utente scaduta: " + username); 
      throw new BadCredentialsException(messages.get("user.password.expired")); 
     } else if (Constants.SECURITY_INVALID_USERNAME_PASSWORD.equals(usernamePasswordCheckResult)) { 
      log.debug("##### SECURITY ##### Tentativo di accesso fallito per errata password: " + username); 
      throw new BadCredentialsException(messages.get("user.password.wrong")); 
     } else if (!Constants.SECURITY_VALID_USERNAME_PASSWORD.equals(usernamePasswordCheckResult)) { 
      log.debug("##### SECURITY ##### Tentativo di accesso fallito per motivo sconosciuto: " + username 
        + " (usernamePasswordCheckResult = " + usernamePasswordCheckResult + ")"); 
      throw new BadCredentialsException(messages.get("user.login.error.other")); 
     } else { 
      log.debug("##### SECURITY ##### Tentativo di accesso eseguito con successo: " + usernamePasswordCheckResult + " - " + username); 
     } 

    } 

    CustomUser user = userService.createCustomUser(gddbUserDetails, userRole); 
    log.debug("##### SECURITY ##### Creazione custom user: " + user); 

    Collection<? extends GrantedAuthority> authorities = user.getAuthorities(); 

    UsernamePasswordAuthenticationToken userToken = new UsernamePasswordAuthenticationToken(user, password, authorities); 
    log.debug("##### SECURITY ##### Creazione userToken: " + userToken); 

    return userToken; 

} 

@Override 
protected UserDetails retrieveUser(String s, UsernamePasswordAuthenticationToken token) throws AuthenticationException { 

    UserDetails user = (UserDetails) token.getPrincipal(); 
    log.debug("##### SECURITY ##### retrieveUser: " + user); 
    return user; 
} 

@Override 
public boolean supports(Class<?> aClass) { 
    return true; 
} 

@Override 
protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken token) throws AuthenticationException { 
    log.debug("##### SECURITY ##### additionalAuthenticationChecks - userDetails " + userDetails); 
    log.debug("##### SECURITY ##### additionalAuthenticationChecks - token " + token); 
} 

} 

這是我的春季安全配置文件:

<?xml version="1.0" encoding="UTF-8"?> 
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xmlns="http://www.springframework.org/schema/security" 
     xsi:schemaLocation="http://www.springframework.org/schema/beans 
          http://www.springframework.org/schema/beans/spring-beans.xsd 
          http://www.springframework.org/schema/security 
          http://www.springframework.org/schema/security/spring-security.xsd"> 

<http auto-config="true"> 
    <intercept-url pattern="/assets/**" access="permitAll()"/> 
    <intercept-url pattern="/pages/**" access="permitAll()"/> 
    <intercept-url pattern="/login" access="permitAll()"/> 
    <intercept-url pattern="/loginApp" access="permitAll()"/> 
    <intercept-url pattern="/loginFailed" access="permitAll()"/> 
    <intercept-url pattern="/logout" access="permitAll()"/> 
    <intercept-url pattern="/logoutSuccess" access="permitAll()"/> 
    <intercept-url pattern="/changepwd" access="permitAll()"/> 
    <intercept-url pattern="/admin/**" access="hasRole('ROLE_ADMIN')"/> 
    <intercept-url pattern="/relabel/**" access="hasRole('ROLE_ADMIN') or hasRole('ROLE_WAREHOUSE_OP') or hasRole('ROLE_QA')"/> 
    <intercept-url pattern="/**" access="hasRole('ROLE_DATA_ENTRY') or hasRole('ROLE_APPROVER') or hasRole('VIEWER') or hasRole('ROLE_ADMIN') or hasRole('ROLE_WAREHOUSE_OP') or hasRole('ROLE_QA')"/> 
    <form-login login-page="/login" 
       default-target-url="/" 
       authentication-failure-url="/loginFailed" 
       login-processing-url="/loginApp" 
       username-parameter="username" 
       password-parameter="password" 
       always-use-default-target="true" 
    /> 
    <logout logout-success-url="/logoutSuccess" logout-url="/logout"/> 
    <access-denied-handler error-page="/403"/> 

    <csrf disabled="true" /> 
</http> 

<authentication-manager> 
    <authentication-provider ref="customAuthenticationProvider"/> 
</authentication-manager> 

每一個建議表示讚賞。 謝謝大家, dolfiz

編輯:我做了春季安全日誌工作,似乎出於某種原因會話已被認證後清除,因此前進到登錄頁面。 這些日誌:

[DEBUG] 2017-02-17 17:01:41.317 org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter - Authentication success. Updating SecurityContextHolder to contain: org.springframew[email protected]e2fe4b0e: Principal: CustomUser{username='MAROTAN1', password='null', email='[email protected]', firstName='Antonio', lastName='Marotta', graceTime='null', authorities=[Role{name='ROLE_ADMIN'}], accountNonExpired=true, accountNonLocked=true, credentialsNonExpired=true, enabled=true}; Credentials: [PROTECTED]; Authenticated: true; Details: org.sprin[email protected]b364: RemoteIpAddress: 10.166.243.87; SessionId: QYWPYnpbth0y139v2gz7r6hCm0cHpsfmxq8DFqsvv3XM1kT6YcP2!2062762872!1487347291632; Granted Authorities: Role{name='ROLE_ADMIN'} 
[DEBUG] 2017-02-17 17:01:41.317 org.springframework.security.web.DefaultRedirectStrategy - Redirecting to '/dbetichette/' 
[DEBUG] 2017-02-17 17:01:41.317 org.springframework.security.web.context.HttpSessionSecurityContextRepository - HttpSession is now null, but was not null at start of request; session was invalidated, so do not create a new session 
[DEBUG] 2017-02-17 17:01:41.317 org.springframework.security.web.context.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as request processing completed 
[DEBUG] 2017-02-17 17:01:41.321 org.springframework.security.web.FilterChainProxy -/at position 1 of 12 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter' 
[DEBUG] 2017-02-17 17:01:41.321 org.springframework.security.web.context.HttpSessionSecurityContextRepository - No HttpSession currently exists 
[DEBUG] 2017-02-17 17:01:41.322 org.springframework.security.web.context.HttpSessionSecurityContextRepository - No SecurityContext was available from the HttpSession: null. A new one will be created. 
[DEBUG] 2017-02-17 17:01:41.322 org.springframework.security.web.FilterChainProxy -/at position 2 of 12 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter' 
[DEBUG] 2017-02-17 17:01:41.322 org.springframework.security.web.FilterChainProxy -/at position 3 of 12 in additional filter chain; firing Filter: 'HeaderWriterFilter' 
[DEBUG] 2017-02-17 17:01:41.323 org.springframework.security.web.FilterChainProxy -/at position 4 of 12 in additional filter chain; firing Filter: 'LogoutFilter' 
[DEBUG] 2017-02-17 17:01:41.323 org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/'; against '/logout' 
[DEBUG] 2017-02-17 17:01:41.323 org.springframework.security.web.FilterChainProxy -/at position 5 of 12 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter' 
[DEBUG] 2017-02-17 17:01:41.323 org.springframework.security.web.util.matcher.AntPathRequestMatcher - Request 'GET /' doesn't match 'POST /loginApp 
[DEBUG] 2017-02-17 17:01:41.323 org.springframework.security.web.FilterChainProxy -/at position 6 of 12 in additional filter chain; firing Filter: 'BasicAuthenticationFilter' 
[DEBUG] 2017-02-17 17:01:41.324 org.springframework.security.web.FilterChainProxy -/at position 7 of 12 in additional filter chain; firing Filter: 'RequestCacheAwareFilter' 
[DEBUG] 2017-02-17 17:01:41.324 org.springframework.security.web.FilterChainProxy -/at position 8 of 12 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter' 
[DEBUG] 2017-02-17 17:01:41.324 org.springframework.security.web.FilterChainProxy -/at position 9 of 12 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter' 
[DEBUG] 2017-02-17 17:01:41.324 org.springframework.security.web.authentication.AnonymousAuthenticationFilter - Populated SecurityContextHolder with anonymous token: 'org.sprin[email protected]6faa3d44: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.sprin[email protected]ffff4c9c: RemoteIpAddress: 10.166.243.87; SessionId: null; Granted Authorities: ROLE_ANONYMOUS' 
[DEBUG] 2017-02-17 17:01:41.325 org.springframework.security.web.FilterChainProxy -/at position 10 of 12 in additional filter chain; firing Filter: 'SessionManagementFilter' 
[DEBUG] 2017-02-17 17:01:41.325 org.springframework.security.web.session.SessionManagementFilter - Requested session ID QYWPYnpbth0y139v2gz7r6hCm0cHpsfmxq8DFqsvv3XM1kT6YcP2!2062762872 is invalid. 
[DEBUG] 2017-02-17 17:01:41.325 org.springframework.security.web.FilterChainProxy -/at position 11 of 12 in additional filter chain; firing Filter: 'ExceptionTranslationFilter' 
[DEBUG] 2017-02-17 17:01:41.325 org.springframework.security.web.FilterChainProxy -/at position 12 of 12 in additional filter chain; firing Filter: 'FilterSecurityInterceptor' 
[DEBUG] 2017-02-17 17:01:41.325 org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/'; against '/assets/**' 
[DEBUG] 2017-02-17 17:01:41.325 org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/'; against '/pages/**' 
[DEBUG] 2017-02-17 17:01:41.326 org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/'; against '/login' 
[DEBUG] 2017-02-17 17:01:41.326 org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/'; against '/loginApp' 
[DEBUG] 2017-02-17 17:01:41.326 org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/'; against '/loginFailed' 
[DEBUG] 2017-02-17 17:01:41.326 org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/'; against '/logout' 
[DEBUG] 2017-02-17 17:01:41.326 org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/'; against '/logoutSuccess' 
[DEBUG] 2017-02-17 17:01:41.326 org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/'; against '/changepwd' 
[DEBUG] 2017-02-17 17:01:41.327 org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/'; against '/admin/**' 
[DEBUG] 2017-02-17 17:01:41.327 org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/'; against '/relabel/**' 
[DEBUG] 2017-02-17 17:01:41.327 org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Secure object: FilterInvocation: URL: /; Attributes: [hasRole('ROLE_DATA_ENTRY') or hasRole('ROLE_APPROVER') or hasRole('VIEWER') or hasRole('ROLE_ADMIN') or hasRole('ROLE_WAREHOUSE_OP') or hasRole('ROLE_QA')] 
[DEBUG] 2017-02-17 17:01:41.327 org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Previously Authenticated: org.sprin[email protected]6faa3d44: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.sprin[email protected]ffff4c9c: RemoteIpAddress: 10.166.243.87; SessionId: null; Granted Authorities: ROLE_ANONYMOUS 
[DEBUG] 2017-02-17 17:01:41.328 org.springframework.security.access.vote.AffirmativeBased - Voter: org.sp[email protected]14b4feab, returned: -1 
[DEBUG] 2017-02-17 17:01:41.329 org.springframework.security.web.access.ExceptionTranslationFilter - Access is denied (user is anonymous); redirecting to authentication entry point 
org.springframework.security.access.AccessDeniedException: Access is denied 

我想,重要的路線是:

[DEBUG] 2017-02-17 17:01:41.317 org.springframework.security.web.context.HttpSessionSecurityContextRepository - HttpSession is now null, but was not null at start of request; session was invalidated, so do not create a new session 

這究竟是爲什麼只是有時,只有在一些enviroments?

+0

爲什麼-1?根據某人我的問題沒有顯示任何研究工作,或者可能不清楚和/或沒有用:/ – Dolfiz

回答

0

針對不同但類似問題的閱讀解決方案herehere,我猜想我的問題也是一個併發問題,與會話管理有關。

爲此,我試圖設置明確的配置在我securityConfig.xml會話管理,限制爲1允許每個用戶的身份驗證會話的數量:

<session-management session-fixation-protection="newSession"> 
    <concurrency-control max-sessions="1" error-if-maximum-exceeded="true" /> 
</session-management> 

並把所需的聽衆對我的web.xml

<listener> 
    <listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class> 
</listener> 

這些變化完全解決了這個問題。

相關問題