23

我正在尝试使用 Google+ API 访问经过身份验证的用户的信息。我已经从其中一个示例中复制了一些代码,这些代码可以正常工作(如下),但是我无法让它以一种我可以在应用程序启动时重用令牌的方式工作。

我尝试捕获“RefreshToken”属性并使用provider.RefreshToken()(除其他外)并始终得到400 Bad Request响应。

有谁知道如何进行这项工作,或者知道我在哪里可以找到一些样品?谷歌代码网站似乎没有涵盖这一点:-(

class Program
{
    private const string Scope = "https://www.googleapis.com/auth/plus.me";

    static void Main(string[] args)
    {
        var provider = new NativeApplicationClient(GoogleAuthenticationServer.Description);
        provider.ClientIdentifier = "BLAH";
        provider.ClientSecret = "BLAH";
        var auth = new OAuth2Authenticator<NativeApplicationClient>(provider, GetAuthentication);

        var plus = new PlusService(auth);
        plus.Key = "BLAH";
        var me = plus.People.Get("me").Fetch();
        Console.WriteLine(me.DisplayName);
    }

    private static IAuthorizationState GetAuthentication(NativeApplicationClient arg)
    {
        // Get the auth URL:
        IAuthorizationState state = new AuthorizationState(new[] { Scope });
        state.Callback = new Uri(NativeApplicationClient.OutOfBandCallbackUrl);
        Uri authUri = arg.RequestUserAuthorization(state);

        // Request authorization from the user (by opening a browser window):
        Process.Start(authUri.ToString());
        Console.Write("  Authorization Code: ");
        string authCode = Console.ReadLine();
        Console.WriteLine();

        // Retrieve the access token by using the authorization code:
        return arg.ProcessUserAuthorization(authCode, state);
    }
}
4

5 回答 5

20

这是一个例子。确保添加名为 RefreshToken 的字符串设置并引用 System.Security 或找到另一种安全存储刷新令牌的方法。

    private static byte[] aditionalEntropy = { 1, 2, 3, 4, 5 };

    private static IAuthorizationState GetAuthorization(NativeApplicationClient arg)
    {
        // Get the auth URL:
        IAuthorizationState state = new AuthorizationState(new[] { PlusService.Scopes.PlusMe.GetStringValue() });
        state.Callback = new Uri(NativeApplicationClient.OutOfBandCallbackUrl);

        string refreshToken = LoadRefreshToken();
        if (!String.IsNullOrWhiteSpace(refreshToken))
        {
            state.RefreshToken = refreshToken;

            if (arg.RefreshToken(state))
                return state;
        }

        Uri authUri = arg.RequestUserAuthorization(state);

        // Request authorization from the user (by opening a browser window):
        Process.Start(authUri.ToString());
        Console.Write("  Authorization Code: ");
        string authCode = Console.ReadLine();
        Console.WriteLine();

        // Retrieve the access token by using the authorization code:
        var result = arg.ProcessUserAuthorization(authCode, state);

        StoreRefreshToken(state);
        return result;
    }

    private static string LoadRefreshToken()
    {
        return Encoding.Unicode.GetString(ProtectedData.Unprotect(Convert.FromBase64String(Properties.Settings.Default.RefreshToken), aditionalEntropy, DataProtectionScope.CurrentUser));
    }

    private static void StoreRefreshToken(IAuthorizationState state)
    {
        Properties.Settings.Default.RefreshToken = Convert.ToBase64String(ProtectedData.Protect(Encoding.Unicode.GetBytes(state.RefreshToken), aditionalEntropy, DataProtectionScope.CurrentUser));
        Properties.Settings.Default.Save();
    }
于 2011-09-20T17:56:51.023 回答
11

大体思路如下:

  1. 您将用户重定向到 Google 的授权端点。

  2. 您会获得一个短暂的授权码。

  3. 您立即使用 Google 的 Token Endpoint 将 Authorization Code 交换为长期存在的 Access Token。访问令牌带有到期日期和刷新令牌。

  4. 您使用访问令牌向 Google 的 API 发出请求。

您可以将访问令牌重复用于任意数量的请求,直到它过期。然后,您可以使用刷新令牌请求新的访问令牌(带有新的到期日期和新的刷新令牌)。

也可以看看:

于 2011-09-17T13:53:09.530 回答
3

我也遇到了让“离线”身份验证工作的问题(即使用刷新令牌获取身份验证),并400 Bad request使用类似于 OP 代码的代码获得 HTTP 响应。但是,我让它与client.ClientCredentialApplicator = ClientCredentialApplicator.PostParameter(this.clientSecret);Authenticate-method中的行一起工作。这对于获得工作代码至关重要——我认为这一行强制将 clientSecret 作为 POST 参数发送到服务器(而不是作为 HTTP Basic Auth 参数)。

此解决方案假定您已经拥有一个客户端 ID、一个客户端密码和一个刷新令牌。请注意,您无需在代码中输入访问令牌。(当使用client.RefreshAuthorization(state);.auth授权 API 调用“在后台”。)

使用 Google API v3 访问我的 Google 日历的代码示例:

class SomeClass
{

    private string clientID         = "XXXXXXXXX.apps.googleusercontent.com";
    private string clientSecret     = "MY_CLIENT_SECRET";
    private string refreshToken     = "MY_REFRESH_TOKEN";
    private string primaryCal       = "MY_GMAIL_ADDRESS";

    private void button2_Click_1(object sender, EventArgs e)
    {
        try
        {
            NativeApplicationClient client = new NativeApplicationClient(GoogleAuthenticationServer.Description, this.clientID, this.clientSecret);
            OAuth2Authenticator<NativeApplicationClient> auth = new OAuth2Authenticator<NativeApplicationClient>(client, Authenticate);

            // Authenticated and ready for API calls...

            // EITHER Calendar API calls (tested):
            CalendarService cal = new CalendarService(auth);
            EventsResource.ListRequest listrequest = cal.Events.List(this.primaryCal);
            Google.Apis.Calendar.v3.Data.Events events = listrequest.Fetch();
            // iterate the events and show them here.

            // OR Plus API calls (not tested) - copied from OP's code:
            var plus = new PlusService(auth);
            plus.Key = "BLAH";  // don't know what this line does.
            var me = plus.People.Get("me").Fetch();
            Console.WriteLine(me.DisplayName);

            // OR some other API calls...
        }
        catch (Exception ex)
        {
            Console.WriteLine("Error while communicating with Google servers. Try again(?). The error was:\r\n" + ex.Message + "\r\n\r\nInner exception:\r\n" + ex.InnerException.Message);
        }
    }

    private IAuthorizationState Authenticate(NativeApplicationClient client)
    {
        IAuthorizationState state = new AuthorizationState(new string[] { }) { RefreshToken = this.refreshToken };

        // IMPORTANT - does not work without:
        client.ClientCredentialApplicator = ClientCredentialApplicator.PostParameter(this.clientSecret);

        client.RefreshAuthorization(state);
        return state;
    }
}
于 2012-08-27T12:00:07.393 回答
2

OAuth 2.0 规范尚未完成,在导致这些错误出现的各种客户端和服务中存在少量规范实现。很可能您所做的一切都是正确的,但您使用的 DotNetOpenAuth 版本实现的 OAuth 2.0 草案与 Google 目前正在实现的草案不同。这两个部分都不是“正确的”,因为规范尚未最终确定,但它使兼容性成为一场噩梦。

您可以检查您使用的 DotNetOpenAuth 版本是否是最新的(如果有帮助,它可能会),但最终您可能需要坐稳,直到规范最终确定并且每个人都正确实施它们,或者阅读 Google 文档你自己(大概描述了他们的 OAuth 2.0 版本)并实施一个专门针对他们草稿版本的版本。

于 2011-09-18T21:26:52.893 回答
2

我建议查看 Google .NET 客户端 API 的 Samples 解决方案中的“SampleHelper”项目:

该文件展示了如何使用 Windows 保护数据来存储刷新令牌,还展示了如何使用本地环回服务器和不同的技术来捕获访问代码,而不是让用户手动输入它。

库中使用这种授权方法的示例之一可以在下面找到:

于 2011-09-21T08:34:35.777 回答