Spring Boot安全认证 - 302重定向

时间:2017-12-05 17:17:22

标签: spring spring-mvc spring-boot spring-security

我正在尝试使用标准的Spring Security API测试我的web api。我通过实现UserDetailService实现了自己的用户身份验证服务。但是,每当我登录到我的应用程序时,/ login api都会继续返回302重定向。我通过手动测试好的凭据和错误的凭据验证了我的登录页面是否正常工作,并且根据凭据是否良好,它确实正确地对主页进行了正确的身份验证,但它仍然返回302 for / login。我想知道为什么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());
}

Login.html页面

   <!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 个答案:

答案 0 :(得分:0)

spring security formLogin默认拦截“/ login”请求,我发现你的登录页面url是“/ login”,这与这个过滤器有冲突。您可以像这样定义您的登录页面网址:

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

然后从登录中更改控制器映射 - &gt; /页/登录

答案 1 :(得分:0)

尝试禁用csrf

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable()
}