0

Quand je note dans mon application, je passe par le code suivant:En utilisant l'identité Cognito en cache de Xamarin

 auth = new Xamarin.Auth.OAuth2Authenticator(
     "my-google-client-id.apps.googleusercontent.com", 
     string.Empty, 
     "openid", 
     new System.Uri("https://accounts.google.com/o/oauth2/v2/auth"), 
     new System.Uri("com.enigmadream.storyvoque:/oauth2redirect"), 
     new System.Uri("https://www.googleapis.com/oauth2/v4/token"), 
     isUsingNativeUI: true); 

    auth.Completed += Auth_Completed; 
    StartActivity(auth.GetUI(this)); 

qui déclenche cette activité:

[Activity(Label = "GoodleAuthInterceptor")] 
[IntentFilter(actions: new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault, Intent.CategoryBrowsable }, 
    DataSchemes = new[] { "com.enigmadream.storyvoque" }, DataPaths = new[] { "/oauth2redirect" })] 
public class GoodleAuthInterceptor : Activity 
{ 
    protected override void OnCreate(Bundle savedInstanceState) 
    { 
    base.OnCreate(savedInstanceState); 
    Android.Net.Uri uri_android = Intent.Data; 
    Uri uri_netfx = new Uri(uri_android.ToString()); 
    MainActivity.auth?.OnPageLoading(uri_netfx); 
    Finish(); 
    } 
} 

Et enfin ce code pour lier le compte Cognito:

private void Auth_Completed(object sender, Xamarin.Auth.AuthenticatorCompletedEventArgs e) 
    { 
    if (e.IsAuthenticated) 
    { 
     var idToken = e.Account.Properties["id_token"]; 

     credentials.AddLogin("accounts.google.com", idToken); 
     AmazonCognitoIdentityClient cli = new AmazonCognitoIdentityClient(credentials, RegionEndpoint.USEast2); 
     var req = new Amazon.CognitoIdentity.Model.GetIdRequest(); 
     req.Logins.Add("accounts.google.com", idToken); 
     req.IdentityPoolId = "us-east-2:79ebf8e1-97de-4d1c-959a-xxxxxxxxxxxx"; 
     cli.GetIdAsync(req).ContinueWith((task) => 
     { 
      if ((task.Status == TaskStatus.RanToCompletion) && (task.Result != null)) 
      { 
       ShowMessage(string.Format("Identity {0} retrieved", task.Result.IdentityId)); 
      } 
      else 
       ShowMessage(task.Exception.InnerException != null ? task.Exception.InnerException.Message : task.Exception.Message); 
     }); 
    } 
    else 
     ShowMessage("Login cancelled"); 
    } 

tout cela fonctionne très bien, et après la connexion, je peux utiliser mon identité/crede ntials pour récupérer des données de DynamoDB. Avec cet objet:

Amazon.DynamoDBv2.AmazonDynamoDBClient ddbc = new Amazon.DynamoDBv2.AmazonDynamoDBClient(credentials, RegionEndpoint.USEast2); 

La deuxième fois que je lance mon application, ce code fonctionne:

if (!string.IsNullOrEmpty(credentials.GetCachedIdentityId()) || credentials.CurrentLoginProviders.Length > 0) 
{ 
    if (!bDidLogin) 
    { 
     var idToken = credentials.GetIdentityId(); 
     ShowMessage(string.Format("I still remember you're {0} ", idToken)); 

Et si je tente d'utiliser les informations d'identification avec DynamoDB (ou quoi que ce soit, je suppose) à ce stade , Je reçois des erreurs que je n'ai pas accès à l'identité. Je dois me déconnecter (credentials.Clear()) et me reconnecter pour obtenir les informations d'identification appropriées. Je pourrais demander à un utilisateur de passer par tout le processus de connexion à chaque fois que mon application fonctionne, mais le processus de connexion Google oblige l'utilisateur à fermer manuellement le navigateur pour revenir à l'application après s'être authentifié. Y at-il quelque chose qui me manque sur le but et l'utilisation des informations d'identification en cache? Lorsque j'utilise la plupart des applications, elles ne me demandent pas de me connecter à mon compte Google à chaque fois et de fermer un navigateur Web uniquement pour accéder aux ressources de leur serveur.

+2

1) Vous pouvez utiliser une activité 'LaunchMode.SingleTask' pour fermer l'onglet personnalisé Chrome (ou Firefox, Samsung, etc ...) après la fin de la connexion oauth2 en lançant l'OAuth2Authenticator dans cette même activité, et non votre "MainActivity" (les docs Xamarin.Auth (readme.md) sont juste faux sur la façon dont ils vous montrent pour le configurer). 2) Voulez-vous dire que les informations d'identification mises en cache sont vides ou que le jeton est manquant après la première connexion? – SushiHangover

