{"id":134,"date":"2013-04-19T16:47:57","date_gmt":"2013-04-19T14:47:57","guid":{"rendered":"http:\/\/www.zellot.at\/blogs\/?p=134"},"modified":"2013-04-19T16:47:57","modified_gmt":"2013-04-19T14:47:57","slug":"zend2-user-auth-mit-doctrine-und-facebook","status":"publish","type":"post","link":"https:\/\/www.zellot.at\/blogs\/2013\/04\/19\/zend2-user-auth-mit-doctrine-und-facebook\/","title":{"rendered":"Zend2 User Auth mit Doctrine und Facebook"},"content":{"rendered":"<p>F\u00fcr meine <strong>AAUShare<\/strong> Applikation brauch ich ja wie bereits in meinen letzten Eintrag erw\u00e4hnt eine User Authentfizierung. Dies habe ich mit 2 Varianten gel\u00f6st. Zuerst gibt es den einfachen Login \u00fcber eine eigene User Tabelle mithilfe von Doctrine. Um die zu erm\u00f6glichen werden mehrere Schritte ben\u00f6tigt. Zuerst\u00a0muss das application.config.php File erweitert werden <\/p>\n<p><pre><code class=\"preserve-code-formatting\">\n&#039;doctrine&#039; =&gt; array(\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;....,\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#039;authentication&#039; =&gt; array(\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#039;orm_default&#039; =&gt; array(\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#039;object_manager&#039; =&gt; &#039;Doctrine\\ORM\\EntityManager&#039;,\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#039;identity_class&#039; =&gt; &#039;AAUShare\\Entity\\User&#039;,\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#039;identity_property&#039; =&gt; &#039;email&#039;,\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#039;credential_property&#039; =&gt; &#039;password&#039;,\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;),\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;),\n&nbsp;&nbsp;&nbsp;&nbsp;),\n<\/code><\/pre><br \/>\nHierbei wird folgendes gemacht: Es wird der Standard EntityManger hergenommen, mit der Klasse User, es wird die Email Adresse als Identity &#8222;Username&#8220; hergenommen und das Passwordfeld ist hier logischerwei\u00dfe das password.<\/p>\n<p>\nDie Auth &#8211; Methode im Controller sieht wie folgt aus:<br \/>\n<pre><code class=\"preserve-code-formatting\">\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$form = $this-&gt;getForm();\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$redirect = &#039;login&#039;;\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$request = $this-&gt;getRequest();\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ($request-&gt;isPost()){\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$form-&gt;setData($request-&gt;getPost());\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ($form-&gt;isValid()){\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/check authentication...\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$config = $this-&gt;getServiceLocator()-&gt;get(&#039;Config&#039;);\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$passwordhashed = crypt($request-&gt;getPost(&#039;password&#039;), \/** app salt here **\/);\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/hier wird der Auth Adapter von Doctrine geholt, so wie wir ihn vorher konfiguriert haben\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$adapter = $this-&gt;getServiceLocator()-&gt;get(&#039;doctrine.authenticationadapter.orm_default&#039;);\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$adapter-&gt;setIdentityValue($request-&gt;getPost(&#039;email&#039;));\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$adapter-&gt;setCredentialValue($passwordhashed);\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;getAuthService()-&gt;setAdapter($adapter);\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$result = $this-&gt;getAuthService()-&gt;authenticate();\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;foreach($result-&gt;getMessages() as $message)\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/save message temporary into flashmessenger, handle errors here\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ($result-&gt;isValid()) {\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/Dot some stuff for valid users here\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;getAuthService()-&gt;setStorage($this-&gt;getSessionStorage());\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;getAuthService()-&gt;getStorage()-&gt;write($request-&gt;getPost(&#039;email&#039;));\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}\n\n<\/code><\/pre><br \/>\nEs wird im der Request abgefangen und behandelt, wichtig ist hier auch das der Doctrine Adapter den ich vorher konfiguriert habe, hier \u00fcber den ServiceManager \/ SerivceLocator geholt wird. Dort ist alle schon vorkonfiguriert und es wird nur mehr das zu testende Passwort und Username gecheckt. Weiters wird im AuthService Storage handling betrieben, d.h. es wird die Email Adresse hinterlegt. Der User Selbst wird auch in die Session gesteckt, die passiert aber bereits im Adapter\n<\/p>\n<h3>Login mit Facebook<\/h3>\n<p>\nNeben dem normalen Login mit Email und Passwort, habe ich noch einen Login \u00fcber OAuth von Facebook implementiert. Hier wird das Facebook Konto als Login f\u00fcr die Applikation hergenommen. Ich habe mehrere fertige L\u00f6sungen f\u00fcr Zend2 ausprobiert, jedoch hat keine f\u00fcr mich funktioniert. Man braucht jedoch f\u00fcr diesen Login bei Facebook nur in der Doku nachzusehen, um zu erkennen das daf\u00fcr mit simplen nativen PHP Funktionen alles erledigt werden kann. In Zend muss dann nur mehr ein eigener Adapter, der ja das Authentifizieren im AuthenicationService durchf\u00fchrt, implementiert werden, dieser sieht wie folgt aus. Der erste Schritt zum Facebook Login sieht dann so aus im Controller aus:<br \/>\n<pre><code class=\"preserve-code-formatting\">\npublic function fbAuthAction(){\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$config = $this-&gt;getServiceLocator()-&gt;get(&#039;Config&#039;);\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$session = new Container(&#039;fb&#039;);\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$fbsessval =&nbsp;&nbsp;md5(uniqid(rand(), TRUE));\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$session-&gt;offsetSet(&#039;state&#039;,$fbsessval); \/\/ CSRF protection\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$fbapiconfig = $this-&gt;getServiceLocator()-&gt;get(&#039;AAUShare\\Bean\\FBApiConfig&#039;);\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$dialog_url = $fbapiconfig-&gt;getUrl($fbsessval);\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return new ViewModel(array(&#039;dialog_url&#039;=&gt;$dialog_url));\n }\n<\/code><\/pre><br \/>\nEs wird hier \u00fcber das Config file, die Keys f\u00fcr die Facebook Api ausgelesen und der Link passend zusammen gebaut<br \/>\n(Sollte so aussehen: https:\/\/www.facebook.com\/dialog\/oauth?client_id=YOUR_APP_ID&#038;redirect_uri=YOUR_REDIRECT_URI&#038;state=SOME_ARBITRARY_BUT_UNIQUE_STRING), der State ist ein zuf\u00e4llig generierter String der beim Callback wieder ben\u00f6tigt wird und daher in die Session abgelegt wird. <br \/>\nWeiter geht es mit der callback &#8211; Methode im Controller. Hier gelangt man nach dem Login auf wieder zur\u00fcck.<br \/>\n<pre><code class=\"preserve-code-formatting\">\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$session = new Container(&#039;fb&#039;);\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$sstate = $session-&gt;state;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if($sstate &amp;&amp; ($sstate === $this-&gt;getStateFromRequest())) {\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;getServiceLocator()-&gt;get(&#039;AAUShare\\Service\\FacebookService&#039;)-&gt;authWithReqquestCode($this-&gt;getRequestCode());\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} else { \/\/TODO: ErrorHandling\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo(&quot;The state does not match. You may be a victim of CSRF.&quot;);\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $code = $_REQUEST[&quot;code&quot;];\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \/\/echo $code;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} \n<\/code><\/pre><br \/>\nEs wird hier die State Variable wieder aus der Session geholt sowie mit getRequestCode aus der $_REQUEST Variable der Wert von Code geholt der von Facebook generiert wird. Im FacebookService passiert dann der eigentliche authentifizierungs Vorgang in der Applikation statt. <\/p>\n<p><pre><code class=\"preserve-code-formatting\">\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ....\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $config = $this-&gt;getSerivceManager()-&gt;get(&#039;AAUShare\\Bean\\FBApiConfig&#039;);\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$response = file_get_contents($config-&gt;getGraphUrl($requestCode));\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$params = null;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;parse_str($response, $params);\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$adapter = $this-&gt;getSerivceManager()-&gt;get(&#039;AAUShare\\Adapter\\FBAuthAdapter&#039;);\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$adapter-&gt;setAccesstoken($params[&#039;access_token&#039;]);\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$authenticationService = new \\Zend\\Authentication\\AuthenticationService();\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$authenticationService-&gt;setAdapter($adapter);\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return $authenticationService-&gt;authenticate();\n<\/code><\/pre><br \/>\nEs wird wieder die Config geladen, danach werden \u00fcber die Graph API von Facebook ein Accestoken geholt. Anschlie\u00dfend werden die geholten Daten weiter verarbeitet. Es wird durch den soeben erlangten Accesstoken, der den Zugriff auf die Userdaten auf Facebook erlaubt, genutzt um die Daten vom User zu holen. Anschlie\u00dfend wird der eigene Adapter geholt und dem Service \u00fcbergeben. Hier noch kurz die Methode vom Adapter. Im handleFbAuth wird also nur mehr \u00fcberpr\u00fcft ob der User bereits in der Datenbank vorhanden ist, wenn nicht wird er angelegt. Wichtig hier auch noch der Return Wert &#8222;Result(\\Zend\\Authentication\\Result::SUCCESS, $user)&#8220; hier das User Objekt abgelegt, \u00fcber das man sp\u00e4ter in der Applikation mit dem AuthenticationService->getIdentity() zugreifen kann (wird in der Session abgelegt)<\/p>\n<p><pre><code class=\"preserve-code-formatting\">\npublic function authenticate()\n&nbsp;&nbsp;&nbsp;&nbsp;{\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$graph_url = &quot;https:\/\/graph.facebook.com\/me?access_token=&quot;.$this-&gt;accesstoken;\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$user_json = json_decode(file_get_contents($graph_url));\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$user = $this-&gt;getUserService()-&gt;handleFbAuth($user_json);\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if($user != null){\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return new \\Zend\\Authentication\\Result(\\Zend\\Authentication\\Result::SUCCESS, $user);\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return new \\Zend\\Authentication\\Result(\\Zend\\Authentication\\Result::FAILURE_IDENTITY_NOT_FOUND, array(&quot;failure on facebook login&quot;));\n&nbsp;&nbsp;&nbsp;&nbsp;}\n<\/code><\/pre><\/p>\n<p>Ab diesen Punkt kann man mit beiden L\u00f6sungen pr\u00fcfen ob der User eingeloggt ist und welcher User eingeloggt ist (AuthenticationService->hasIdentity() und AuthenticationService->getIdentity()\n<\/p>\n<ul>\n<li><a href=\"https:\/\/developers.facebook.com\/docs\/howtos\/login\/server-side-login\/\" >https:\/\/developers.facebook.com\/docs\/howtos\/login\/server-side-login\/<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>F\u00fcr meine AAUShare Applikation brauch ich ja wie bereits in meinen letzten Eintrag erw\u00e4hnt eine User Authentfizierung. Dies habe ich mit 2 Varianten gel\u00f6st. Zuerst gibt es den einfachen Login \u00fcber eine eigene User Tabelle mithilfe von Doctrine. Um die zu erm\u00f6glichen werden mehrere Schritte ben\u00f6tigt. Zuerst\u00a0muss das application.config.php File erweitert werden &#039;doctrine&#039; =&gt; array( [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5,3,4],"tags":[20,21,17,18,19],"class_list":["post-134","post","type-post","status-publish","format-standard","hentry","category-doctrine-2","category-php","category-zend-2","tag-auth","tag-doctrine2","tag-facbeook","tag-login","tag-zend2"],"_links":{"self":[{"href":"https:\/\/www.zellot.at\/blogs\/wp-json\/wp\/v2\/posts\/134","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.zellot.at\/blogs\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.zellot.at\/blogs\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.zellot.at\/blogs\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.zellot.at\/blogs\/wp-json\/wp\/v2\/comments?post=134"}],"version-history":[{"count":1,"href":"https:\/\/www.zellot.at\/blogs\/wp-json\/wp\/v2\/posts\/134\/revisions"}],"predecessor-version":[{"id":135,"href":"https:\/\/www.zellot.at\/blogs\/wp-json\/wp\/v2\/posts\/134\/revisions\/135"}],"wp:attachment":[{"href":"https:\/\/www.zellot.at\/blogs\/wp-json\/wp\/v2\/media?parent=134"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.zellot.at\/blogs\/wp-json\/wp\/v2\/categories?post=134"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.zellot.at\/blogs\/wp-json\/wp\/v2\/tags?post=134"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}