登录期间访问拒绝页面

时间:2020-04-02 10:27:48

标签: java spring spring-boot spring-security

我能够在Spring Boot应用程序中使用Spring Security登录。然后输入了错误的凭据,访问拒绝页面按预期方式工作。之后,我尝试使用正确的凭据登录,但是访问拒绝页面始终加载。解释解决方案?

WebSecurityConfig.java

import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.BeanIds;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/showReg", "/", "/index.html", "/registerUser", "/login", "/showLogin", "/login/*")
                .permitAll()
                .anyRequest()
                .authenticated();

        http
                .csrf().disable()
                .logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout")).logoutSuccessUrl("/showLogin")
                .deleteCookies("remember-me").permitAll()
                .and()
                .rememberMe();
    }

    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    @Bean(name = BeanIds.AUTHENTICATION_MANAGER)
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}

SecutityServiceImpl.java

import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Service;

@Service
public class SecurityServiceImpl implements SecurityService {

    @Autowired
    UserDetailsService userDetailsService;

    @Autowired
    AuthenticationManager authenticationManager;

    @Override
    public boolean login(String userName, String password) {
        UserDetails userDetails = userDetailsService.loadUserByUsername(userName);
        UsernamePasswordAuthenticationToken token=new UsernamePasswordAuthenticationToken(
                userDetails,password,userDetails.getAuthorities());
        authenticationManager.authenticate(token);
        boolean result = token.isAuthenticated();
        if (result){
            SecurityContextHolder.getContext().setAuthentication(token);
        }
        return result;
    }
}

1 个答案:

答案 0 :(得分:1)

在尝试找出拒绝访问页面的原因之前, 具有3个参数构造函数的UsernamePasswordAuthenticationToken始终将身份验证标志设置为true。

UsernamePasswordAuthenticationToken token=new UsernamePasswordAuthenticationToken(
            userDetails,password,userDetails.getAuthorities());

因此请检查认证结果是否为true,这不是您在if(result){...}中所依赖的基于认证的真实状态:

boolean result = token.isAuthenticated();<- always true

对于尝试认证authenticationManager.authenticate(token);令牌的尝试,此处应表示由用户凭据构造的身份验证对象,如下所示:

UsernamePasswordAuthenticationToken token=new UsernamePasswordAuthenticationToken(enteredUserName,enteredPassword);

传递给身份验证管理器,后者依次委托注册的身份验证提供程序进行身份验证。 我认为您的SecurityServiceImpl模仿了身份验证提供程序逻辑。我建议将该逻辑带到AuthenticationProvider实现中,并在AuthenticationManagerBuilder中注册它。 基本示例:

@Component
public class AuthProvider implements AuthenticationProvider {

@Autowired
UserDetailsService userDetailsService;

@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {

    String enteredUserName = authentication.getName();
    String enteredPassword = authentication.getCredentials().toString();

    UserDetails ud = userDetailsService.loadUserByUsername(userName);

    // compare/check password

    // if password valid
    return new UsernamePasswordAuthenticationToken(ud,null,authorities);
}

@Override
public boolean supports(Class<?> aClass) {
    return UsernamePasswordAuthenticationToken.class.isAssignableFrom(aClass);
}

}