是否可以在没有重定向服务器的情况下使用OAuth 2.0?

我正在尝试创建一个与SurveyMonkey API交互的本地基于Java的客户端。

SurveyMonkey需要使用OAuth 2.0的长期访问令牌,我不是很熟悉。

我一直在谷歌搜索这几个小时,我认为答案是否定的,但我只是想确定:

我是否可以编写一个与SurveyMonkey交互的简单Java客户端, 而无需在某些云中设置我自己的重定向服务器

我觉得必须拥有自己的在线服务才能收到OAuth 2.0生成的持有人令牌。 是否有可能我无法让SurveyMonkey直接向我的客户发送承载令牌?

如果我要在某处设置我自己的自定义Servlet,并将其用作redirect_uri,那么正确的流程如下:

  1. 来自SurveyMonkey的Java客户端请求承载令牌,redirect_uri是我自己的自定义servlet URL。
  2. SurveyMonkey将令牌发送到我的自定义servlet URL。
  3. Java客户端轮询自定义servlet URL,直到令牌可用?

它是否正确?

不完全是,OAuth流程的重点是用户(代表您访问数据的客户端)需要授予您访问其数据的权限。

请参阅身份validation说明 。 您需要将用户发送到OAuth授权页面:

https://api.surveymonkey.net/oauth/authorize?api_key&client_id=&response_type=code&redirect_uri= 

这将向用户显示一个页面,告诉他们您要求访问其帐户的哪些部分(例如,查看他们的调查,查看他们的回复等)。 一旦用户通过单击该页面上的“授权”批准,SurveyMonkey将自动转到您设置的任何重定向URI(确保上面的URL中的一个与您在应用程序的设置中设置的匹配)与代码。

因此,如果您的重定向url为https://example.com/surveymonkey/oauth ,则SurveyMonkey会使用以下代码将用户重定向到该url:

https://example.com/surveymonkey/oauth?code=

您需要获取该代码,然后通过以下post params对https://api.surveymonkey.net/oauth/token?api_key=发出POST请求来交换访问令牌:

 client_secret= code= redirect_uri= grant_type=authorization_code 

这将返回访问令牌,然后您可以使用该访问令牌访问用户帐户上的数据。 您不会将访问令牌提供给您用来访问用户帐户的用户。 无需投票或其他任何事情。

如果您只是访问自己的帐户,则可以使用应用设置页面中提供的访问令牌。 否则,如果没有设置自己的重定向服务器,则无法为用户获取访问令牌(除非所有用户与您在同一个组中,即同一帐户下的多个用户;但我不会进入该目标)。 SurveyMonkey需要一个地方在用户授权后向您发送代码,您不能只请求一个。

是的,可以在没有回调URL的情况下使用OAuth2。 RFC6749引入了几个流程。 隐式和授权代码授权类型需要重定向URI。 但是, 资源所有者密码凭据授予类型不会。

自RFC6749以来,已发布不需要任何重定向URI的其他规范:

  • RFC7522 :OAuth 2.0客户端身份validation和授权授权的安全声明标记语言(SAML)2.0配置文件
  • RFC7523 :用于OAuth 2.0客户端身份validation和授权授权的JSON Web令牌(JWT)配置文件

还有另一个IETF草案试图为有限设备引入另一种授权类型( https://tools.ietf.org/html/draft-ietf-oauth-device-flow ),它不需要任何重定向URI。

在任何情况下,如果上述授权类型不符合您的需求,则不会阻止您创建自定义授权类型 。

确实需要实现一些充当redirect_uri的东西,它不一定需要托管在客户端以外的地方(正如您所说,在某些云中)。

我对Java和Servelets不是很熟悉,但是如果我假设正确的话,那将是可以处理http:// localhost:some_port的东西 。 在这种情况下,您描述的流程是正确的。

我在C#中成功实现了相同的流程。 这是实现该流程的类。 我希望它有所帮助。

 class OAuth2Negotiator { private HttpListener _listener = null; private string _accessToken = null; private string _errorResult = null; private string _apiKey = null; private string _clientSecret = null; private string _redirectUri = null; public OAuth2Negotiator(string apiKey, string address, string clientSecret) { _apiKey = apiKey; _redirectUri = address.TrimEnd('/'); _clientSecret = clientSecret; _listener = new HttpListener(); _listener.Prefixes.Add(address + "/"); _listener.AuthenticationSchemes = AuthenticationSchemes.Anonymous; } public string GetToken() { var url = string.Format(@"https://api.surveymonkey.net/oauth/authorize?redirect_uri={0}&client_id=sm_sunsoftdemo&response_type=code&api_key=svtx8maxmjmqavpavdd5sg5p", HttpUtility.UrlEncode(@"http://localhost:60403")); System.Diagnostics.Process.Start(url); _listener.Start(); AsyncContext.Run(() => ListenLoop(_listener)); _listener.Stop(); if (!string.IsNullOrEmpty(_errorResult)) throw new Exception(_errorResult); return _accessToken; } private async void ListenLoop(HttpListener listener) { while (true) { var context = await listener.GetContextAsync(); var query = context.Request.QueryString; if (context.Request.Url.ToString().EndsWith("favicon.ico")) { context.Response.StatusCode = (int)HttpStatusCode.NotFound; context.Response.Close(); } else if (query != null && query.Count > 0) { if (!string.IsNullOrEmpty(query["code"])) { _accessToken = await SendCodeAsync(query["code"]); break; } else if (!string.IsNullOrEmpty(query["error"])) { _errorResult = string.Format("{0}: {1}", query["error"], query["error_description"]); break; } } } } private async Task SendCodeAsync(string code) { var GrantType = "authorization_code"; //client_secret, code, redirect_uri and grant_type. The grant type must be set to “authorization_code” var client = new HttpClient(); client.BaseAddress = new Uri("https://api.surveymonkey.net"); var request = new HttpRequestMessage(HttpMethod.Post, string.Format("/oauth/token?api_key={0}", _apiKey)); var formData = new List>(); formData.Add(new KeyValuePair("client_secret", _clientSecret)); formData.Add(new KeyValuePair("code", code)); formData.Add(new KeyValuePair("redirect_uri", _redirectUri)); formData.Add(new KeyValuePair("grant_type", GrantType)); formData.Add(new KeyValuePair("client_id", "sm_sunsoftdemo")); request.Content = new FormUrlEncodedContent(formData); var response = await client.SendAsync(request); if (!response.IsSuccessStatusCode) { _errorResult = string.Format("Status {0}: {1}", response.StatusCode.ToString(), response.ReasonPhrase.ToString()); return null; } var data = await response.Content.ReadAsStringAsync(); if (data == null) return null; Dictionary tokenInfo = JsonConvert.DeserializeObject>(data); return(tokenInfo["access_token"]); } }