使用谷歌凭据登录 UWP C# 应用程序 [英] Use google credentials to login into UWP C# app

查看:24
本文介绍了使用谷歌凭据登录 UWP C# 应用程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试登录我正在开发的 UWP 应用,该应用具有使用 G Suite 的 @<theircompay>.com 电子邮件.它不必访问任何用户数据,他们只是希望将其作为身份验证,以便只有拥有公司电子邮件的人才能访问该应用.

I'm trying to make a login for a UWP app that I'm developing for a client that has a @<theircompay>.com email that uses G Suite. It doesn't have to access any user data, they just want it as an authentication so that only people that have a company email can access the app.

如果他们无需使用网络浏览器就可以从应用内登录,那就太好了,如果它能够记住他们,这样他们就不必每次都登录,那就更好了.

It would be great if they could login from within the app without having to use a web browser, and even better if it could remember them so they wouldn't have to login every single time.

我一直在研究 OAuth 2.0 和谷歌的其他几种解决方案,但无法真正理解该使用哪一个,更不用说如何使用了.

I've been looking at OAuth 2.0 and several other solutions google has but can't really understand which one to use and much less how.

我查看了这个答案,但将证书文件与您的应用一起发送似乎不是一个好主意.

I looked into this answer but it doesn't seem like a good idea to ship your certificate file with your app.

所以基本上,如果可以做到这一点,我需要从 Google 获得什么(如果有)证书或凭据,我将如何处理它们并通过我的 C# 代码登录?

So basically if this can be done, what (if any) certificates or credentials do I need to get from Google, and how would I handle them and the login through my C# code?

该应用程序是 100% 客户端,没有服务器后端

The app is 100% client side, no server backend

推荐答案

看一看 Google 的 GitHub 似乎 .Net API 还没有为 UWP 做好准备(但是如果你遍历问题你会发现他们正在处理它,所以正式版本准备好可能是时间问题,这个答案会过时).

Taking a look at Google's GitHub it seems that .Net API is still not ready for UWP (however if you traverse the issues you will find that they are working on it, so it's probably a matter of time when official version is ready and this answer would be obsolete).

因为我认为让简单的 accessToken(可选地引用它)到基本的个人资料信息应该足以满足这种情况.基于 来自 Google 的可用示例,我构建了 一个小项目(来自 GitHub),可以帮助你.

As I think getting simple accessToken (optionaly refresing it) to basic profile info should be sufficient for this case. Basing on available samples from Google I've build a small project (source at GitHub), that can help you.

因此,首先您必须在 Google 的开发者控制台上定义您的应用并获取ClientIDClientSecret.一旦你有了这个,你就可以开始编码了.为了获得accessToken,我将使用WebAuthenticationBroker:

So first of all you have to define your app at Google's developer console and obtain ClientID and ClientSecret. Once you have this you can get to coding. To obtain accessToken I will use a WebAuthenticationBroker:

string authString = "https://accounts.google.com/o/oauth2/auth?client_id=" + ClientID;
authString += "&scope=profile";
authString += $"&redirect_uri={RedirectURI}";
authString += $"&state={state}";
authString += $"&code_challenge={code_challenge}";
authString += $"&code_challenge_method={code_challenge_method}";
authString += "&response_type=code";

var receivedData = await WebAuthenticationBroker.AuthenticateAsync(WebAuthenticationOptions.UseTitle, new Uri(authString), new Uri(ApprovalEndpoint));

switch (receivedData.ResponseStatus)
{
    case WebAuthenticationStatus.Success:
        await GetAccessToken(receivedData.ResponseData.Substring(receivedData.ResponseData.IndexOf(' ') + 1), state, code_verifier);
        return true;
    case WebAuthenticationStatus.ErrorHttp:
        Debug.WriteLine($"HTTP error: {receivedData.ResponseErrorDetail}");
        return false;

    case WebAuthenticationStatus.UserCancel:
    default:
        return false;
}

如果一切顺利并且用户输入了正确的凭据,您将不得不向 Google 索取令牌(我假设您只希望用户输入一次凭据).为此,您有方法 GetAccessToken:

