MediaWiki来自外部表单的身份验证

时间:2009-07-09 21:43:12

标签: mediawiki restful-authentication

我已经安装了mediawiki,但是我想让用户通过外部身份验证表单进行身份验证。当他们输入正确的用户名和密码时,他们会被重定向到维基页面,不需要再次重新键入登录数据,因此他们可以按照他们想要的方式编辑维基。我怎样才能实现呢?

3 个答案:

答案 0 :(得分:3)

将mediawiki API与action = login一起使用。见http://en.wikipedia.org/w/api.php

答案 1 :(得分:0)

如果您有提供网络身份验证服务的外部身份验证服务,则可以调整部分网络扩展This one在我的组织中使用。你当然必须自定义它。

另一个选项是 OpenID 登录this extension,看起来类似于stackoverflow登录。

在这两个解决方案中,“外部表单”和您的wiki之间不会发送密码,只有表示用户通过登录质询的令牌。

答案 2 :(得分:0)

另见https://www.mediawiki.org/wiki/User:Krinkle/API_PHP_cURL_example

简单代码:

<?php

// Retrieves email address and password from sign-in form
$Username = array_key_exists('username',$_REQUEST)?$_REQUEST['username']:'';
$Password = array_key_exists('password',$_REQUEST)?$_REQUEST['password']:'';
$Action = array_key_exists('action',$_REQUEST)?$_REQUEST['action']:'';


$API_Location = "http://127.0.0.1/w/api.php";

//copied from LocalSettings.php

$wgDBtype = "mysql";
$wgDBserver = "localhost";
$wgDBname = "wiki";
$wgDBuser = "myuser";
$wgDBpassword = "12312312";

$CookiePrefix = 'wiki';

$expire = 60*60*24*365*5 + time();
$CooiePath= null; //='/';
$CookieDomain = null; //'example.com';




function encodeURIComponent($str) {
    $revert = array('%21'=>'!', '%2A'=>'*', '%27'=>"'", '%28'=>'(', '%29'=>')');
    return strtr(rawurlencode($str), $revert);
}


class curl_onHeaders
{
    public $result=array();
    function onHeader( $curl, $header_line ) {
        $this->result[]=$header_line;
        return strlen($header_line);
    }
}

function curl($method,$url,$data=false,$headers=false)
{
    //$method="PUT"
    //$url ="http://example.com";
    //$data = "The updated text message";
    //$headers=array();  $headers[] = 'Accept: text/html';
    $ch = curl_init();
    if($data!==false)
    {
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch,CURLOPT_POSTFIELDS,$data); // any post data, a string like param1=a&param2=b
    }
    if($headers!==false)
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);  
    curl_setopt($ch, CURLOPT_URL,$url);
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);  //for updating we have to use PUT method.
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 


    $onHeader = new curl_onHeaders();
    curl_setopt($ch, CURLOPT_HEADERFUNCTION, array(&$onHeader, 'onHeader'));

    $result = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    $object = new stdClass();
    $object->result = $result;
    $object->code = $code;
    $object->headers = $onHeader->result;

    if(curl_errno($ch))
              throw new Exception("curl error: ".  curl_error($ch)); 
              //$object->error =curl_error($ch);

    return $object;
}




function getcookies($headers)
{
    $cookies='';
    foreach( $headers as $header)
    {
        if (preg_match('/^Set-Cookie:\s*([^;]*)/mi', $header, $cookie) == 1)
        {
            if($cookies==='')
                $cookies = $cookie[1];
            else
                $cookies .="; ".$cookie[1];
        }
    }
    return $cookies;
}