+0

@SushiHangover Je crois que les identifiants sont là parce qu'il me dit mon identité, et me dit que je ne peux pas utiliser une autre identité si j'essaie de me connecter à un autre compte Google (en ajoutant un autre identifiant avec un ID différent). Mais si j'essaie d'utiliser les informations d'identification, cela signifie que je n'ai pas accès à l'identité. Je suis très nouveau à ce sujet, donc je ne suis pas sûr de savoir comment les pièces s'emboîtent, ou ce que ces erreurs signifient. – BlueMonkMN

+0

@SushiHangover J'ai pu obtenir 'LaunchMode.SingleTask' pour améliorer le comportement, mais je ne suis toujours pas clair sur la nature ou le but des informations d'identification mises en cache et si je dois demander un compte Google chaque fois que l'application fonctionne . Il se souvient de mon jeton d'identité, mais apparemment pas de tout ce dont il a besoin pour être authentifié avec. – BlueMonkMN

Répondre

0

Il semble que le jeton d'actualisation doit être renvoyé au fournisseur OAuth2 pour obtenir un jeton d'identification mis à jour à ajouter à l'objet d'informations d'identification. Tout d'abord, j'ai ajouté un code pour enregistrer et charger le refresh_token dans un fichier config.json:

private Dictionary<string, string> config; 
const string CONFIG_FILE = "config.json"; 

private void Auth_Completed(object sender, Xamarin.Auth.AuthenticatorCompletedEventArgs e) 
{ 
    if (e.IsAuthenticated) 
    { 
     var idToken = e.Account.Properties["id_token"]; 
     if (e.Account.Properties.ContainsKey("refresh_token")) 
     { 
     if (config == null) 
      config = new Dictionary<string, string>(); 
     config["refresh_token"] = e.Account.Properties["refresh_token"]; 
     WriteConfig(); 
     } 

     credentials.AddLogin("accounts.google.com", idToken); 
     CognitoLogin(idToken).ContinueWith((t) => 
     { 
     try 
     { 
      t.Wait(); 
     } 
     catch (Exception ex) 
     { 
      ShowMessage(ex.Message); 
     } 
     }); 
    } 
    else 
     ShowMessage("Login cancelled"); 
} 

void WriteConfig() 
{ 
    using (var configWriter = new System.IO.StreamWriter(
     Application.OpenFileOutput(CONFIG_FILE, Android.Content.FileCreationMode.Private))) 
    { 
     configWriter.Write(ThirdParty.Json.LitJson.JsonMapper.ToJson(config)); 
     configWriter.Close(); 
    } 
} 

public void Login() 
{ 
    try 
    { 
     if (!string.IsNullOrEmpty(credentials.GetCachedIdentityId()) || credentials.CurrentLoginProviders.Length > 0) 
     { 
     if (!bDidLogin) 
     { 
      var idToken = credentials.GetIdentityId(); 
      if (ReadConfig()) 
      { 
       LoginRefreshAsync().ContinueWith((t) => 
       { 
        try 
        { 
        t.Wait(); 
        if (!t.Result) 
         FullLogin(); 
        } 
        catch (Exception ex) 
        { 
        ShowMessage(ex.Message); 
        } 
       }); 
      } 
      else 
      { 
       credentials.Clear(); 
       FullLogin(); 
      } 
     } 
     } 
     else 
     FullLogin(); 
     bDidLogin = true; 
    } 
    catch(Exception ex) 
    { 
     ShowMessage(string.Format("Error logging in: {0}", ex.Message)); 
    } 
} 

