spring-security - 调用spring rest api时出现CORS未经授权的401错误
问题描述
我的休息服务中没有 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
我有两个电话要休息:
1) 登录
2) 其他
登录功能基于 Shiro,例如,当我从 Postman 执行登录然后尝试调用其他资源时,它可以工作。
当我开始使用 react 实现客户端应用程序并尝试从 fetch javascript 方法中调用其余应用程序时,我的问题就开始了。我在第一次调用登录时遇到了 CORS 问题,我通过向我的控制器添加 @CorsOrigin 注释来解决它,但是在登录成功后,第二次调用仍然在 cors 401 上失败。
如果我正确理解,可以通过向 oWebSecurityConfig 添加过滤器来解决 CORS,但是如果我的应用程序是从 Postman 工作的,那么就不需要在我的服务器端应用程序中执行这样的更改,我想从客户端解决它。
这让我可以选择在我的请求中传递 JSESSIONID,对吧?!我仍然不知道该怎么做......我应该从哪里获取 JSESSIONID?我尝试读取浏览器的 cookie,但没有找到它...我尝试从第一次调用 Login 的响应标头中获取它,但响应为空!
试图在服务器端使用 Spring 解决它,但没有运气:
网络安全配置:
@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 {
}
}
解决方案
感谢这个类似的获取问题:https ://github.com/github/fetch/issues/386
我终于成功了。所以,总结一下:
1) 不需要 Spring Security Config 更改,除了将此注释添加到控制器(您可以将其添加到基本控制器一次,并且都可以从它继承)
@CrossOrigin(origins = " * ", allowedHeaders = " * ")
2)从客户端,当使用 fetch 我必须从两个请求(登录和第二个)中使用:
凭据:“包括”,//“同源”
(请注意,使用 cors 时不要使用凭据的“同源”值)
无需手动设置任何cookie,浏览器应处理(如果您需要编写Java客户端,则需要...您可以搜索CookiesManagement java类,您会找到这样的实现)
推荐阅读
- java - 有没有办法将响应实体存储在 redis 缓存中?
- logstash - Sequel + Logstash JDBC 输入:处理列名中的方括号
- javascript - 如何使用弹出框描述显示数字而不是点
- python - 如何向 message.delete() 添加延迟?
- python - 如何在pygame中显示一个带有可移动透明圆圈的大黑色矩形?
- gradle - 从 Spring Contract 的合约和基类测试的默认“test”目录更改
- hibernate - Grails4:dynamicUpdate:多对一外键即使不脏也会更新
- entity-framework-core - 我无法运行迁移(使用 .net core 3.0 和实体框架)
- javascript - 使用 chrome ext 右键单击文本区域中的选定文本
- docker - Hyperledger-Fabric 中从 leveldb 更改为 couchdb 时是否需要更改端口号