[C#/PHP] Externer Login für WoltLab Burning Board 3 [15.10.2012]

    • Release
    • Open Source

    Es gibt 54 Antworten in diesem Thema. Der letzte Beitrag () ist von Pac.

      Lukas schrieb:

      Dynamische Gruppen klingt schwer, ich wüsste nicht, dass das WBB/WCF da irgendwas für stellen würde.

      Naja, du hast ja den Username. Über den kommst du sicherlich auch an eine art User-Klasse, über die man sicherlich an die User-Spezifischen Daten (z. B. Postcount) kommt. Bevor du dann die Login-Daten prüfst, kannst du ja dann auf diese kriterien prüfen.
      Von meinem iPhone gesendet
      Die Sache war auch eher, wie man das gut integriert bekommt, auch in den Optionen. Und ob man diese dynamische Gruppe WBB-Gruppen zuordnen lassen kann, oder ob sie global gelten.

      Also Postcount/Registrierungszeitpunkt würde ich schonmal als Bedingung nehmen, sonst noch was?
      „Was daraus gefolgert werden kann ist, dass jeder intelligentere User sein Geld lieber für Bier ausgibt, um einen schönen Rausch zu haben, und nicht dieses Ranzprodukt.“

      -Auszug aus einer Unterhaltung über das iPhone und dessen Vermarktung.

      slice schrieb:

      nebenbei n doppelpost? echt jetzt?
      Das Ganze habe ich deshalb gemacht, da ich ja zuerst dachte, dass sich das Thema damit erledigt hätte was ich ja auch so geschrieben habe. Ich hatte gesehen, dass Lukas in der Zeit im Thema aktiv war. Als ich jetzt nach ein paar Minuten die andere Fehlermeldung nachgetragen hatte, war er nicht mehr aktiv. Da sich ein Beitrag durch das bearbeiten ja nicht als neu markiert, hätte Lukas mein nachgetragenes Problem wahrscheinlich erst viel später gelesen. Da mich aber in der Angelegenheit ein wenig die Zeit drängt, wollte ich das verhindern.

      Lukas schrieb:

      Für Eigenbauten mag ich nur ungerne breiten Support geben, denn "SUCCESS" sollte in keinem Falle irgendwo auftauchen.
      Ich verstehe nicht so ganz, wie du ständig darauf kommst, dass ich das umgebaut hätte. Jetzt mal ehrlich, dass einzige was ich modifiziert habe ist das, was du mir gesagt hast (Datenbankdaten direkt eintragen).
      Ich kann jedenfalls keines deiner Probleme so wirklich verstehen, weder nachkonstruieren. Der Statuscode sollte nunmal nirgends als String auftauchen.
      „Was daraus gefolgert werden kann ist, dass jeder intelligentere User sein Geld lieber für Bier ausgibt, um einen schönen Rausch zu haben, und nicht dieses Ranzprodukt.“

      -Auszug aus einer Unterhaltung über das iPhone und dessen Vermarktung.
      Huh... okay. Dann lade ich jetzt das Script nochmal komplett neu aus dem Startpost herunter, trage die Datenbankdaten wieder ein und gucke, was dann passiert. Wenn dann immernoch das bei rauskommt, mach ich nen Video von...

      EDIT: So. Alles nochmal neu gemacht - Selbes Ergebnis, die Statuscodes werden als String ausgegeben. Aber ich habe mir jetzt mal die login.inc.php angeschaut und mit meinen nicht-PHP-Kentnissen mal versucht zu verstehen. Und ab Zeile 72 wird für jeden Status folgendes Aufgerufen: $output = Main::GenerateResponse(SUCCESS, $data); wobei $data nur bei Erfolg ausgeben wird. Die GenerateResponse-Funktion sieht folgendermaßen aus:

      PHP-Quellcode

      1. function GenerateResponse($code, $data = array())
      2. {
      3. return json_encode(array("StatusCode" => $code, "UserData" => $data));
      4. }
      Dort wird doch also nur der übergebene Wert (in dem Fall SUCCESS) in die Statusmeldung eingetragen. Also ist es doch kein Wunder, warum dann da ein String bei rauskommt...

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „FunnySunny“ ()

      Die Definition sagt mir was anderes. Da stehen Zahlen hinter.


      ideone.com/DSULjb

      Rückgabe von V1.2.2 unter PHP 5.5.0 in der WBBLite-Testinstallation (2.1.2 pl 1 (Aurora), WCF 1.1.10 (Tempest)):

      Quellcode

      1. {"StatusCode":1,"UserData":{"userID":1,"username":"MightyAdmin","posts":0,"groups":[{"groupID":1,"groupName":"Jeder"},{"groupID":3,"groupName":"Registrierte Benutzer"},{"groupID":4,"groupName":"Administratoren"}]}}


      Schick mir den Link zu deinem Forum bitte mal per PN. Weitere Daten wie Skript-, PHP-, WBB und WCF-Version wären zur Problemlösung sicher auch noch hilfreich.
      „Was daraus gefolgert werden kann ist, dass jeder intelligentere User sein Geld lieber für Bier ausgibt, um einen schönen Rausch zu haben, und nicht dieses Ranzprodukt.“

      -Auszug aus einer Unterhaltung über das iPhone und dessen Vermarktung.
      So, ich denke mal, das mit dem WBB-Paket hat Zukunft.

      Ich habe vor das System wiefolgt aufzubauen: Die Standardoptionen vom Screenshot sind nach wie vor verfügbar. Weiterhin soll das Feature für einzelne Benutzergruppen an- und abschaltbar sein. Außerdem sollen die einzelnen Felder, die die Schnittstelle am Ende ausgibt, konfigurierbar sein. Ich denke, dass das in die Haupteinstellungen wandert, oder gibt es da andere Ansichten? In den Gruppeneinstellungen macht es mMn nicht unbedingt Sinn.

      Die Liste der Felder umfasst derzeit folgende:

      Quellcode

      1. userID
      2. username
      3. email
      4. languageID
      5. registrationDate
      6. styleID
      7. oldUsername
      8. lastUsernameChange
      9. banned
      10. banReason
      11. rankID
      12. userTitle
      13. activityPoints
      14. lastActivityTime
      15. profileHits
      16. pmTotalCount
      17. pmUnreadCount
      18. pmOutstandingNotifications
      19. avatarURL
      20. posts
      21. Liste der Gruppen
      22. groupID
      23. groupName


      Hat jemand Verbesserungsvorschläge?

      mfg
      Lukas
      „Was daraus gefolgert werden kann ist, dass jeder intelligentere User sein Geld lieber für Bier ausgibt, um einen schönen Rausch zu haben, und nicht dieses Ranzprodukt.“

      -Auszug aus einer Unterhaltung über das iPhone und dessen Vermarktung.

      Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Lukas“ ()

      Nein, im Moment nicht.
      „Was daraus gefolgert werden kann ist, dass jeder intelligentere User sein Geld lieber für Bier ausgibt, um einen schönen Rausch zu haben, und nicht dieses Ranzprodukt.“

      -Auszug aus einer Unterhaltung über das iPhone und dessen Vermarktung.
      Per PN wurde ich angefragt, ob ich die Projektmappe der Bibliothek zur Verfügung stellen könnte.

      Auch wenn die Bibliothek im Kern eigentlich nur auf einen WebClient und etwas JSON herausläuft werde ich die Projektmappe im Startpost anhängen. Sie enthält einige experimentelle Änderungen, von denen ich nicht sagen kann, ob sie funktionieren(/funktioniert haben). Eine Version der Projektmappe, welche den derzeitigen Download wiederspiegelt, konnte ich auf die Schnelle nicht auftreiben, wer das unbedingt braucht, kann dekompilieren.
      „Was daraus gefolgert werden kann ist, dass jeder intelligentere User sein Geld lieber für Bier ausgibt, um einen schönen Rausch zu haben, und nicht dieses Ranzprodukt.“

      -Auszug aus einer Unterhaltung über das iPhone und dessen Vermarktung.
      @Lukas

      Ich hab da mal eine Frage:

      Ich will die Usergroups accessen, heißt VIP, Admin, Mod etc.,
      aber ich verstehe nicht ganz wie ich die Usergroup von der LoginResponse Instanz abfragen kann.

      C#-Quellcode

      1. if (/*response.UserData.PostCount >= 40*/ response.UserData.Groups[0].GroupName == "VIP")
      2. {
      3. MessageBox.Show("Der Login war korrekt, der Benutzer ist nicht gebannt und hat mehr als 40 Beiträge.");
      4. }


      Man muss ja irgendwie auf die Property GroupName oder GroupID zugreifen können was man ja nur via index machen kann.
      Ich weiß aber nicht ob das jetzt so richtig ist, weil ich einfach den Index null genommen habe und das ja bestimmt nur auf die nullte(erste) Group
      zugreift und nicht die direkte Group der LoginResponse abfragt. Danke im vorraus.

      EDIT: Um es nochmal klarzustellen, Ich möchte nicht die einzelnen Elemente der Liste, also die einzelnen Groups accessen die vorhanden sind, sondern ich will direkt die GroupID / GroupName
      der LoginResponse Instanz checken um so einen Mod Login zu performen. Hoffe mir kann jemand helfen ;)
      Du benötigst eine for oder foreach-Schleife, mit welcher du die Liste der Gruppen durchgehen kannst.

      msdn.microsoft.com/en-us/library/ttw7t8t6.aspx
      msdn.microsoft.com/en-us/library/ch45axte.aspx
      „Was daraus gefolgert werden kann ist, dass jeder intelligentere User sein Geld lieber für Bier ausgibt, um einen schönen Rausch zu haben, und nicht dieses Ranzprodukt.“

      -Auszug aus einer Unterhaltung über das iPhone und dessen Vermarktung.
      Hey Lukas, ggf. Kannst du mir mal Helfen.

      und zwar, ich habe Versucht das Ganze in WBB4 zu Realisieren. Also dein Script genommen und die Ganzen SQL Abfragen abgeändert, problem. Die Berechnung des Passwort ist Komplett anders. Also.. Gegoogelt und Fündig geworden. Angefagen zu Versuchen und einzupacken.... Ich glaub ich habe nun Kompletten quirl gemacht ^^ Wäre nett wenn du es dir mal Anschauen könntest.

      PHP-Quellcode

      1. <?php
      2. require_once 'includes/db.inc.php';
      3. class ExternalLogin
      4. {
      5. function __construct()
      6. {
      7. MySQL::Connect();
      8. }
      9. function Check($username, $password)
      10. {
      11. $username = mysql_real_escape_string($username);
      12. $password = mysql_real_escape_string($password);
      13. $output;
      14. $query = "SELECT `userID`, `password`, `accessToken`, `banned` FROM ".DBPREFIX."_user WHERE `username`='".$username."'";
      15. $result = mysql_query($query);
      16. if(mysql_num_rows($result) == 1)
      17. {
      18. while($row = mysql_fetch_array($result))
      19. {
      20. $salt = self::getSaltedHash($row["password"]);
      21. $dbpassword = $row["password"];
      22. $userID = intval($row["userID"]);
      23. $banned = intval($row["banned"]) == 1 ? true : false;
      24. if($banned)
      25. {
      26. $output = Main::GenerateResponse(USER_BANNED);
      27. }
      28. else
      29. {
      30. if(self::GenerateWBBPass($password, $salt) == $dbpassword)
      31. {
      32. //get more user info.
      33. //array of user groups
      34. $data = array();
      35. $groupIDs = array();
      36. $groups = array();
      37. $query = "SELECT `groupID` FROM ".DBPREFIX."_user_to_groups WHERE `userID`='".$userID."'";
      38. $dbgroupIDs = mysql_query($query);
      39. while($row = mysql_fetch_array($dbgroupIDs))
      40. {
      41. array_push($groupIDs, $row["groupID"]);
      42. }
      43. //get displayable group names
      44. foreach ($groupIDs as $groupID)
      45. {
      46. $query = "SELECT `groupName` FROM ".DBPREFIX."_user_group WHERE `groupID`='".$groupID."'";
      47. $dbgroups = mysql_query($query);
      48. while($row = mysql_fetch_array($dbgroups))
      49. {
      50. array_push($groups, array("groupID" => intval($groupID), "groupName" => $row["groupName"]));
      51. }
      52. }
      53. //get post count
      54. $query = "SELECT `wbbPosts` FROM ".DBPREFIX."_user WHERE `userID`='".$userID."'";
      55. $dbposts = mysql_query($query);
      56. while($row = mysql_fetch_array($dbposts))
      57. {
      58. $posts = intval($row["wbbPosts"]);
      59. }
      60. $data = array("userID" => $userID, "username" => $username, "posts" => $posts, "groups" => $groups);
      61. $output = Main::GenerateResponse(SUCCESS, $data);
      62. }
      63. else
      64. {
      65. $output = Main::GenerateResponse(WRONG_PASS);
      66. }
      67. }
      68. }
      69. }
      70. else
      71. {
      72. $output = Main::GenerateResponse(USER_NO_MATCH);
      73. }
      74. MySQL::Close();
      75. return $output;
      76. }
      77. function GenerateWBBPass($password, $salt)
      78. {
      79. return sha1($salt.sha1($salt.$password));
      80. }
      81. public static function getSaltedHash($password, $salt = null) {
      82. if ($salt === null) {
      83. $salt = self::getRandomSalt();
      84. }
      85. return crypt($password, $salt);
      86. }
      87. private static $blowfishCharacters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789./';
      88. public static function getRandomSalt() {
      89. $salt = '';
      90. for ($i = 0, $maxIndex = (strlen(self::$blowfishCharacters) - 1); $i < 22; $i++) {
      91. $salt .= self::$blowfishCharacters[self::secureRandomNumber(0, $maxIndex)];
      92. }
      93. return self::getSalt($salt);
      94. }
      95. const BCRYPT_COST = '08';
      96. const BCRYPT_TYPE = '2a';
      97. protected static function getSalt($salt) {
      98. $salt = mb_substr($salt, 0, 22);
      99. return '$' . self::BCRYPT_TYPE . '$' . self::BCRYPT_COST . '$' . $salt;
      100. }
      101. public static function secureRandomNumber($min, $max) {
      102. $range = $max - $min;
      103. if ($range == 0) {
      104. // not random
      105. throw new SystemException("Cannot generate a secure random number, min and max are the same");
      106. }
      107. // fallback to mt_rand() if OpenSSL is not available
      108. if (version_compare(PHP_VERSION, '5.4.0-dev', '<') || !function_exists('openssl_random_pseudo_bytes')) {
      109. return mt_rand($min, $max);
      110. }
      111. $log = log($range, 2);
      112. $bytes = (int) ($log / 8) + 1; // length in bytes
      113. $bits = (int) $log + 1; // length in bits
      114. $filter = (int) (1 << $bits) - 1; // set all lower bits to 1
      115. do {
      116. $rnd = hexdec(bin2hex(openssl_random_pseudo_bytes($bytes, $s)));
      117. $rnd = $rnd & $filter; // discard irrelevant bits
      118. }
      119. while ($rnd >= $range);
      120. return $min + $rnd;
      121. }
      122. }
      123. class Main
      124. {
      125. function GenerateResponse($code, $data = array())
      126. {
      127. return json_encode(array("StatusCode" => $code, "UserData" => $data));
      128. }
      129. function CheckValue($value)
      130. {
      131. return strlen($value) != 0;
      132. }
      133. }
      134. ?>



      Ich danke schon mal fürs Durchlesen und freue mich Auf Antworten!
      Frohe Ostern!

      Mit freundlichen Grüßen,
      Pac