Spring Secriuty登录失败错误状态999重定向302

发布时间 2023-08-09 16:04:50作者: 蔚然丶丶

原因是login.html登录页面有不能加载的静态资源,找出来去掉就好了,比如 bootstrap.min.css

环境

使用Spring Boot Security 3做一个登录功能,使用了一个教程提供的HTML登录页面,代码如下

Spring Security配置,自定义了登录页,资源都做了放行,能正常加载,使用数据库认证,正常查出

@Configuration
public class SecurityConfiguration {

    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
    
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        return http
                .authorizeHttpRequests(auth -> {
                    auth.requestMatchers("/static/**").permitAll();
                    auth.anyRequest().authenticated();
                })
                .formLogin(conf -> {
                    conf.loginPage("/login");
                    conf.loginProcessingUrl("/doLogin");
                    conf.defaultSuccessUrl("/success");
                    conf.permitAll();
                })
                .logout(conf -> {
                    conf.logoutUrl("/doLogout");
                    conf.logoutSuccessUrl("/login");
                    conf.permitAll();
                })
                .csrf(AbstractHttpConfigurer::disable)

                .build();
    }
}

数据库认证

@Service
public class SecurityUserService implements UserDetailsService {

    @Autowired
    UserService userService;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        System.out.println("登录用户:" + username);

        User user = userService.getPasswordByUsername(username);
        if (user == null) {
            throw new UsernameNotFoundException("用户 " + username + " 登录失败,用户名不存在!");
        }

        System.out.println(user);

        return org.springframework.security.core.userdetails.User
                .withUsername(user.getName())
                .password(user.getPassword())
                .roles(user.getRole())
                .build();
    }
}

image

错误

但是在登录时,总是失败

{
    "timestamp": "2023-09-20T08:24:33.240+00:00",
    "status": 999,
    "error": "None"
}

image

如果此时修改url再次登录,或者直接访问目标页面,是可以成功的

或者取消自定义登录页,直接使用Spring Security提供的默认登录页是可以登录

解决

问题大致意思是页面有不能加载的静态资源,会转发错误页面,而Spring Security认为错误页面没有授权,就出现这个上面的错误页面,所以在login.html页面,很容易找到一个特殊的静态资源,bootstrap.min.css,去掉就好了

参考java - Spring 安全性重定向到状态代码为 999 的页面 - 堆栈溢出 (stackoverflow.com)

在浪费了很多时间之后,我想出了发生了什么。

所以 spring 找不到登录页面上使用的静态资源之一。但是,它不会返回此资源的状态,而是尝试呈现错误页面并将请求转发到 。然后 spring 安全性拒绝此请求,因为用户未获得授权。它将请求保存到会话(用于成功登录后重定向)并将用户重定向到登录页面。404``/error``/error

当然,用户看不到此重定向,因为状态返回在后台完成的请求。但主要问题是保存在会话中的请求。302``/error

然后用户登录成功,弹簧检查会话中的此属性并重定向到页面。默认情况下,spring假设您在静态资源的某个位置有这样的页面。如果您没有此页面,您将看到状态代码为999的奇怪错误。/error

解决方案 1

忽略安全配置中的页面:/error

web.ignoring().antMatchers("/favicon.ico", "/resources/**", "/error");

因此,成功登录后,此请求将不会保存到会话以供用户重定向。您将看到,在登录页面上,对静态资源的请求的状态代码将从 更改为 。302``404

解决方案 2

忽略部分 Spring 引导自动配置:

spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration

这给出了相同的结果,但禁用了配置中的某些 bean,所以要小心。ErrorMvcAutoConfiguration

我有同样的问题。我尝试注释每个样式表链接,以查看导致错误的一个。这是我的自定义css文件。问题是在我的 css 文件中,我有一个不存在的图像的 url,还有另一个错误的@import语句。评论这些之后,一切正常。