首页 > 解决方案 > Spring安全登录失败错误重定向并且没有错误消息

问题描述

我正在尝试构建一个简单的登录表单(JS)和用户 Spring 安全性。据我了解,当登录失败时,它应该重定向到登录页面(或者仅适用于引导项目中的 JSP 登录页面?)但它无法做到这一点。并且查询错误字符串参数也是空的。

我的弹簧安全配置:

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .cors()
                .and()
            .authorizeRequests()
                .anyRequest().authenticated()
                .and()
            .formLogin()
                .defaultSuccessUrl("/", true)
                .permitAll()
                .and()
            .httpBasic()
                .and()
            .csrf().disable()
            .logout()
                .permitAll()
                .logoutSuccessUrl("/");
    }

    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        final CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(ImmutableList.of("*"));
        configuration.setAllowedMethods(ImmutableList.of("HEAD",
                "GET", "POST", "PUT", "DELETE", "PATCH"));
        configuration.setAllowCredentials(true);
        configuration.setAllowedHeaders(ImmutableList.of("Authorization", "Cache-Control", "Content-Type"));
        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }

    @Bean
    public UserDetailsService userDetailsService() {
        // ensure the passwords are encoded properly
        User.UserBuilder users = User.withDefaultPasswordEncoder();
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        manager.createUser(users.username("user").password("user").roles("USER").build());
        manager.createUser(users.username("admin").password("admin").roles("USER","ADMIN").build());
        return manager;
    }
}

引导:

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

从 JS 应用程序我向 发送请求http://localhost:8080/login,在这种情况下我认为这并不重要,但我正在使用 MithrilJS 请求:

m.request({
    method: "POST",
    url: "http://localhost:8080/login",
    body: {username: login, password: pass}
})
.then((result) => {
    UserLogin.loggedIn = true;
})
.catch(error => {
    console.log(error);
});

回应(2出于某种原因)我得到:

http://localhost:8080/login?error 
Request Method: OPTIONS
Response is empty
error string is also empty

http://localhost:8080/login?error 
Request Method: GET
error String is empty

现在有趣的部分是,响应包含 html (请注意,我的代码中的任何地方都没有这个 HTML)

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="description" content="">
    <meta name="author" content="">
    <title>Please sign in</title>
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">
    <link href="https://getbootstrap.com/docs/4.0/examples/signin/signin.css" rel="stylesheet" crossorigin="anonymous"/>
  </head>
  <body>
     <div class="container">
      <form class="form-signin" method="post" action="/login">
        <h2 class="form-signin-heading">Please sign in</h2>
<div class="alert alert-danger" role="alert">Invalid credentials</div>        <p>
          <label for="username" class="sr-only">Username</label>
          <input type="text" id="username" name="username" class="form-control" placeholder="Username" required autofocus>
        </p>
        <p>
          <label for="password" class="sr-only">Password</label>
          <input type="password" id="password" name="password" class="form-control" placeholder="Password" required>
        </p>
        <button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
      </form>
</body></html>

任何想法我在哪里失败?

编辑:

感谢您的回答,虽然它没有完全回答我的想法,但它确实引导我走向正确的方向。

我的主要问题是我有 2 个独立的项目:1)一个 Spring Boot 项目 2)一个 JS 应用程序。JS 应用程序包含表单 html 本身(或本例中的 JS),因为我不希望任何前端代码来自或来自后端(spring boot 项目),而所有登录逻辑都在 spring boot spring security 中。

如果我禁用 formLogin (我必须这样做,不使用弹簧登录表单)我没有 /login 端点。

总结一下,我想在绕过spring登录表单的同时使用spring security(这种方式后端包含登录逻辑,可以通过任何表单访问,或者就是这个想法)。

虽然我还没有完全到达那里,但我正在到达那里。

对于任何好奇的人,这篇文章有帮助:没有登录表单的弹簧安全性

标签: springspring-security

解决方案


您正在尝试使用 ajax 进行身份验证,因此您不能重定向到依赖于服务器响应的任何其他页面,您应该在您的 JS(例如window.location.href)中执行此操作。

现在让我们谈谈form login你的情况。根据UsernamePasswordAuthenticationFilter您的配置启用。

.formLogin()
    .defaultSuccessUrl("/", true)
    .permitAll()

此过滤器将从请求参数中获取用户名和密码。

protected String obtainUsername(HttpServletRequest request) {
    return request.getParameter(usernameParameter);
}
protected String obtainPassword(HttpServletRequest request) {
    return request.getParameter(passwordParameter);
}

但是您正在尝试将 json 正文发送到服务器,因此它无法获得正确的凭据。您应该将其更改为form请求。

下一个是关于失败重定向 url,现在你应该知道 ajax 不能重定向到其他页面,failureHandler你配置中的默认设置会重定向到登录页面,现在你正在使用 ajax,所以你可以得到 HTML ,我认为您可以仅根据标头(例如 401)验证请求,这是一个示例。

.formLogin()
    .failureHandler(new SimpleUrlAuthenticationFailureHandler())

这是代码SimpleUrlAuthenticationFailureHandler

if (defaultFailureUrl == null) {
    logger.debug("No failure URL set, sending 401 Unauthorized error");
    response.sendError(HttpStatus.UNAUTHORIZED.value(),
                HttpStatus.UNAUTHORIZED.getReasonPhrase());
}

您可以根据标题和正文获得结果。

现在我认为你应该知道defaultSuccessUrl你的配置不会像你期望的那样工作。你需要实现你自己的AuthenticationSuccessHandler.

最后一个是关于你的form身份验证,表单身份验证大部分是基于cookie的,我认为你所有的请求都应该包含登录成功后向服务器发送的cookie。也许你可以研究JWT来代替。


推荐阅读