{"id":55000413,"date":"2023-12-01T00:00:00","date_gmt":"2023-12-19T15:03:11","guid":{"rendered":"http:\/\/access-im-unternehmen.aix-dev.de\/aiu\/?p=413"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-30T00:00:00","slug":"OAuth2Token_fuer_Google_per_NETApp_holen","status":"publish","type":"post","link":"https:\/\/vbentwickler.de\/OAuth2Token_fuer_Google_per_NETApp_holen\/","title":{"rendered":"OAuth2-Token f&uuml;r Google per .NET-App holen"},"content":{"rendered":"<p><b>Einer der wenigen Schritte, die wir nicht mit klassischem Visual Basic oder per VBA abgebildet haben, ist das Ermitteln eines OAuth2-Tokens f&uuml;r Rest-APIs wie die von Google oder anderen Anbietern. Die Aufgabe ist, mit den online einmalig ermittelten Daten Client-ID und Client-Secret ein Access-Token oder noch besser ein Refresh-Token zu holen. Das Access-Token ist in der Regel zeitlich begrenzt, das Refresh-Token ist haltbarer und erm&ouml;glicht es uns, neue Access-Token zu holen &#8211; dies &uuml;brigens mit einer reinen VB6\/VBA-Prozedur. In diesem Artikel zeigen wir, wie wir eine kleine Anwendung mit Benutzeroberfl&auml;che auf Basis von WPF\/VB.NET in Visual Studio erstellen. Diese soll die Eingabe von Client-ID und Client-Secret erlauben und daf&uuml;r die Werte eines Refresh- und eines Access-Tokens zur&uuml;ckliefern.<\/b><\/p>\n<h2>Projekt erstellen<\/h2>\n<p>Nach dem Starten von Visual Studio, in diesem Fall in der Version 2022, legen wir ein neues Projekt des Typs <b>WPF-Anwendung <\/b>an. Um dieses schnell anzuzeigen, w&auml;hlen wir als Filter <b>Visual Basic<\/b>, <b>Windows <\/b>und <b>Desktop <\/b>aus (siehe Bild 1).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2023_06\/pic_413_001.png\" alt=\"Anlegen einer WPF-Anwendung\" width=\"700\" height=\"365,7302\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 1: Anlegen einer WPF-Anwendung<\/span><\/b><\/p>\n<p>Damit landen wir beim zweiten Schritt, wo wir das Projekt konfigurieren. Hier legen wir den Projektnamen fest und den Namen der Projektmappe (in diesem Fall identisch) und w&auml;hlen den Speicherort f&uuml;r das Projekt aus (siehe Bild 2). Im n&auml;chsten Schritt behalten wir die Voreinstellung bei und erstellen das Projekt.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2023_06\/pic_413_002.png\" alt=\"Konfigurieren des Projekts\" width=\"574,6265\" height=\"410,2004\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 2: Konfigurieren des Projekts<\/span><\/b><\/p>\n<h2>Benutzeroberfl&auml;che definieren<\/h2>\n<p>Danach finden wir den Entwurf des Startfensters der Anwendung namens <b>MainWindow.xaml <\/b>vor. Hier k&ouml;nnen wir nun die Steuerelemente anlegen, die wir f&uuml;r die Anwendung ben&ouml;tigen. Wir ben&ouml;tigen:<\/p>\n<ul>\n<li><b>txtClientID<\/b>: Feld zum Eingeben der Client-ID<\/li>\n<li><b>btnLoadClientData<\/b>: &Ouml;ffnet einen Dateiauswahl-Dialog, um eine JSON-Datei mit Client-ID und Client-Secret auszuw&auml;hlen, deren Daten in die beiden Felder <b>txtClientID <\/b>und <b>txtClientSecret <\/b>eingelesen werden.<\/li>\n<li><b>txtClientSecret<\/b>: Feld zum Eingeben des Client-Secrets<\/li>\n<li><b>txtRefreshToken<\/b>: Feld, in welches das ermittelte Refresh-Token geschrieben werden soll.<\/li>\n<li><b>btnCopyRefreshToken<\/b>: Schaltfl&auml;che zum Kopieren des Refresh-Tokens in die Zwischenablage<\/li>\n<li><b>txtAccessToken<\/b>: Feld, in welches das Access-Token geschrieben werden soll<\/li>\n<li><b>btnCopyAccessToken<\/b>: Schaltfl&auml;che zum Kopieren des Access-Tokens in die Zwischenablage<\/li>\n<li><b>txtExpiresAt<\/b>: Feld, in das wir das Verfallsdatum des Access-Tokens eintragen<\/li>\n<li><b>btnGetTokens<\/b>: Schaltfl&auml;che zum Aktualisieren beider Token<\/li>\n<li><b>btnRefreshToken<\/b>: Schaltfl&auml;che zum Aktualisieren des Access-Tokens mit dem Refresh-Token<\/li>\n<li><b>btnOK<\/b>: Schaltfl&auml;che zum Beenden des Dialogs<\/li>\n<\/ul>\n<h2>Icons f&uuml;r die Schaltfl&auml;chen<\/h2>\n<p>Damit wir die Schaltfl&auml;chen klein halten k&ouml;nnen, verwenden wir, soweit m&ouml;glich, Icons zur Beschreibung der Funktion. So k&ouml;nnen wir zum Beispiel f&uuml;r die Schaltfl&auml;chen <b>btnCopyRefreshToken<\/b> und <b>btnCopyAccessToken <\/b>das &uuml;bliche Icon f&uuml;r das Kopieren in die Zwischenablage verwenden.<\/p>\n<p>Um Icons zu verwalten, f&uuml;gen wir dem Projekt einen Ordner namens <b>Images <\/b>hinzu. In dieses ziehen wir die zu verwenden Icons aus dem jeweiligen Ordner aus dem Windows Explorer hinein. Dazu k&ouml;nnen wir eine spezielle Instanz des Windows Explorers &ouml;ffnen, aus dem wir sicher Dateien in das Projekt ziehen k&ouml;nnen. Dazu bet&auml;tigen wir, w&auml;hrend Visual Studio aktiviert ist, die Tastenkombination <b>Strg + O<\/b>. Dann stellen wir f&uuml;r die Elemente des Ordners <b>Images <\/b>noch die Eigenschaft <b>Buildvorgang <\/b>auf <b>Ressource <\/b>ein. Nur so werden diese in den Buildvorgang integriert und erscheinen auch in der Anwendung (siehe Bild 3).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2023_06\/pic_413_004.png\" alt=\"Einstellen der Bilddatei-Eigenschaften\" width=\"324,6267\" height=\"648,2785\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 3: Einstellen der Bilddatei-Eigenschaften<\/span><\/b><\/p>\n<h2>Code des WPF-Fensters f&uuml;r die Anwendung<\/h2>\n<p>Neben den Schaltfl&auml;chen soll auch das Hauptfenster selbst ein Icon erhalten &#8211; und eine entsprechende Beschriftung. Dazu stellen wir in dem Ger&uuml;st der Seite <b>MainWindow.xaml<\/b>, das beim Erstellen des Projekts automatisch angelegt wurde, f&uuml;r das Hauptelement <b>Window <\/b>die Attribute <b>Title<\/b> und <b>Icon <\/b>entsprechend ein (siehe Listing 1).<\/p>\n<pre>&lt;Window x:Class=\"MainWindow\"\r\n         ...\r\n         Title=\"amvGetGoogleToken\" Height=\"350\" Width=\"800\" Icon=\"Images\/key.ico\"&gt;\r\n     &lt;Window.Resources&gt;...&lt;\/Window.Resources&gt;\r\n     &lt;Grid&gt;\r\n         &lt;Grid.RowDefinitions&gt;...&lt;\/Grid.RowDefinitions&gt;\r\n         &lt;Grid.ColumnDefinitions&gt;...&lt;\/Grid.ColumnDefinitions&gt;\r\n         &lt;TextBlock Grid.ColumnSpan=\"3\" Height=\"50\" Width=\"350\" HorizontalAlignment=\"Left\" TextWrapping=\"Wrap\"&gt;Gib die \r\n             Client-ID und das Client-Secret ein und klicke auf die Refresh-Schaltfl&auml;che, um Refresh-Token und Access-\r\n             Token zu erhalten.&lt;\/TextBlock&gt;\r\n         &lt;Label Grid.Row=\"1\"&gt;Client-ID:&lt;\/Label&gt;\r\n         &lt;TextBox x:Name=\"txtClientID\" Width=\"Auto\" Margin=\"5\" Grid.Column=\"1\" Grid.Row=\"1\"&gt;&lt;\/TextBox&gt;\r\n         &lt;Button x:Name=\"btnLoadClientdata\" Grid.Row=\"1\" Grid.Column=\"2\" HorizontalAlignment=\"left\" \r\n                 Click=\"btnLoadClientdata_Click\" Background=\"Transparent\" BorderBrush=\"Transparent\"&gt;\r\n             &lt;Image Source=\"Images\/folder.ico\" Width=\"24\" Height=\"24\"&gt;&lt;\/Image&gt;\r\n         &lt;\/Button&gt;\r\n         &lt;Label Grid.Row=\"2\"&gt;Client-Secret:&lt;\/Label&gt;\r\n         &lt;TextBox x:Name=\"txtClientSecret\" Width=\"Auto\" Margin=\"5\" Grid.Row=\"2\" Grid.Column=\"1\"&gt;&lt;\/TextBox&gt;\r\n         &lt;Label Grid.Row=\"3\"&gt;Refresh-Token:&lt;\/Label&gt;\r\n         &lt;TextBox x:Name=\"txtRefreshToken\" Width=\"Auto\" Margin=\"5\" Grid.Row=\"3\" Grid.Column=\"1\"&gt;&lt;\/TextBox&gt;\r\n         &lt;StackPanel Grid.Row=\"3\" Grid.Column=\"2\" Orientation=\"Horizontal\"&gt;\r\n             &lt;Button x:Name=\"btnCopyRefreshToken\" Click=\"btnCopyRefreshToken_Click\" Background=\"Transparent\" \r\n                     BorderBrush=\"transparent\"&gt;\r\n                 &lt;Image Source=\"Images\/Copy.ico\" Width=\"24\" Height=\"24\"&gt;&lt;\/Image&gt;\r\n             &lt;\/Button&gt;\r\n             &lt;Button x:Name=\"btnRefresh\" Click=\"btnRefresh_Click\" Background=\"Transparent\" BorderBrush=\"transparent\"&gt;\r\n                 &lt;Image Source=\"Images\/refresh.ico\" Width=\"24\" Height=\"24\"&gt;&lt;\/Image&gt;\r\n             &lt;\/Button&gt;\r\n         &lt;\/StackPanel&gt;\r\n         &lt;Label Grid.Row=\"4\"&gt;Access-Token:&lt;\/Label&gt;\r\n         &lt;TextBox x:Name=\"txtAccessToken\" Width=\"Auto\" Margin=\"5\" Grid.Row=\"4\" Grid.Column=\"1\"&gt;&lt;\/TextBox&gt;\r\n         &lt;Button x:Name=\"btnCopyAccessToken\" Grid.Row=\"4\" Grid.Column=\"2\" HorizontalAlignment=\"left\" \r\n                 Click=\"btnCopyRefreshToken_Click\" Background=\"Transparent\" BorderBrush=\"Transparent\"&gt;\r\n             &lt;Image Source=\"Images\/Copy.ico\" Width=\"24\" Height=\"24\"&gt;&lt;\/Image&gt;\r\n         &lt;\/Button&gt;\r\n         &lt;Label Grid.Row=\"5\"&gt;G&uuml;ltig bis:&lt;\/Label&gt;\r\n         &lt;TextBox x:Name=\"txtExpiresAt\" Width=\"150\" HorizontalAlignment=\"left\" Grid.Row=\"5\" Grid.Column=\"1\"&gt;&lt;\/TextBox&gt;\r\n         &lt;Button x:Name=\"btnOK\" Grid.Row=\"6\" Click=\"btnOK_Click\" Margin=\"5\"&gt;\r\n             &lt;StackPanel Orientation=\"Horizontal\"&gt;\r\n                 &lt;Image Source=\"Images\/ok.ico\" Width=\"16\" Height=\"16\"&gt;&lt;\/Image&gt;\r\n                 &lt;Label Padding=\"0\"&gt;OK&lt;\/Label&gt;\r\n             &lt;\/StackPanel&gt;\r\n         &lt;\/Button&gt;\r\n     &lt;\/Grid&gt;\r\n&lt;\/Window&gt;<\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 1: Definition des Hauptfensters der Anwendung<\/span><\/b><\/p>\n<p>Danach folgt der Abschnitt <b>Windows.Resources<\/b>. Hier legen wir Standardwerte f&uuml;r einige Attribute bestimmter Steuerelemente fest. Danach folgt das <b>Grid<\/b>-Element, in dem wir im Abschnitt <b>Grid.RowDefinitions <\/b>die Zeilen definieren und im Abschnitt <b>Grid.ColumnDefinitions <\/b>die Spalten. Die H&ouml;he der <b>RowDefinition<\/b>-Elemente legen wir mit dem Attribut <b>Height <\/b>jeweils auf <b>Auto <\/b>fest, damit diese sich an die H&ouml;he der enthaltenen Steuerelemente anpasst. Einzige Ausnahme ist die letzte Zeile, welche wir auf <b>* <\/b>einstellen und die so den verbleibenden Platz einnimmt.<\/p>\n<p>Die Breite der Spalten definieren wir mit dem Attribut <b>Width <\/b>der <b>ColumnDefinition<\/b>-Elemente. Die erste und die letzten Spalte sollen sich an der Breite der enthaltenen Steuerelemente orientieren, die mittlere soll den verbleibenden Platz einnehmen. Dadurch erstrecken sich die in der mittleren Spalte enthaltenen Textfelder, sofern nicht anders festgelegt, &uuml;ber die gesamte Breite der mittleren Spalte. Wenn der Benutzer die Breite des Fensters einstellt, passt er somit auch die Breite der Textfelder an.<\/p>\n<p>Die Position der Steuerelemente innerhalb des Grids wird durch die Attribute <b>Grid.Column <\/b>und <b>Grid.Row <\/b>definiert. F&uuml;r die Schaltfl&auml;chen hinterlegen wir mit dem <b>Click<\/b>-Attribut entsprechende Ereignisprozeduren, die im Code behind-Modul angelegt werden.<\/p>\n<p>Nach dem Hinzuf&uuml;gen der Steuerelemente, wie durch die XAML-Definition aus dem Listing geschehen, sieht der Entwurf des Fensters wie in Bild 4 aus.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2023_06\/pic_413_003.png\" alt=\"Entwurf des Hauptfensters\" width=\"700\" height=\"313,4708\" \/><\/p>\n<div class=\"rcp_restricted\"><p><span style=\"color: #ff0000;\">M&ouml;chten Sie weiterlesen? Dann l&ouml;sen Sie Ihr Ticket!<\/span><br \/>\n<span style=\"color: #ff0000;\">Hier geht es zur Bestellung des Jahresabonnements des Magazins <strong>Visual Basic Entwickler<\/strong>:<\/span><br \/>\n<span style=\"color: #ff0000;\"><a style=\"color: #ff0000;\" href=\"https:\/\/shop.minhorst.com\/magazine\/363\/visual-basic-entwickler-jahresabonnement?c=77\">Zur Bestellung ...<\/a><\/span><br \/>\n<span style=\"color: #ff0000;\">Danach greifen Sie sofort auf <strong>alle rund 200 Artikel<\/strong> unseres Angebots zu - auch auf diesen hier!<\/span><br \/>\n<span style=\"color: #000000;\">Oder haben Sie bereits Zugangsdaten? Dann loggen Sie sich gleich hier ein:<\/span><\/p>\n<\/div>\n\n\t\n\t<form id=\"rcp_login_form\"  class=\"rcp_form\" method=\"POST\" action=\"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts\/55000413\/\">\n\n\t\t\n\t\t<fieldset class=\"rcp_login_data\">\n\t\t\t<p>\n\t\t\t\t<label for=\"rcp_user_login\">Username or Email<\/label>\n\t\t\t\t<input name=\"rcp_user_login\" id=\"rcp_user_login\" class=\"required\" type=\"text\"\/>\n\t\t\t<\/p>\n\t\t\t<p>\n\t\t\t\t<label for=\"rcp_user_pass\">Password<\/label>\n\t\t\t\t<input name=\"rcp_user_pass\" id=\"rcp_user_pass\" class=\"required\" type=\"password\"\/>\n\t\t\t<\/p>\n\t\t\t\t\t\t<p>\n\t\t\t\t<input type=\"checkbox\" name=\"rcp_user_remember\" id=\"rcp_user_remember\" value=\"1\"\/>\n\t\t\t\t<label for=\"rcp_user_remember\">Remember me<\/label>\n\t\t\t<\/p>\n\t\t\t<p class=\"rcp_lost_password\"><a href=\"\/data\/wp\/v2\/posts\/55000413?rcp_action=lostpassword\"><\/a><\/p>\n\t\t\t<p>\n\t\t\t\t<input type=\"hidden\" name=\"rcp_action\" value=\"login\"\/>\n\t\t\t\t<input type=\"hidden\" name=\"rcp_redirect\" value=\"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts\/55000413\/\"\/>\n\t\t\t\t<input type=\"hidden\" name=\"rcp_login_nonce\" value=\"123b777de9\"\/>\n\t\t\t\t<input id=\"rcp_login_submit\" class=\"rcp-button\" type=\"submit\" value=\"Login\"\/>\n\t\t\t<\/p>\n\t\t\t\t\t<\/fieldset>\n\n\t\t\n\t<\/form>\n<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Einer der wenigen Schritte, die wir nicht mit klassischem Visual Basic oder per VBA abgebildet haben, ist das Ermitteln eines OAuth2-Tokens f&uuml;r Rest-APIs wie die von Google oder anderen Anbietern. Die Aufgabe ist, mit den online einmalig ermittelten Daten Client-ID und Client-Secret ein Access-Token oder noch besser ein Refresh-Token zu holen. Das Access-Token ist in der Regel zeitlich begrenzt, das Refresh-Token ist haltbarer und erm&ouml;glicht es uns, neue Access-Token zu holen &#8211; dies &uuml;brigens mit einer reinen VB6\/VBA-Prozedur. In diesem Artikel zeigen wir, wie wir eine kleine Anwendung mit Benutzeroberfl&auml;che auf Basis von WPF\/VB.NET in Visual Studio erstellen. Diese soll die Eingabe von Client-ID und Client-Secret erlauben und daf&uuml;r die Werte eines Refresh- und eines Access-Tokens zur&uuml;ckliefern.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_uf_show_specific_survey":0,"_uf_disable_surveys":false,"footnotes":""},"categories":[662023,66062023,44000023,44000036,44000032],"tags":[],"yst_prominent_words":[],"class_list":["post-55000413","post","type-post","status-publish","format-standard","hentry","category-662023","category-66062023","category-PowerApps","category-Ribbon_programmieren","category-VBNETProgrammierung"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts\/55000413","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/comments?post=55000413"}],"version-history":[{"count":0,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts\/55000413\/revisions"}],"wp:attachment":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/media?parent=55000413"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/categories?post=55000413"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/tags?post=55000413"},{"taxonomy":"yst_prominent_words","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/yst_prominent_words?post=55000413"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}