如何强制 UriBuilder 使用 https?
How can I force UriBuilder to use https?
我目前 运行 Apache httpd 背后的 Dropwizard 作为反向代理,配置如下:
<VirtualHost *:443>
<Location /api>
ProxyPass "http://my.app.org:8080/api"
<Location>
...
</VirtualHost>
使用其他 Location
服务于静态资产的设置和一些身份验证。现在,httpd 还执行 SSL 卸载,所以我的 Dropwizard 只接收纯 HTTP 请求。
在我的 Dropwizard API 中,我喜欢 return 一个 Location
header 指示新创建的资源:
@Path("/comment")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
class CommentResource() {
@PUT
fun create(@Context uri: UriInfo, entity: EventComment): Response {
val stored: EventComment = createEntity(entity)
return Response.created(uri.baseUriBuilder.path(MessageStream::class.java)
.resolveTemplate("realmish", entity.realmId)
.path(stored.id.toString()).build()).build()
}
这将创建一个 Response
,其中 Location
header 来自 JerseyUriBuilder
:
Location http://my.app.org/api/messages/123
在我的 SSL-only 应用程序上,自然无法加载(我真的很惊讶这并没有呈现为 http://my.app.org:8080/api/messages/123
- 可能也是 [=19= 的原因] 没有帮助)。
我知道我可以使用 baseUriBuilder.scheme("https")
强制该方案为 https,但这会重复并且很容易出错。
因此我的问题:我怎样才能使 Jersey 生成正确的 front-end URL 或成功地使 httpd 重写由 Dropwizard 生成的那些?
对于 Jersey,您可以使用 pre-matching ContainerRequestFilter
来重写 URI。例如
@PreMatching
public class SchemeRewriteFilter implements ContainerRequestFilter {
@Override
public void filter(ContainerRequestContext request) throws IOException {
URI newUri = request.getUriInfo().getRequestUriBuilder().scheme("https").build();
request.setRequestUri(newUri);
}
}
然后用 Jersey (Dropwizard) 注册它
env.jersey().register(SchemeRewriteFilter.class);
编辑
以上仅在您使用 uriInfo.getAbsolutePathBuilder()
时有效。如果你想使用 uriInfo.getBaseUriBuilder()
,那么你需要使用接受基本 uri 作为第一个参数的重载 setRequestUri
。
URI newUri = request.getUriInfo().getRequestUriBuilder().scheme("https").build();
URI baseUri = request.getUriInfo().getBaseUriBuilder().scheme("https").build();
request.setRequestUri(baseUri, newUri);
如果使用 Jetty,则可以通过在服务器上注册 org.eclipse.jetty.server.ForwardedRequestCustomizer
来避免黑客攻击。这将查看 X-Forwarded-*
headers 以构建基本 URI。
使用嵌入式 Jetty 的示例:
Server jettyServer = new Server();
HttpConfiguration config = new HttpConfiguration();
config.addCustomizer(new ForwardedRequestCustomizer());
ServerConnector serverConnector = new ServerConnector(jettyServer,
new HttpConnectionFactory(config));
serverConnector.setPort(8080);
jettyServer.setConnectors(new Connector[] {serverConnector});
无论您是否在反向代理后面,这似乎都有效,所以我不知道为什么默认情况下不启用它。
我目前 运行 Apache httpd 背后的 Dropwizard 作为反向代理,配置如下:
<VirtualHost *:443>
<Location /api>
ProxyPass "http://my.app.org:8080/api"
<Location>
...
</VirtualHost>
使用其他 Location
服务于静态资产的设置和一些身份验证。现在,httpd 还执行 SSL 卸载,所以我的 Dropwizard 只接收纯 HTTP 请求。
在我的 Dropwizard API 中,我喜欢 return 一个 Location
header 指示新创建的资源:
@Path("/comment")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
class CommentResource() {
@PUT
fun create(@Context uri: UriInfo, entity: EventComment): Response {
val stored: EventComment = createEntity(entity)
return Response.created(uri.baseUriBuilder.path(MessageStream::class.java)
.resolveTemplate("realmish", entity.realmId)
.path(stored.id.toString()).build()).build()
}
这将创建一个 Response
,其中 Location
header 来自 JerseyUriBuilder
:
Location http://my.app.org/api/messages/123
在我的 SSL-only 应用程序上,自然无法加载(我真的很惊讶这并没有呈现为 http://my.app.org:8080/api/messages/123
- 可能也是 [=19= 的原因] 没有帮助)。
我知道我可以使用 baseUriBuilder.scheme("https")
强制该方案为 https,但这会重复并且很容易出错。
因此我的问题:我怎样才能使 Jersey 生成正确的 front-end URL 或成功地使 httpd 重写由 Dropwizard 生成的那些?
对于 Jersey,您可以使用 pre-matching ContainerRequestFilter
来重写 URI。例如
@PreMatching
public class SchemeRewriteFilter implements ContainerRequestFilter {
@Override
public void filter(ContainerRequestContext request) throws IOException {
URI newUri = request.getUriInfo().getRequestUriBuilder().scheme("https").build();
request.setRequestUri(newUri);
}
}
然后用 Jersey (Dropwizard) 注册它
env.jersey().register(SchemeRewriteFilter.class);
编辑
以上仅在您使用 uriInfo.getAbsolutePathBuilder()
时有效。如果你想使用 uriInfo.getBaseUriBuilder()
,那么你需要使用接受基本 uri 作为第一个参数的重载 setRequestUri
。
URI newUri = request.getUriInfo().getRequestUriBuilder().scheme("https").build();
URI baseUri = request.getUriInfo().getBaseUriBuilder().scheme("https").build();
request.setRequestUri(baseUri, newUri);
如果使用 Jetty,则可以通过在服务器上注册 org.eclipse.jetty.server.ForwardedRequestCustomizer
来避免黑客攻击。这将查看 X-Forwarded-*
headers 以构建基本 URI。
使用嵌入式 Jetty 的示例:
Server jettyServer = new Server();
HttpConfiguration config = new HttpConfiguration();
config.addCustomizer(new ForwardedRequestCustomizer());
ServerConnector serverConnector = new ServerConnector(jettyServer,
new HttpConnectionFactory(config));
serverConnector.setPort(8080);
jettyServer.setConnectors(new Connector[] {serverConnector});
无论您是否在反向代理后面,这似乎都有效,所以我不知道为什么默认情况下不启用它。