private bool ReadConfig() 
{ 
    bool bFound = false; 
    foreach (string filename in Application.FileList()) 
     if (string.Compare(filename, CONFIG_FILE, true) == 0) 
     { 
     bFound = true; 
     break; 
     } 
    if (!bFound) 
     return false; 
    using (var configReader = new System.IO.StreamReader(Application.OpenFileInput(CONFIG_FILE))) 
    { 
     config = ThirdParty.Json.LitJson.JsonMapper.ToObject<Dictionary<string, string>>(configReader.ReadToEnd()); 
     return true; 
    } 
} 

Ensuite, le code qui remaniée avec initie la connexion interactive dans une fonction distincte:

public void FullLogin() 
{ 
    auth = new Xamarin.Auth.OAuth2Authenticator(CLIENTID_GOOGLE, string.Empty, "openid", 
     new Uri("https://accounts.google.com/o/oauth2/v2/auth"), 
     new Uri("com.enigmadream.storyvoque:/oauth2redirect"), 
     new Uri("https://accounts.google.com/o/oauth2/token"), 
     isUsingNativeUI: true); 

    auth.Completed += Auth_Completed; 
    StartActivity(auth.GetUI(this)); 
} 

Refonte du code récupère une identité Cognito dans sa propre fonction:

private async Task CognitoLogin(string idToken) 
{ 
    AmazonCognitoIdentityClient cli = new AmazonCognitoIdentityClient(credentials, RegionEndpoint.USEast2); 
    var req = new Amazon.CognitoIdentity.Model.GetIdRequest(); 
    req.Logins.Add("accounts.google.com", idToken); 
    req.IdentityPoolId = ID_POOL; 
    try 
    { 
     var result = await cli.GetIdAsync(req); 
     ShowMessage(string.Format("Identity {0} retrieved", result.IdentityId)); 
    } 
    catch (Exception ex) 
    { 
     ShowMessage(ex.Message); 
    } 
} 

Et finalement mis en œuvre une fonction qui permet de récupérer un nouveau jeton basé sur le jeton de rafraîchissement, insérez dans les informations d'identification Cognito actuelles et obtenir une identité Cognito mise à jour. Je ne suis pas sûr si c'est optimal ou même correct, mais cela semble fonctionner. Je peux utiliser les informations d'identification qui en résultent pour accéder à DynamoDB sans avoir à demander de nouveau à l'utilisateur des autorisations/informations d'identification.

0

Il y a une solution très différente que j'essaye d'adapter avec l'autre réponse. Mais c'est tellement différent, je l'ajoute comme une réponse séparée. Il semble que le problème n'était pas tellement lié au besoin d'utiliser explicitement un jeton d'actualisation pour obtenir un jeton d'accès mis à jour (je pense que c'est fait implicitement), mais plutôt de devoir se souvenir du jeton d'identité. Ainsi, plutôt que d'inclure toute la complexité de l'application manuelle d'un jeton d'actualisation, il suffit de stocker le jeton d'identité (ce qui peut être fait de la même manière que le jeton d'actualisation était stocké).Ensuite, nous avons juste besoin d'ajouter ce même jeton d'identité à l'objet credentials quand il est manquant.

if (!string.IsNullOrEmpty(credentials.GetCachedIdentityId()) || credentials.CurrentLoginProviders.Length > 0) 
{ 
    if (config.Read()) 
    { 
     if (config["id_token"] != null) 
     credentials.AddLogin(currentProvider.Name, config["id_token"]); 

Edit: Le problème d'avoir besoin d'utiliser un jeton rafraîchissement ne existe encore. Ce code fonctionne si le jeton n'a pas expiré, mais la tentative d'utilisation de ces informations d'identification après l'expiration du jeton échouera. Il est donc nécessaire d'utiliser un jeton d'actualisation dans certains cas.