function mearge_cookies($old,$new)
{
    // cookies like session are sent only once from server, multiple cookies generally can be mearged  with "; "
    // a cookie jar is prefered  but this code generally fine.
    // folowing code does not handle expires
    //
    // cookie format: https://msdn.microsoft.com/en-us/library/windows/desktop/aa384321(v=vs.85).aspx
    //
    // Set-Cookie: <name>=<value>[; <name>=<value>]...
    // [; expires=<date>][; domain=<domain_name>]
    // [; path=<some_path>][; secure][; httponly]
    //
    // <date> format:
    // DAY, DD-MMM-YYYY HH:MM:SS GMT
    // DAY The day of the week (Sun, Mon, Tue, Wed, Thu, Fri, Sat).
    // DD The day in the month (such as 01 for the first day of the month).
    // MMM The three-letter abbreviation for the month (Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec).
    // YYYY The year.
    // HH The hour value in military time (22 would be 10:00 P.M., for example).
    // MM The minute value.
    // SS The second value.


    $cookiesa=array();
    $cookies_strs_to_merge=array($old,$new);
    foreach($cookies_strs_to_merge as $cookies_str)
    {
        foreach(preg_split("/\\s*;\\s*/",$cookies_str) as $cookie)
        {
         $pcookie=preg_split("/\\s*=\\s*/",$cookie);
         $cookie_name=$pcookie[0];
         $cookie_value=$pcookie[1];
         if(sizeof($pcookie)>1)
         {
             if($cookie_name=='domain') continue;
             if($cookie_name=='expires') continue;
             if($cookie_name=='path') continue;
            $cookiesa[$cookie_name]=$cookie_value;
         }
         else if($cookie=='secure' )continue;
         else if($cookie=='httponly' )continue;
        }
    }
    $cookies='';
    foreach($cookiesa as $cookie_name=>$cookie_value)
     $cookies.=($cookies===''?'':'; ').$cookie_name.'='.$cookie_value;
 return $cookies;
}
//echo mearge_cookies("aaa=vsdfvsdfv; bbb=asdfasdfasf","aaa=222; ccc=123123"); die;

//$res=curl("GET",'http://doodkin.com');
//$lastcookies=getcookies($res->headers);
//$res=curl("GET",'http://doodkin.com',false,array('Cookie: '.$lastcookies));
//$lastcookies=mearge_cookies($lastcookies, getcookies($res->headers) );


mysql_connect($wgDBserver, $wgDBuser, $wgDBpassword) or die('Could not connect: ' . mysql_error());


if($Action == 'login')
{ 



    // Query to retrieve username from database based on email. It is implied that authentication has already succeeded.
    $Query = "SELECT Username FROM `$wgDBname`.Accounts WHERE Email = '".mysql_escape_string($Username)."'";
    $ResultSet = mysql_query($Query);
    if(mysql_num_rows($Query))
    {
        $ResultArray = mysql_fetch_array($ResultSet);
        $Username = $ResultArray[0]; // Username
    }
    mysql_free_result($ResultSet);



    // first http post to sign in to MediaWiki  
    $res=curl("POST",$API_Location,"action=login&lgname=".encodeURIComponent($Username)."&lgpassword=".encodeURIComponent($Password)."&format=php");
    $lastcookies=getcookies($res->headers);
    $result = unserialize($res->result);
    $Token = $result[login][token];

    // cookie must be set using session id from first response
    $WikiSessionID = $result[login][sessionid];
    setcookie("${CookiePrefix}_session", $WikiSessionID, $expire, $CooiePath, $CookieDomain);

    // second http post to finish sign in
    if ($result["login"]["result"] == "NeedToken") {
        $res=curl("POST",$API_Location,"action=login&lgname=".encodeURIComponent($Username)."&lgpassword=".encodeURIComponent($Password)."&lgtoken=".encodeURIComponent($Token)."&format=php",array('Cookie: '.$lastcookies));
        $result = unserialize($res->result);
    }


     if ($result["login"]["result"] == "Success") {
        $error = 'ok';


        // set persistent cookies
        $LgToken = $result["login"]["lgtoken"]; 
        $LgUserID = $result["login"]["lguserid"];
        $LgUserName = $result["login"]["lgusername"];
        $cookieprefix = $result["login"]["cookieprefix"];

        if($cookieprefix!=$CookiePrefix) throw new Exception('notice a wrong cookie prefix');


        $_COOKIE["${CookiePrefix}UserName"]=$LgUserName;
        $_COOKIE["${CookiePrefix}UserID"]=$LgUserID;
        $_COOKIE["${CookiePrefix}Token"]=$LgToken;
        $_COOKIE["${CookiePrefix}_session"]=$WikiSessionID;


        setcookie("${CookiePrefix}UserName", $LgUserName, $expire, $CooiePath, $CookieDomain);
        setcookie("${CookiePrefix}UserID", $LgUserID, $expire, $CooiePath, $CookieDomain);
        setcookie("${CookiePrefix}Token", $LgToken, $expire, $CooiePath, $CookieDomain);
    } else if ($result["login"]["result"] == "NeedToken") {
        $error = "Error 005: Token error. second request.";

    } else if ($result["login"]["result"] == "NoName") {
        $error =  "The username can not be blank";

    } else if ($result["login"]["result"] == "Illegal") {
        $error =  "You provided an illegal username";

    } else if ($result["login"]["result"] == "NotExists") {
        $error =  "The username you provided doesn't exist";

    } else if ($result["login"]["result"] == "EmptyPass") {
        $error =  "The password can not be blank";

    } else if ($result["login"]["result"] == "WrongPass" || $result["login"]["result"] == "WrongPluginPass") {
        $error =  "The password you provided is incorrect";

    } else if ($result["login"]["result"] == "CreateBlocked") {
        $error =  "Autocreation was blocked from this IP address";

    } else if ($result["login"]["result"] == "Throttled") {
        $error =  "You've logged in too many times in a short time. Try again later.";

    } else if ($result["login"]["result"] == "mustbeposted") {
        $error =  "Error 004: Logindata was not send correctly";

    } else if ($result["login"]["result"] == "Blocked") {
        $error =  "This account is blocked.";

    } else if ($result["login"]["result"]){
        $error = "Error 001: An unknown event occurred.";
    } else {
        $error = "Error 002: An unknown event occurred.";
    }

    echo $error;
}


