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

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

问题描述

我试图为我开发的UWP应用程序登录,该应用程序具有使用G的 @< theircompay> .com 电子邮件套房。它不必访问任何用户数据,他们只需要它作为身份验证,以便只有拥有公司电子邮件的人才能访问该应用程序。



如果他们可以在应用程序内登录而无需使用网络浏览器,那将是非常好的,如果能记住它们,甚至更好,这样他们就不必每次登录。

我一直在研究OAuth 2.0和其他几种Google解决方案,但无法真正理解使用哪种方法,更不用说如何。



我查看了这个答案,但似乎没有这是一个好主意,可以将您的证书文件与您的应用程序一起发送。



因此,基本上如果可以这样做,我需要从哪些证书或证书Google,以及我将如何处理它们以及通过我的C#代码进行登录?

编辑



该应用程序为100%客户端,无服务器后端

解决方案

查看 Google的GitHub ,似乎.Net API仍然没有为UWP做好准备(但是如果你经历了这些问题,你会发现他们正在开发它,所以当官方版本准备就绪时,这可能是时间问题了。答案将过时)。



正如我认为简单的 accessToken (可选)更新到基本的个人资料信息应该足以满足这种情况。根据来自Google的样本,我已经构建了一个小型项目(源于GitHub),它可以帮助你。



因此,首先您必须在 Google开发人员控制台上定义您的应用程序,然后获取 ClientID ClientSecret 。一旦你有了这个,你可以开始编码。要获取 accessToken ,我将使用一个 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 =等待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),状态,code_verifier);
返回true;
case WebAuthenticationStatus.ErrorHttp:
Debug.WriteLine($HTTP error:{receivedData.ResponseErrorDetail});
返回false;

案例WebAuthenticationStatus.UserCancel:
默认值:
返回false;





$ b如果一切正常,并且用户输入正确的凭证,你将不得不问Google for token(我假设你只希望用户放置证书一次)。为此,您可以使用 GetAccessToken 方法:


$ b

  //解析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 =等待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); $(b)
$ b foreach(var item in vault.RetrieveAll()。Where((x)=> x.Resource == TokenTypes.AccessToken.ToString()|| x.Resource == TokenTypes.RefreshToken。 ToString()))vault.Remove(item);
$ b $ v vault.Add(新的PasswordCredential(TokenTypes.AccessToken.ToString(),MyApp,accessToken));
vault.Add(new PasswordCredential(TokenTypes.RefreshToken.ToString(),MyApp,tokens.GetNamedString(refresh_token)));
TokenLastAccess = DateTimeOffset.UtcNow;

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

  if(DateTimeOffset.UtcNow< TokenLastAccess.AddSeconds(3600))
{
//被授权 - 无需登录
返回真正;
}
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 =等待httpClient.PostAsync(TokenEndpoint,content);
string responseString = await response.Content.ReadAsStringAsync();

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

accessToken = tokens.GetNamedString(access_token);
$ b foreach(var item in vault.RetrieveAll()。Where((x)=> x.Resource == TokenTypes.AccessToken.ToString()))vault.Remove(item);
$ b $ v vault.Add(新的PasswordCredential(TokenTypes.AccessToken.ToString(),MyApp,accessToken));
TokenLastAccess = DateTimeOffset.UtcNow;
返回true;
}
}
}

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


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.

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.

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?

Edit

The app is 100% client side, no server backend

解决方案

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).

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.

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;
}

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;

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;
        }
    }
}

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天全站免登陆