当前位置: 首页 > 知识库问答 >
问题:

Spring Security-用户身份验证有时失败,用户被重定向到登录页面

闻人献
2023-03-14
  • Java 6
  • Servlet 2.5
  • WebLogic 12.1
  • Spring MVC 4.3.4.release
  • Spring Security 4.2.0.版本

我实现了一个CustomAuthenticationProvider来根据Oracle db对用户进行身份验证:用户实际上是db用户,因此我尝试连接到db以检查用户/密码,如果结果是肯定的,则加载权限。

除非发生登录错误,否则配置工作正常。如果用户输入了错误的用户名或密码,则应用程序会在同一页面中显示错误消息,但进一步正确的尝试不会让用户登录。而是重定向到登录页。如果用户再次尝试,则问题仍然存在。一分钟后,在不重新加载页面的情况下,同样的尝试是成功的。

正如我所说的,只有在登录错误之后才会出现问题。如果用户在第一次尝试时或注销后正确键入凭据,则不会出现任何问题。如果他在登录错误后再这样做,那么问题就会出现。此外,在我的开发环境(本地应用服务器和各种浏览器)上没有发生任何错误,但问题每次都出现在临时环境(相同的应用服务器,但集中和IE9-IE10-Edge)上。我真的不明白这有什么区别。

我在CustomAuthenticationProvider上放了很多日志,我可以看到,在两种情况下(正登录和负登录)用户名和密码都已被成功接受,并且已经创建了UsernamePasswordAuthenticationToken。然后,用户应该被重定向到default-target-url,它是我的应用程序根/(我设置了always-use-default-target=true)。由于一个我不理解的原因,当问题发生时,重定向失败,因为Spring Security认为用户还没有访问安全路径的授权,它会重新将他重定向到登录页面。

我检查了这两种情况下的登录表单提交请求,除了传递的JSESSIONID之外,它们实际上是完全相同的。但是登录是成功的我可以从响应头看到JSESSIONID cookie已经设置了,在否定的情况下没有“set cookie”。

尽管提交的用户名和密码是相同的,但为什么会有这种不同的行为?!什么能起到作用?我的猜测是错误的登录尝试留下了一些肮脏的东西。影响下一次尝试的东西。会是什么呢?为什么这个问题只发生在我的本地环境中?我错过了什么?

这是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);
}

}

这是我的Spring Security配置文件:

<?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>
[DEBUG] 2017-02-17 17:01:41.317 org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter - Authentication success. Updating SecurityContextHolder to contain: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@e2fe4b0e: Principal: CustomUser{username='MAROTAN1', password='null', email='antonio.marotta@novartis.com', 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.springframework.security.web.authentication.WebAuthenticationDetails@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.springframework.security.authentication.AnonymousAuthenticationToken@6faa3d44: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@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.springframework.security.authentication.AnonymousAuthenticationToken@6faa3d44: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@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.springframework.security.web.access.expression.WebExpressionVoter@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

为什么这种情况只在某些情况下发生,而且只发生在某些环境中?

共有1个答案

艾阳羽
2023-03-14

阅读不同但相似的问题的解决方案,我猜我的也是一个并发问题,与会话管理有关。

为此,我尝试在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>
 类似资料:
  • 我有一个API在Apache堆栈上运行,使用Java。我继承了一个遗留代码库,需要找到这个错误来自哪里显然是上一个开发人员构建了一个不能工作的特性,这就是错误所在,但没有更多信息。它使用Drupal webservice模块,发送调用的代码如下所示 我可以从哪里开始寻找这个错误,或者它可能意味着什么,你有什么想法吗? 完整的堆栈跟踪如下所示::: 用户失败:null。java.lang.Unsup

  • 我试图使用Jenkins的REST api。Jenkins需要向URL发送POST请求来删除作业。其结果如下: 我告诉我选择的客户端将一篇文章发送到适当的URL。 客户端发送一篇文章,并使用用户名和密码对自己进行授权。 Jenkins删除作业。 Jenkins返回一个“302-Found”,其中包含包含已删除作业的文件夹的位置。 客户端自动将邮件发送到该位置。 Jenkins回答“200-OK”和

  • 我正在使用ApacheShiro开发JSF应用程序。我用Shiro引诱用户,并将其重定向到主页。这没有问题。验证后,当我尝试访问登录页面时,它不会将我重定向到主页。即使已经有loggedin用户,我也可以再次登录。正如巴卢斯克在他的博客文章中提到的,我正在进行程序登录。 这个滤镜是根据博文写的。 } 问题是什么?如果用户已经通过身份验证,我该如何重定向用户? 编辑:现在,如果用户已经通过身份验证,

  • 该应用程序应该接受用户电子邮件和密码,并使用Firebase身份验证作为后端。我使用像素2作为模拟器。每次应用程序处理登录功能时,它都会崩溃。 下面是Java文件和gradle文件 Java文件:

  • 遵循这个指南:https://www.youtube.com/watch?v=bqkt6eSsRZs 添加了从laravel docs的auth路由 创建登录/注册视图 创建 /home路线 自定义AuthController: 尝试访问身份验证/登录时,我遇到以下错误: 请求中出现错误异常。php第775行:。。未根据请求设置会话存储。 已将身份验证路由移动到中间件组。 成功注册,在数据库和会话

  • 本文向大家介绍php面向对象的用户登录身份验证,包括了php面向对象的用户登录身份验证的使用技巧和注意事项,需要的朋友参考一下 本文实例为大家分享了php用户登录身份验证的具体代码,供大家参考,具体内容如下 一、代码 conn.php index.php 二、运行结果 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持呐喊教程。