在我的web应用程序中,我需要调用不同的web服务(由我开发/管理),以通过rest API启动/管理资源。Web服务在tomcat6上运行。我可以从浏览器日志中看到POST请求正在通过,但GET请求被禁止。如果我从web服务本身进行相同的调用,那么我没有看到任何问题。我已经为tomcat6定义了跨源过滤器,并在支持的方法中提到了GET,但问题仍然存在。。
我已经在应用程序服务器级别的web.xml中以这种方式定义了跨源过滤器。我使用的CORS过滤器库来自http://software.dzhuvinov.com/cors-filter.html.这是一个tomcat6服务器,过滤器已在($tomcat6_HOME/conf/web.xml)中定义如下
<filter>
<filter-name>CORS</filter-name>
<filter-class>com.thetransactioncompany.cors.CORSFilter</filter-class>
<init-param>
<param-name>cors.allowOrigin</param-name>
<param-value>*</param-value>
</init-param>
<init-param>
<param-name>cors.supportedMethods</param-name>
<param-value>GET, POST, HEAD, PUT, DELETE, OPTIONS</param-value>
</init-param>
<init-param>
<param-name>cors.supportedHeaders</param-name>
<param-value>*</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CORS</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
奇怪的是,Web服务接受POST调用,但对于GET调用,它抛出403-Forbidden错误,告诉"已禁止访问指定资源"。
GET调用的标头如下
Request URL:https://remote.vm.mycompany.com/remote/tunnel?read:c2faeb31-4147-49e8-b8d3-53d89496e5ca:0
Request Method:GET
Status Code:403 Forbidden
Request Headersview source
Accept:*/*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8
Connection:keep-alive
Host:remote.vm.mycompany.com
Origin:https://ec2-184-72-200-91.compute-1.amazonaws.com
Referer:https://ec2-184-72-200-91.compute-1.amazonaws.com/
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.71 Safari/537.36
Query String Parametersview sourceview URL encoded
read:c2faeb31-4147-49e8-b8d3-53d89496e5ca:0:
Response Headersview source
Access-Control-Allow-Credentials:true
Access-Control-Allow-Origin:https://ec2-184-72-200-91.compute-1.amazonaws.com
Content-Length:961
Content-Type:text/html;charset=utf-8
Date:Sun, 21 Jul 2013 17:17:37 GMT
Server:Apache-Coyote/1.1
Tomcat访问日志还显示GET请求已被禁止,但在的任何日志中都没有给出任何线索
- - - [21/Jul/2013:17:17:37 +0000] POST /remote/tunnel?connect HTTP/1.1 200 -
- - - [21/Jul/2013:17:17:37 +0000] GET /remote/tunnel?read:c2faeb31-4147-49e8-b8d3-53d89496e5ca:0 HTTP/1.1 403 -
这是我的servlet代码。我正在尝试集成鳄梨酱(HTML5VNC客户端即Web服务)
package com.mycompany.html5remote;
import java.util.Arrays;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.sourceforge.guacamole.GuacamoleException;
import net.sourceforge.guacamole.net.GuacamoleSocket;
import net.sourceforge.guacamole.net.GuacamoleTunnel;
import net.sourceforge.guacamole.net.InetGuacamoleSocket;
import net.sourceforge.guacamole.protocol.ConfiguredGuacamoleSocket;
import net.sourceforge.guacamole.protocol.GuacamoleClientInformation;
import net.sourceforge.guacamole.protocol.GuacamoleConfiguration;
import net.sourceforge.guacamole.servlet.GuacamoleHTTPTunnelServlet;
import net.sourceforge.guacamole.servlet.GuacamoleSession;
public class HttpTunnel extends GuacamoleHTTPTunnelServlet {
private Logger logger = LoggerFactory.getLogger(HttpTunnel.class);
@Override
protected GuacamoleTunnel doConnect(HttpServletRequest request) throws GuacamoleException {
HttpSession httpSession = request.getSession(true);
logger.info("Inside doConnect Method.");
GuacamoleClientInformation info = new GuacamoleClientInformation();
String hostname = request.getParameter("hostname");
String protocol = request.getParameter("protocol");
// Create socket
GuacamoleConfiguration config = new GuacamoleConfiguration();
config.setProtocol(protocol);
config.setParameter("hostname", hostname);
//config.setParameter("hostname", "ec2-184-73-104-108.compute-1.amazonaws.com");
if("vnc".equals(protocol)){
config.setParameter("port", "5901");
}else if ("rdp".equals(protocol)){
config.setParameter("port", "3389");
}else{
config.setParameter("port", "22");
}
logger.info("Set the configuration. Creating the socket connection now..");
// Return connected socket
GuacamoleSocket socket = new ConfiguredGuacamoleSocket(
new InetGuacamoleSocket("localhost", 4822),
config, info
);
logger.info("Successfully created socket connection.");
// Create tunnel from now-configured socket
GuacamoleTunnel tunnel = new GuacamoleTunnel(socket);
// Attach tunnel
GuacamoleSession session = new GuacamoleSession(httpSession);
session.attachTunnel(tunnel);
logger.info("Done");
return tunnel;
}
}
GuacamoleHTTPTunnelServlet(GPL许可)的文档在这里
我可能错过了什么?还有其他地方我可以寻找线索吗?请帮助
您是否有任何与web.xml中配置的http方法相关的安全约束?我不确定你为什么选择一个单独的api来过滤你的请求?
我花了几天时间试图将我的Spring Boot与Apache Guacamole后端连接到我的NextJS前端,下面是适用于我的解决方案(参考StackOverflow上的这个问题):
问题有两个主要部分,CORS和CSRF。首先,创建一个新的Java类,并使用Guacamole所需的头和方法以及前端服务器的来源等内容设置CORS配置。这确保了Spring Boot服务器将使用正确的CORS头来响应来自前端的请求,这样它就不会被浏览器阻止。
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("http://localhost:3000"));
configuration.setAllowedMethods(Arrays.asList("*"));
configuration.setAllowedHeaders(Arrays.asList("*"));
configuration.setAllowCredentials(true);
configuration.setExposedHeaders(Arrays.asList("Guacamole-Status-Code", "Guacamole-Error-Message", "Guacamole-Tunnel-Token"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
其次,在正确的CORS配置下,POST请求以"0"结束/地下通道"连接";但是随后的GET请求以"0"结尾/地下通道读:一些数字和文本:0";仍将被阻止。这就是CSRF的作用所在,因为由于Spring Security的默认CSRF保护,请求可能被拒绝。因此,只需创建一个新的SecurityFilterChain并指定行";http.cors().and().csrf().disable()&";,禁用CSRF(您可以稍后对此进行配置)。POST请求将被接受,并且可以启动Apache Guacamole隧道。
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
// Adds a CorsFilter to be used. If a bean by the name of corsFilter is provided, that CorsFilter is used.
// Else if corsConfigurationSource is defined, then that CorsConfiguration is used.
http.cors().and().csrf().disable();
return http.build();
}
以下是完整的Java类:
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
// Adds a CorsFilter to be used. If a bean by the name of corsFilter is provided, that CorsFilter is used.
// Else if corsConfigurationSource is defined, then that CorsConfiguration is used.
http.cors().and().csrf().disable();
return http.build();
}
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("http://localhost:3000"));
configuration.setAllowedMethods(Arrays.asList("*"));
configuration.setAllowedHeaders(Arrays.asList("*"));
configuration.setAllowCredentials(true);
configuration.setExposedHeaders(Arrays.asList("Guacamole-Status-Code", "Guacamole-Error-Message", "Guacamole-Tunnel-Token"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}