If everything goes all right and user puts correct credentials, you will have to ask Google for tokens (I assume that you only want the user to put credentials once). For this purpose you have the method GetAccessToken:

// Parses URI params into a dictionary - ref: http://stackoverflow.com/a/11957114/72176 
Dictionary<string, string> queryStringParams = data.Split('&').ToDictionary(c => c.Split('=')[0], c => Uri.UnescapeDataString(c.Split('=')[1]));

StringContent content = new StringContent($"code={queryStringParams["code"]}&client_secret={ClientSecret}&redirect_uri={Uri.EscapeDataString(RedirectURI)}&client_id={ClientID}&code_verifier={codeVerifier}&grant_type=authorization_code",
                                          Encoding.UTF8, "application/x-www-form-urlencoded");

HttpResponseMessage response = await httpClient.PostAsync(TokenEndpoint, content);
string responseString = await response.Content.ReadAsStringAsync();

if (!response.IsSuccessStatusCode)
{
    Debug.WriteLine("Authorization code exchange failed.");
    return;
}

JsonObject tokens = JsonObject.Parse(responseString);
accessToken = tokens.GetNamedString("access_token");

foreach (var item in vault.RetrieveAll().Where((x) => x.Resource == TokenTypes.AccessToken.ToString() || x.Resource == TokenTypes.RefreshToken.ToString())) vault.Remove(item);

vault.Add(new PasswordCredential(TokenTypes.AccessToken.ToString(), "MyApp", accessToken));
vault.Add(new PasswordCredential(TokenTypes.RefreshToken.ToString(), "MyApp", tokens.GetNamedString("refresh_token")));
TokenLastAccess = DateTimeOffset.UtcNow;

一旦您拥有令牌(为了安全起见,我将它们保存在 PasswordVault 中),稍后您就可以使用它们进行身份验证,而无需询问用户的凭据.请注意,accessToken 的生命周期是有限的,因此您可以使用 refreshToken 来获取一个新的:

Once you have the tokens (I'm saving them in PasswordVault for safety), you can later then use them to authenticate without asking the user for his credentials. Note that accessToken has limited lifetime, therefore you use refreshToken to obtain a new one:

if (DateTimeOffset.UtcNow < TokenLastAccess.AddSeconds(3600))
{
    // is authorized - no need to Sign In
    return true;
}
else
{
    string token = GetTokenFromVault(TokenTypes.RefreshToken);
    if (!string.IsNullOrWhiteSpace(token))
    {
        StringContent content = new StringContent($"client_secret={ClientSecret}&refresh_token={token}&client_id={ClientID}&grant_type=refresh_token",
                                                  Encoding.UTF8, "application/x-www-form-urlencoded");

        HttpResponseMessage response = await httpClient.PostAsync(TokenEndpoint, content);
        string responseString = await response.Content.ReadAsStringAsync();

        if (response.IsSuccessStatusCode)
        {
            JsonObject tokens = JsonObject.Parse(responseString);

            accessToken = tokens.GetNamedString("access_token");

            foreach (var item in vault.RetrieveAll().Where((x) => x.Resource == TokenTypes.AccessToken.ToString())) vault.Remove(item);

            vault.Add(new PasswordCredential(TokenTypes.AccessToken.ToString(), "MyApp", accessToken));
            TokenLastAccess = DateTimeOffset.UtcNow;
            return true;
        }
    }
}

上面的代码只是一个示例(带有一些快捷方式),如上所述 - 您可以在我的 GitHub 上找到具有更多错误处理功能的工作版本.另请注意,我没有花太多时间在这上面,肯定需要做更多的工作来处理所有情况和可能的问题.虽然希望能帮助你开始.

The code above is only a sample (with some shortcuts) and as mentioned above - a working version with some more error handling you will find at my GitHub. Please also note, that I haven't spend much time on this and it will surely need some more work to handle all the cases and possible problems. Though hopefully will help you to start.

这篇关于使用谷歌凭据登录 UWP C# 应用程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