if($Action == "logout")
{
        // first http post to sign in to MediaWiki  

    $_session = array_key_exists("${CookiePrefix}_session",$_COOKIE)?$_COOKIE["${CookiePrefix}_session"]:'';
    $UserName = array_key_exists("${CookiePrefix}UserName",$_COOKIE)?$_COOKIE["${CookiePrefix}UserName"]:'';
    $UserID = array_key_exists("${CookiePrefix}UserID",$_COOKIE)?$_COOKIE["${CookiePrefix}UserID"]:'';
    $Token = array_key_exists("${CookiePrefix}Token",$_COOKIE)?$_COOKIE["${CookiePrefix}Token"]:'';

    $headers=array( "Cookie: ". 
           "${CookiePrefix}_session=".encodeURIComponent($_session)."; ". 
           "${CookiePrefix}UserName=".encodeURIComponent($UserName)."; ". 
           "${CookiePrefix}UserID=".encodeURIComponent($UserID)."; ". 
           "${CookiePrefix}Token=".encodeURIComponent($Token) );

    $res=curl("POST",$API_Location,"action=logout",$headers);

    $LogoutReturn = unserialize($res->result);

    // destroys persistent cookies and ends session
    $expire = time() - 60*60*24*90;

    setcookie('Session', '', $expire, $CooiePath, $CookieDomain);
    setcookie("${CookiePrefix}_session", '', $expire, $CooiePath, $CookieDomain);
    setcookie("${CookiePrefix}UserName", '', $expire, $CooiePath, $CookieDomain);
    setcookie("${CookiePrefix}UserID", '', $expire, $CooiePath, $CookieDomain);
    setcookie("${CookiePrefix}Token", '', $expire, $CooiePath, $CookieDomain);

        unset($_COOKIE["${CookiePrefix}UserName"]);
        unset($_COOKIE["${CookiePrefix}UserID"]);
        unset($_COOKIE["${CookiePrefix}Token"]);
        unset($_COOKIE["${CookiePrefix}_session"]);


  echo "logout";
}

function checklogin()
{
    global $CookiePrefix,$wgDBname;
    if( array_key_exists("${CookiePrefix}_session",$_COOKIE)
        && array_key_exists("${CookiePrefix}UserID",$_COOKIE)
    )
    {

        $UserID = intval($_COOKIE["${CookiePrefix}UserID"]);
        $UserName = array_key_exists("${CookiePrefix}UserName",$_COOKIE)?$_COOKIE["${CookiePrefix}UserName"]:'';
        $Token = array_key_exists("${CookiePrefix}Token",$_COOKIE)?$_COOKIE["${CookiePrefix}Token"]:'';

        ($result=mysql_query("Select user_name,user_real_name,user_email,user_token,user_token,(Select ug_user from `$wgDBname`.user_groups  WHERE ug_group='sysop' and ug_user=user.user_id) as perms from `$wgDBname`.user user WHERE user_id=$UserID"))||die(mysql_error());
                $udata=mysql_fetch_object($result);
                mysql_free_result($result);

        if ($udata!=null)
        {
            if ( $udata->perms!=null )
            {
                $level = 1;
            }

            if($UserName!=$udata->user_name)
            {
                echo "different username. cookie vs db. can not auto login from mediawiki";
                return null;
            }

            if($Token!=$udata->user_token) {
                echo "different token. cookie vs db. can not auto login from mediawiki";
                return null;
            }

            return array(
                'UniqueID' => $UserID,
                'Name' => $UserName,
                'Title' => $udata->user_real_name==""?NULL:$udata->user_real_name,
                'Email' => $udata->user_email==""?'no@email.com':$udata->user_email,
                'Admin' => $level
            );
        }
        return null;

    }
}

