使用JavaScript搜索四方位置而不暴露客户端密钥

时间:2012-01-01 17:44:29

标签: javascript api oauth-2.0 authentication foursquare

我正在阅读Foursquare API,并试图找到如何将其用于地点搜索(替代Google地方信息)。但是我很惊讶它需要始终提供客户端密钥!。

我在浏览器中使用它,获得响应的唯一方法是在请求中提供客户端密钥和客户端ID。这是“客户端秘密”应该有另一种方式来做到这一点,而不使用客户端秘密。 Google API会检查引荐网址和客户端ID。 Foursquare支持这样的东西吗?

我知道我可以在我的服务器中将请求发送到foursquare并从我的JavaScript客户端代码中调用它。但这将是非常丑陋的(IMO),因为用户必须等待响应时间加倍user -> my-server -> foursquare-api而不仅仅是user -> foursquare-api

我的Web应用程序中的一个页面将使用它:Where can I a great place in the city to see Christmas lights in Boston, MA?,尝试共享提示以便找出(您不必真正发布它!)。

3 个答案:

答案 0 :(得分:2)

这是我从其他开发者那里学到的一个技巧。

它不是代理,但类似。它仍然会从您的IP地址(而不是服务器)发出请求,但是在服务器上进行签名。它不会产生大量的网络流量。

基本上它只是一个签名端点。您在服务器上创建一个页面,该页面仅签署请求但实际上并未执行该页面。然后,使用Location: https://api.foursquare.com/...标头将用户重定向到已签名的页面版本。

请注意,所有签名都在服务器上进行,但实际请求是由客户端进行的。没有秘密暴露,因为它们只在服务器上使用。

答案 1 :(得分:1)

很难看,是的。但我的两分钱:

如果您对安全性的需求大大超过您对速度的需求,那么使用服务器端代理......这基本上是每个人都做的事情,大多数代理都以某种方式伪装,有些是第三方服务,有些是非常小的独立服务rails / express / etc应用程序,有些只是现有应用程序的端点,有些使用google appengine,但不要自欺欺人,大多数人都使用代理。

如果您对速度的需求大大超过您对安全性的需求:那么采用“不安全”的方式来暴露您的密钥。当你从foursquare访问的数据中分离出来自foursquare的用户敏感的数据时,它并没有那么糟糕。你只是分享了一些可能虚假的地理数据,一些可能是虚假的地方数据,好吧,你得到的图片:它不是你用户的财务报表,它是一款名为Foursquare的大型游戏。更糟糕的是,偶尔更改您的API密钥。

IMO,在这样的情况下,没有中间立场,你必须在头脑中保持平衡,以便一个人大大超过另一个人(安全性与速度)。我还没有看到这样一种情况,即两者都是真实而诚实地同等重要,没有任何东西可以被交易。

答案 2 :(得分:0)

代理方法对我有帮助。我的应用程序在嵌入式jetty上运行,我使用ProxyServelt来解决这个问题:

    import java.net.URI;

    import javax.servlet.ServletConfig;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServletRequest;
    import javax.ws.rs.core.UriBuilder;

    import org.eclipse.jetty.client.HttpClient;
    import org.eclipse.jetty.client.api.Request;
    import org.eclipse.jetty.proxy.ProxyServlet;
    import org.eclipse.jetty.util.ssl.SslContextFactory;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;

    public class FoursquareProxyServlet extends ProxyServlet {
        public  static final String FOURSQUARE_API_PREFIX = "foursquare";

    private static final long serialVersionUID = 1L;
    private static final Logger LOG = LoggerFactory.getLogger(FoursquareProxyServlet.class);
    private static final String FOURSQUARE_API_VERSION = "20141026";

    private String apiURL;
    private String clientId;
    private String clientSecret;

    public void init() throws ServletException {
        super.init();

        ServletConfig config = getServletConfig();
        apiURL       = config.getInitParameter("foursquare.apiUrl");
        clientId     = config.getInitParameter("foursquare.clientId");
        clientSecret = config.getInitParameter("foursquare.clientSecret");
    }

    @Override
    protected void customizeProxyRequest(Request proxyRequest, HttpServletRequest request) {
        proxyRequest.getHeaders().remove("Host");
    }

    @Override
    protected URI rewriteURI(HttpServletRequest request) {
        URI uri = UriBuilder.fromUri(this.apiURL)
            .path(request.getRequestURI().replaceAll("/foursquare", ""))
            .replaceQuery(request.getQueryString().trim())
            .queryParam("client_id", this.clientId)
            .queryParam("client_secret", this.clientSecret)
            .queryParam("v", FOURSQUARE_API_VERSION)
            .build();

        return uri;
    }

    protected HttpClient newHttpClient() {
        SslContextFactory sslContextFactory = new SslContextFactory();
        HttpClient httpClient = new HttpClient(sslContextFactory);
        return httpClient;
    }
}

然后你只需将它插入你的服务器:

protected ServletContextHandler createFoursquareProxy() {
    ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
    context.setContextPath("/"+FoursquareProxyServlet.FOURSQUARE_API_PREFIX+"/*");

    ServletHolder foursquareProxy = new ServletHolder("foursquare", new FoursquareProxyServlet());
    foursquareProxy.setInitParameter("foursquare.apiUrl", this.foursquareApiUrl);
    foursquareProxy.setInitParameter("foursquare.clientId", this.foursquareClientId);
    foursquareProxy.setInitParameter("foursquare.clientSecret", this.foursquareClientSecret);

    context.addServlet(foursquareProxy, "/*");
    return context;
}

在这种情况下,您的请求将如下所示:

GET http://{host}:{port}/foursquare/venues/search?&ll=40.7,-74%20&query=sushi

我确定你能够找到与你的筹码类似的东西。