ログイン後にGETパラメーターを引き継ぐ
要求
DokuWiki をベース CMS にしてアプリケーションを開発していると、未ログイン状態で認証が必要なページにアクセスした際、ログインページに飛ばされ、ログイン後に目的のページにリダイレクトされますが、その際、 URL にカスタムの GET パラメータがあった場合、ログイン後に消えてしまいます。リダイレクトされたページにもそれを引き継ぎたい、というのが今回の要求です。
これは DokuWiki 本体に手を入れるため、DokuWikiの更新で不具合が出るため、注意が必要!
調査
- 実際の認証処理は inc/auth.php で行っている。
- ログインページのフォームに hidden タグを埋め込んだりするのは
inc/html.php::html_login:53
辺りで行っている。 - submit は通常の id を指定した
doku.php?id=“…:…”
に対し POST で送られているdo=login id=…:… sectok=“”
等の POST パラメータが hidden で指定されている。 - 追加のパラメータは
$INPUT->str('name')
で取得できるらしい。event_id
であれば$INPUT->str('event_id')
、int 型であれば$INPUT->int('event_id')
のような感じ。 inc/html.php::html_login
を改造したものの、認証が成功した後はそのままページを表示せずに 302 リダイレクトしている。その際に不要なパラメータが削られている。。。inc/Action/Redirect.php:33
付近、$opts 配列に params プロパティを追加し、引継ぎたい GET パラメータの名前と値を連想配列で指定するinc/Action/Redirect.php:59
付近、wl() への第二引数に先ほどの $opts に追加した params の連想配列を指定する。
実装
バージョンアップにより、実装場所が変更になっている。inc/Ui/Login.php::show()
- inc/html.php
/** * The loginform * * @author Andreas Gohr <andi@splitbrain.org> * * @param bool $svg Whether to show svg icons in the register and resendpwd links or not */ function html_login($svg = false){ global $lang; global $conf; global $ID; global $INPUT; print p_locale_xhtml('login'); print '<div class="centeralign">'.NL; $form = new Doku_Form(array('id' => 'dw__login', 'action'=> $ID)); $form->startFieldset($lang['btn_login']); $form->addHidden('id', $ID); $form->addHidden('do', 'login'); /** ここでログイン後に引継ぎたいパラメータを追加 **/ if ($INPUT->str('test')) $form->addHidden('test', $INPUT->str('test')); $form->addElement(form_makeTextField( 'u', ((!$INPUT->bool('http_credentials')) ? $INPUT->str('u') : ''), $lang['user'], 'focus__this', 'block') ); $form->addElement(form_makePasswordField('p', $lang['pass'], '', 'block')); if($conf['rememberme']) { $form->addElement(form_makeCheckboxField('r', '1', $lang['remember'], 'remember__me', 'simple')); } $form->addElement(form_makeButton('submit', '', $lang['btn_login'])); $form->endFieldset(); if(actionOK('register')){ $registerLink = (new \dokuwiki\Menu\Item\Register())->asHtmlLink('', $svg); $form->addElement('<p>'.$lang['reghere'].': '. $registerLink .'</p>'); } if (actionOK('resendpwd')) { $resendPwLink = (new \dokuwiki\Menu\Item\Resendpwd())->asHtmlLink('', $svg); $form->addElement('<p>'.$lang['pwdforget'].': '. $resendPwLink .'</p>'); } html_form('login', $form); print '</div>'.NL; }
- inc/Action/Redirect.php
/** * Redirect to the show action, trying to jump to the previously edited section * * @triggers ACTION_SHOW_REDIRECT * @throws ActionAbort */ public function preProcess() { global $PRE; global $TEXT; global $INPUT; global $ID; global $ACT; $opts = array( 'id' => $ID, 'preact' => $ACT, 'params' => [] ); /** 引継ぎたい GETパラメータを指定 **/ if ($INPUT->str('test')) $opts['params']['test'] = $INPUT->str('test'); //get section name when coming from section edit if($INPUT->has('hid')) { // Use explicitly transmitted header id $opts['fragment'] = $INPUT->str('hid'); } else if($PRE && preg_match('/^\s*==+([^=\n]+)/', $TEXT, $match)) { // Fallback to old mechanism $check = false; //Byref $opts['fragment'] = sectionID($match[0], $check); } // execute the redirect Event::createAndTrigger('ACTION_SHOW_REDIRECT', $opts, array($this, 'redirect')); // should never be reached throw new ActionAbort('show'); } /** * Execute the redirect * * Default action for ACTION_SHOW_REDIRECT * * @param array $opts id and fragment for the redirect and the preact */ public function redirect($opts) { $go = wl($opts['id'], $opts['params'], true, '&'); /** 第二引数を指定 **/ if(isset($opts['fragment'])) $go .= '#' . $opts['fragment']; //show it send_redirect($go); }
課題
DokuWikiソースに手を加えなくていいよう、Plugin 化したい。