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

Posted

技术标签:

【中文标题】是否可以在没有重定向服务器的情况下使用 OAuth 2.0?【英文标题】:Is it possible to use OAuth 2.0 without a redirect server? 【发布时间】:2016-11-11 02:41:40 【问题描述】:

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

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

我已经在谷歌上搜索了几个小时,我认为答案是否定的,但我只想确定:

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

我觉得必须拥有自己的在线服务才能接收由 OAuth 2.0 生成的不记名令牌。是否有可能我不能让 SurveyMonkey 直接向我的客户发送不记名令牌?

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

    来自 SurveyMonkey 的 Java 客户端请求不记名令牌,带有 redirect_uri 是我自己的自定义 servlet URL。 SurveyMonkey 将令牌发送到我的自定义 servlet URL。 Java 客户端轮询自定义 servlet URL,直到令牌可用?

这对吗?

【问题讨论】:

我不知道它是否有任何帮助,但对于谷歌身份验证,我通过以下方式获取我的重定向 url: VerificationCodeReceiver receiver = new LocalServerReceiver();接收器=前提条件.checkNotNull(接收器); String redirectUri = receiver.getRedirectUri(); 【参考方案1】:

是的,可以在没有回调 URL 的情况下使用 OAuth2。 RFC6749 引入了几个流程。 Implicit 和 Authorization Code 授权类型需要重定向 URI。但是Resource Owner Password Credentials 授权类型没有。

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

RFC7522:用于 OAuth 2.0 客户端身份验证和授权授予的安全断言标记语言 (SAML) 2.0 配置文件 RFC7523:用于 OAuth 2.0 客户端身份验证和授权授予的 JSON Web 令牌 (JWT) 配置文件 RFC8628:OAuth 2.0 设备授权授权

在任何情况下,如果上述授权类型不符合您的需求,没有什么能阻止您创建custom grant type。

【讨论】:

【参考方案2】:

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

我对 Java 和 Servlet 不是很熟悉,但如果我猜对了,那将是可以处理 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<string> 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<KeyValuePair<string, string>>();
        formData.Add(new KeyValuePair<string, string>("client_secret", _clientSecret));
        formData.Add(new KeyValuePair<string, string>("code", code));
        formData.Add(new KeyValuePair<string, string>("redirect_uri", _redirectUri));
        formData.Add(new KeyValuePair<string, string>("grant_type", GrantType));
        formData.Add(new KeyValuePair<string, string>("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<string, string> tokenInfo = JsonConvert.DeserializeObject<Dictionary<string, string>>(data);
        return(tokenInfo["access_token"]);
    

【讨论】:

我是套接字编程的新手,并且正在开发一个简单的 mac 桌面应用程序。是否有 oauth 在 swift 中监听 localhost 的示例? 找到这个:alexw.me/2013/03/…(迟到总比没有好)【参考方案3】:

不完全是,OAuth 流程的全部意义在于用户(您代表其访问数据的客户)需要授予您访问其数据的权限。

请参阅authentication instructions。您需要将用户发送到 OAuth 授权页面:

https://api.surveymonkey.net/oauth/authorize?api_key<your_key>&client_id=<your_client_id>&response_type=code&redirect_uri=<your_redirect_uri>

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

因此,如果您的重定向 URL 是 https://example.com/surveymonkey/oauth,SurveyMonkey 将使用代码将用户重定向到该 URL:

https://example.com/surveymonkey/oauth?code=&lt;auth_code&gt;

您需要获取该代码,然后通过使用以下帖子参数向https://api.surveymonkey.net/oauth/token?api_key=&lt;your_api_key&gt; 发出 POST 请求,将其交换为访问令牌:

client_secret=<your_secret>
code=<auth_code_you_just_got>
redirect_uri=<same_redirect_uri_as_before>
grant_type=authorization_code

这将返回一个访问令牌,然后您可以使用该访问令牌访问用户帐户中的数据。您不会将访问令牌提供给您用于访问用户帐户的用户。不需要投票或任何东西。

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

【讨论】:

关于设置面板的最后一个建议:我一直在尝试这个以及解决方法,但它似乎不起作用。我认为“我的应用程序”部分中的“访问令牌”是我可以用于私有应用程序的不记名令牌是否正确? @Tovi7 是的,您可以在承载中使用它来访问应用程序所有者的同一帐户。无论应用处于何种状态(禁用除外),它始终可用于访问应用所有者的帐户。 另外,如果您有兴趣,可能会有一种方法可以为您的组中的用户(案例:私人应用程序)或您自己的帐户(client_credentials grant_type)获取访问令牌。如果您有兴趣收到更改通知,可以通过以下方式观看文档:github.com/SurveyMonkey/public_api_docs。 感谢您的回答。花了 2 天的时间,终于弄清楚了重定向 uri 的问题。非常感谢! @Nalin,你最终使用了重定向服务器吗?

以上是关于是否可以在没有重定向服务器的情况下使用 OAuth 2.0?的主要内容,如果未能解决你的问题,请参考以下文章

是否可以在不使用 WooCommerce 重定向到 PayPal 网站的情况下进行 PayPal 付款?

如何在没有 IdentityServer 或 OAuth 的情况下配置 JWT STS

是否可以使用OAuth2 API发布请求设置“重定向URI”? [关闭]

Laravel sanctum 检查用户是不是在没有重定向的情况下通过身份验证

使用自定义标头重定向到外部站点 - AngularJS/OAuth

重定向循环中的 Spring Security OAuth2 (google) web 应用程序