如何在Heroku上使用restlet在某些URL上强制使用SSL

时间:2012-02-04 22:30:34

标签: java ssl heroku jetty restlet

我在heroku上运行了一个基于restlet的应用程序,我想使用SSL。我启用了基本的“搭载”ssl选项,因此它接受ssl连接 - 几乎就在那里!但是,我希望某些(实际上,可能是所有)URL仅在用户通过ssl连接时才起作用。现在(我被告知)Heroku将SSL转换为非ssl调用并将HTTP_X_FORWARDED_PROTO设置为https,所以我认为我需要在restlet中处理这个问题,但我不知道如何处理。我看到Redirector类,但我不清楚我是否可以使用这个类来解决这个问题。

注意:我以前使用GAE运行我的应用程序,GAE使用了servlet容器,所以我可以在web.xml中指定“CONFIDENTIAL”。

谢谢!

1 个答案:

答案 0 :(得分:2)

您可以从HTTP请求标头中获取信息,然后决定是否要抛出错误或重定向:

    Form requestHeaders = (Form) this.getRequest().getAttributes().get("org.restlet.http.headers");

    boolean secure = false;
    if (requestHeaders.getValues("x-forwarded-proto") != null) {
        secure = requestHeaders.getValues("x-forwarded-proto").contains("https");
    }

展开此功能,您可以创建一个可轻松应用于路线的过滤器。完整的代码示例是on GitHub。但这是基本的SecureFilter:

public class SecureFilter extends Filter {

    private boolean doRedirect;

    public SecureFilter(Context context, Restlet next) {
        super(context);
        doRedirect = false;
        setNext(next);
    }

    public SecureFilter(Context context, Restlet next, boolean doRedirect) {
        super(context);
        this.doRedirect = doRedirect;
        setNext(next);
    }

    public SecureFilter(Context context, Class<?> next) {
        super(context);
        doRedirect = false;
        setNext(next);
    }

    public SecureFilter(Context context, Class<?> next, boolean doRedirect) {
        super(context);
        this.doRedirect = doRedirect;
        setNext(next);
    }

    public boolean isDoRedirect() {
        return doRedirect;
    }

    public void setDoRedirect(boolean doRedirect) {
        this.doRedirect = doRedirect;
    }

    @Override
    protected int beforeHandle(Request request, Response response) {
        Form requestHeaders = (Form) request.getAttributes().get("org.restlet.http.headers");

        if ((requestHeaders.getValues("x-forwarded-proto") != null) && (requestHeaders.getValues("x-forwarded-proto").indexOf("https") != 0)) {
            if (doRedirect) {
                String target = "https://" + request.getHostRef().getHostDomain() + request.getResourceRef().getPath();
                Redirector redirector = new Redirector(getContext(), target, Redirector.MODE_CLIENT_SEE_OTHER);
                redirector.handle(request, response);
                return STOP;
            }
            else {
                response.setStatus(Status.CLIENT_ERROR_FORBIDDEN);
                return STOP;
            }
        }

        return CONTINUE;
    }

}

要使用SecureFilter,只需包装路由/资源映射:

    router.attach("/secure", new SecureFilter(getContext(), HelloSecureResource.class));
    router.attach("/secureWithRedirect", new SecureFilter(getContext(), HelloSecureResource.class, true));