?>
<?

$user=checklogin();
if($user!=null)
{
    ?>
     welcome <?=$user['Title']? $user['Title']:$user['Name'] ?>. <br>
     <a href="<?=$_SERVER['PHP_SELF']?>?action=logout">logout</a>
    <?
}
else
{
    ?>

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->

    <title>Signin</title>

    <!-- Bootstrap core CSS -->
    <link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha/css/bootstrap.css" rel="stylesheet">

<!--[if eq IE 10]>
<style type="text/css">
/*!
 * IE10 viewport hack for Surface/desktop Windows 8 bug
 * http://getbootstrap.com/getting-started/#support-ie10-width
 */
@-webkit-viewport { width: device-width; }
@-moz-viewport    { width: device-width; }
@-ms-viewport     { width: device-width; }
@-o-viewport      { width: device-width; }
@viewport         { width: device-width; }
</style>


    <![endif]-->

    <!-- Custom styles for this template -->
    <style type="text/css">
    body {
      padding-top: 40px;
      padding-bottom: 40px;
      background-color: #eee;
    }

    .form-signin {
      max-width: 330px;
      padding: 15px;
      margin: 0 auto;
    }
    .form-signin .form-signin-heading,
    .form-signin .checkbox {
      margin-bottom: 10px;
    }
    .form-signin .checkbox {
      font-weight: normal;
    }
    .form-signin .form-control {
      position: relative;
      height: auto;
      -webkit-box-sizing: border-box;
         -moz-box-sizing: border-box;
              box-sizing: border-box;
      padding: 10px;
      font-size: 16px;
    }
    .form-signin .form-control:focus {
      z-index: 2;
    }
    .form-signin input[type="email"] {
      margin-bottom: -1px;
      border-bottom-right-radius: 0;
      border-bottom-left-radius: 0;
    }
    .form-signin input[type="password"] {
      margin-bottom: 10px;
      border-top-left-radius: 0;
      border-top-right-radius: 0;
    }
    </style>

    <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
      <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
      <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
    <![endif]-->
  </head>

  <body>

    <div class="container">

      <form class="form-signin" action="<?=$_SERVER['PHP_SELF']?>" method="post" ><input type="hidden" name="action" value="login">
        <h2 class="form-signin-heading">Please sign in</h2>
        <label for="inputEmail" class="sr-only">Username or Email address</label>
        <input type="text" id="inputEmail" class="form-control" name="username" placeholder="Username Or Email address" required autofocus>
        <label for="inputPassword" class="sr-only">Password</label>
        <input type="password" id="inputPassword" name="password" class="form-control" placeholder="Password" required>
        <!-- <div class="checkbox">
          <label>
            <input type="checkbox" value="remember-me"> Remember me
          </label>
        </div> -->
        <button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
      </form>

    </div> <!-- /container -->


    <!--[if eq IE 10]>
<script type="application/javascript">
/*!
 * IE10 viewport hack for Surface/desktop Windows 8 bug
 * Copyright 2014-2015 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 */

// See the Getting Started docs for more information:
// http://getbootstrap.com/getting-started/#support-ie10-width

(function () {
  'use strict';

  if (navigator.userAgent.match(/IEMobile\/10\.0/)) {
    var msViewportStyle = document.createElement('style')
    msViewportStyle.appendChild(
      document.createTextNode(
        '@-ms-viewport{width:auto!important}'
      )
    )
    document.querySelector('head').appendChild(msViewportStyle)
  }

})();
    </script>
    <![endif]-->
  </body>
</html>
    <?
}
@mysql_close($conn);
?>