【问题标题】:Spring dropping session when performing cross domain request执行跨域请求时弹出会话
【发布时间】:2015-10-23 16:21:48
【问题描述】:

我正在尝试创建一个 JavaScript 应用程序,仅通过其余接口 (@RestController) 与使用 spring (spring-boot) 编写的后端通信。问题是请求是跨域的,最终在用户登录应用程序后似乎没有建立会话。当我尝试向后端发送新的http请求时,登录后,Principal为空。

这是我的安全配置:

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserService userService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/**").permitAll()
                .and()
                .formLogin()
                    .passwordParameter("password")
                    .usernameParameter("email")
                    .loginPage("/")
                    .failureHandler(new JsonAuthenticationFailureHandler())
                    .successHandler(new JsonAuthenticationSuccessHandler())
                .and()
                .rememberMe()
                .and()
                .logout()
                    .deleteCookies("remember-me")
                    .logoutSuccessUrl("/")
                    .logoutUrl("/logout")
                .and()
                .csrf()
                    .disable();
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth, PasswordEncoder encoder) throws Exception {
        auth.userDetailsService(userService).passwordEncoder(encoder);
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        PasswordEncoder encoder = new BCryptPasswordEncoder();
        return encoder;
    }
}

这是我的 CORS 配置:

@Component
public class SimpleCORSFilter implements Filter {

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
        chain.doFilter(req, res);
    }

    public void init(FilterConfig filterConfig) {}

    public void destroy() {}

}

还有一个我在成功登录后尝试调用的示例控制器:

@RestController
@RequestMapping("/rest/users")
public class UserController extends AbstractRestController {

    @Autowired
    private UserService userService;

    /**
     * Exposed public method for registering the user
     *
     * @param email    email to log in
     * @param password password to log in
     * @return BooleanResponse.result == true if the user registration succeeded without any problems
     */
    @RequestMapping(value = "/register", method = {RequestMethod.POST, RequestMethod.GET})
    public RegistrationResponse register(@RequestParam String email, @RequestParam String password) {
        try {
            userService.createUser(email, password);
        } catch (UserRegistrationException e) {
            return new RegistrationResponse(e.getErrors());
        }
        return new RegistrationResponse(Arrays.asList(RegistrationStatus.SUCCESS));
    }

    /**
     * Determines whether a user with a specific email address already exists
     *
     * @param email email address to be searched for
     * @return BooleanResponse.result = true if the user with the specific email already exists
     */
    @RequestMapping(value = "/userExists", method = {RequestMethod.POST, RequestMethod.GET})
    public BooleanResponse userExists(@RequestParam String email) {
        boolean response = userService.userWithEmailExists(email);
        return new BooleanResponse(response);
    }

    /**
     * Searches for the user info
     *
     * @param principal uniquely identifying the logged in user
     * @return user info for the user with the specified email address
     */
    @RequestMapping(value = "/userInfo", method = RequestMethod.GET)
    public UserInfo getUserInfo(Principal principal) {
        return userService.findUserInfo(principal.getName());
    }


    /**
     * Update info of the currently logged in user
     *
     * @param userInfo new user info provided in the request body
     */
    @RequestMapping(value = "/userInfo", method = RequestMethod.POST)
    public void submitUserInfo(@RequestBody UserInfo userInfo, Principal principal) {
        userService.updateUserInfo(principal.getName(), userInfo);
    }
}

因此,如果用户已登录,submitUserInfo 和 getUserInfo 应该会收到 Principal 对象,但他们没有。我还尝试在 JsonAuthenticationSuccessHandler 中添加会话属性,但是当我将适当的 @SessionAttributes 添加到我的控制器并尝试使用 @ModelAttribute 获取方法内的属性时,我仍然无法获取它,因此假设我的 http 会话不正确成立。

【问题讨论】:

    标签: spring spring-mvc session


    【解决方案1】:

    不知道你如何在 JS 中进行 AJAX 调用。

    如果您使用的是AngularJS,则在进行AJAX调用时需要添加凭据,

    $http({
                        method: 'PUT',
                        url: <rest_api>,
                        withCredentials: true,
                        data: {},
                    })..then(function successCallback(response) {
    

    【讨论】:

    • 我想我以前在某处看到过类似的解决方案,但是使用 jQuery...仍然,你知道这件事实际上改变了请求本身吗?它会以某种有趣的方式修改标题吗?我也在尝试为后端编写 jbehave 验收测试,该测试实际上会生成对服务器的 http 请求,但它们似乎有同样的问题
    • AngularJS 的withCredentials: true 的神奇之处在于在请求 Spring Boot 应用程序提供的 RestAPI 时使用 JSession/Session cookie。
    • 另见 this answer for jquery @KamilMilkaJanowski
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-30
    • 1970-01-01
    • 2018-04-12
    • 2012-08-20
    相关资源
    最近更新 更多