Spring Boot安全认证 - 302重定向

7

我正在尝试测试我的Web API,该API使用标准的Spring Security API进行安全保护。我已经通过实现UserDetailService来实现了自己的用户认证服务。然而,每当我登录应用程序时,/login API都会返回302重定向。我通过手动测试好的凭据和错误的凭据验证了我的登录页面正常工作,并且根据凭据是否正确地正确身份验证到主页,但仍然为/login返回302。我想知道为什么Spring/Thymeleaf在执行/login请求时会返回302重定向。这将防止我测试任何被Spring Security锁定的受保护端点的能力。

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;

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

@Bean
public JwtTokenFilter jwtTokenFilter() {
    return new JwtTokenFilter();
}

@Override
protected void configure(HttpSecurity http) throws Exception {

    http
            .csrf()
            .disable()
            .cors()
            .and()
            .authorizeRequests().antMatchers("/profiles/**","/img/**","/resources","/v2/**","/users", "/login", "/error/**", "/keepalive", "/register").permitAll()
            .anyRequest().authenticated()
            .and()
            .formLogin()
            .loginPage("/login").permitAll()
            .defaultSuccessUrl("/")
            .permitAll()
            .and()
            .logout();

    http.addFilterBefore(jwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
}

@Bean
public CorsConfigurationSource corsConfigurationSource() {
    final CorsConfiguration configuration = new CorsConfiguration();
    configuration.setAllowedOrigins(asList("*"));
    configuration.setAllowedMethods(asList("HEAD",
            "GET", "POST", "PUT", "DELETE", "PATCH"));
    // setAllowCredentials(true) is important, otherwise:
    // The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.
    configuration.setAllowCredentials(true);
    // setAllowedHeaders is important! Without it, OPTIONS preflight request
    // will fail with 403 Invalid CORS request
    configuration.setAllowedHeaders(asList("Authorization", "Cache-Control", "Content-Type"));
    final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", configuration);
    return source;
}

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
}

登录页面

   <!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
>
<head>
    <title>Login</title>
    <div th:replace="fragments/header :: header-css"/>
</head>
<body class="white-bg">

<div th:replace="fragments/header :: header"/>

    <div class="middle-box text-center loginscreen">
        <div>
            <div>

                <h1 class="logo-name"></h1>

            </div>
        <h3>Welcome to </h3>

        <p>Login in. To see it in action.</p>
        <form th:action="@{/login}" method="post">
            <fieldset>
                <div th:if="${param.error}">
                    <div class="alert alert-danger">
                        Invalid username and password.
                    </div>
                </div>
                <div th:if="${param.logout}">
                    <div class="alert alert-info">
                        You have been logged out.
                    </div>
                </div>

                <div class="form-group">
                    <input type="text" name="username" id="username" class="form-control"
                           placeholder="UserName" required="true" autofocus="true"/>
                </div>
                <div class="form-group">
                    <input type="password" name="password" id="password" class="form-control"
                           placeholder="Password" required="true"/>
                </div>
                <input type="submit" class="btn btn-lg btn-primary btn-block" value="Sign In"/>

                <a href="#"><small>Forgot password?</small></a>
                <p class="text-muted text-center"><small>Do not have an account?</small></p>
                <a class="btn btn-sm btn-white btn-block" href="register.html">Create an account</a>
            </fieldset>
        </form>
        <p class="m-t"> <small>DigiProof Company &copy; 2017</small> </p>
    </div>
</div>

BaseController.java 用于路由

@Controller
public class BaseController {

    @Autowired
    private UserService userService;

    @GetMapping("/")
    public String homeMain() {
        return "home";
    }

    @GetMapping("/home")
    public String home() {
        return "home";
    }

    @GetMapping("/login")
    public String login(Principal principal) {
        if (principal!=null && ((Authentication)principal).isAuthenticated())
            return "redirect:/home";
        else
            return "login";
    }

    @RequestMapping(value="/registration", method = RequestMethod.GET)
    public ModelAndView registration(){
        ModelAndView modelAndView = new ModelAndView();
        User user = new User();
        modelAndView.addObject("user", user);
        modelAndView.setViewName("register");
        return modelAndView;
    }

    @RequestMapping(value = "/registration", method = RequestMethod.POST)
    public ModelAndView createNewUser(@Valid User user, BindingResult bindingResult) {
        ModelAndView modelAndView = new ModelAndView();
        User userByEmailExists = userService.findUserByEmail(user.getEmail());
        if (userByEmailExists != null) {
            bindingResult
                    .rejectValue("email", "error.user",
                            "There is already a user registered with the email provided");
        }
        if (bindingResult.hasErrors()) {
            modelAndView.setViewName("register");
        } else {
            userService.save(user);
            modelAndView.addObject("successMessage", "User has been registered successfully");
            modelAndView.addObject("user", new User());
            modelAndView.setViewName("register");
        }
        return modelAndView;
    }

    @GetMapping("/profile")
    public String profile() {
        return "profile";
    }

    @GetMapping("/activity")
    public String activity() {
        return "activity";
    }

    @GetMapping("/teams")
    public String teams() {
        return "teams";
    }

    @GetMapping("/404")
    public String error404() {
        return "/error/403";
    }

    @GetMapping("/403")
    public String error403() {
        return "/error/403";
    }

    @GetMapping("/500")
    public String error500() {
        return "/error/500";
    }

    @GetMapping("/error")
    public String error() {
        return "/error/500";
    }


}
2个回答

4

Spring Security的formLogin默认拦截了“/login”请求,我发现你的登录页面URL是“/login”,这与该过滤器冲突。你可以这样定义你的登录页面URL:

.formLogin()
        .loginPage("/page/login.html").permitAll()

并将控制器映射从login更改为/page/login


-4
尝试禁用 CSRF。
@Override
protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable()
}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接