【问题标题】:CORS Unauthorized 401 error when calling spring rest api调用spring rest api时出现CORS未经授权的401错误
【发布时间】:2019-07-14 20:13:20
【问题描述】:

我的休息服务中没有 Spring Security 实现,并且在尝试调用休息中的资源时遇到 CORS 401 Unauthorized 问题。

我很生气:

https://www.baeldung.com/spring-security-cors-preflight

https://docs.spring.io/spring-security/site/docs/5.0.7.RELEASE/reference/html5/#cors

我有 2 个电话要休息:

1) 登录

2) 其他

登录功能基于 Shiro,例如当我从 Postman 执行登录然后尝试调用其他资源时它可以工作。

当我开始使用 react 实现客户端应用程序并尝试从 fetch javascript 方法调用其余应用程序时,我的问题就开始了。我在第一次调用登录时遇到了 CORS 问题,我通过向我的控制器添加 @CorsOrigin 注释来解决它,但是在登录成功后,第二次调用仍然在 cors 401 上失败。

如果我理解正确,可以通过向 oWebSecurityConfig 添加过滤器来解决 CORS,但如果我的应用程序是从 Postman 运行的,则无需在我的服务器端应用程序中执行此类更改,我想从客户端解决它。

这让我可以选择在我的请求中传递 JSESSIONID,对吧?! 我仍然不知道该怎么做......我应该从哪里获取 JSESSIONID?我尝试读取浏览器的 cookie,但没有找到它...我尝试从第一次调用 Login 的响应标头中获取它,但响应为空!

尝试在服务器端使用 Spring 解决它,但没有成功:

WebSecurityConfig:

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {

//        http
//        .cors();
//        .headers().disable();

//      http
//        .authorizeRequests()
//        .requestMatchers(CorsUtils::isCorsRequest).permitAll()
//        .anyRequest().authenticated()
//        .and().httpBasic()
//        .and().addFilterBefore(new WebSecurityCorsFilter(), ChannelProcessingFilter.class);

        http.addFilterBefore(new CorsFilter(), ChannelProcessingFilter.class);

    }
}

WebSecurityCorsFilter:

public class WebSecurityCorsFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    HttpServletResponse res = (HttpServletResponse) response;
    res.setHeader("Access-Control-Allow-Origin", "*");
    res.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT");
    res.setHeader("Access-Control-Max-Age", "3600");
    res.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type, Accept, x-requested-with, Cache-Control");
    chain.doFilter(request, res);
}

@Override
public void destroy() {
}

}

或者,CorsFilter(使用它们中的一个):

@Component
//@Order(Ordered.HIGHEST_PRECEDENCE)
public class CorsFilter implements Filter{

public CorsFilter () {
    super();
}

@Override
public final void doFilter(final ServletRequest req, final ServletResponse res, final FilterChain chain) throws IOException, ServletException {
    final HttpServletResponse response = (HttpServletResponse) res;
    response.setHeader("Access-Control-Allow-Origin", "http://localhost:3000");

    // without this header jquery.ajax calls returns 401 even after successful login and SSESSIONID being succesfully stored.
    response.setHeader("Access-Control-Allow-Credentials", "true");

    response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
    response.setHeader("Access-Control-Max-Age", "3600");
    response.setHeader("Access-Control-Allow-Headers", "X-Requested-With, Authorization, Origin, Content-Type, Version");
    response.setHeader("Access-Control-Expose-Headers", "X-Requested-With, Authorization, Origin, Content-Type");

    final HttpServletRequest request = (HttpServletRequest) req;
    if (!request.getMethod().equals("OPTIONS")) {
        chain.doFilter(req, res);
    } else {
        // do not continue with filter chain for options requests
    }
}

@Override
public void destroy() {

} 

@Override
public void init(FilterConfig filterConfig) throws ServletException {       
}
}

【问题讨论】:

  • 我已经尝试过这种方法,但没有帮助:~(用代码更新了我的帖子)
  • 您是否在请求标头中传递了JSESSIONID?
  • 不,这是我的主要问题......怎么做?从哪里得到它?如果我从 chrome 开发工具检查 cookie --> 网络选项卡,我看不到任何附加到我的请求的 cookie!我试图从登录第一次调用的响应中获取它,但响应是空的,没有标题......也许我需要手动填充它作为响应(从服务器控制器端)?我在帖子中添加了登录资源代码
  • 可能需要在我的服务器容器 (tomcat) 上做一些事情来启用 JSESSIONID?

标签: spring-security cors fetch


【解决方案1】:

感谢这个类似的获取问题:https://github.com/github/fetch/issues/386

我终于成功了。所以,总结一下:

1) 无需更改 Spring Security Config,除了将此注解添加到控制器(您可以将其添加到基本控制器一次,并且所有人都可以从它继承)

@CrossOrigin(origins = " * ", allowedHeaders = " * ")

2) 从客户端,当使用 fetch 我必须使用 两个 请求(登录和第二个):

凭证:'include', //'same-origin'

(请注意,使用 cors 时不要使用凭据的“同源”值)

无需手动设置cookies,浏览器自行处理(如果你需要写Java客户端,那就需要了……你可以搜索CookiesManagement java类,你会找到这样的实现)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-02-09
    • 2020-12-17
    • 1970-01-01
    • 2021-04-07
    • 1970-01-01
    • 2019-06-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多