2012-10-31 6 views
12

Zurück im Mai habe ich this question gepostet. Ich versuche das Gleiche noch einmal auf einer anderen App zu tun, aber ich habe keine Lösung für dieses Problem gefunden. Ich habe mehr Informationen und besseren Code, also hoffe ich, dass ihr mir helfen könnt, das zu klären.CakePHP 2.x Auth mit zwei separaten Logins

Anwendungsfall: Arztpraxis hat eine Website mit Admin-Benutzern. Die Benutzer loggen sich erfolgreich mit CakePHP's Auth über User Modell und UsersController ein.

Ärzte haben überweisende Ärzte mit völlig anderen Profilen und Aktionen. Ärzte müssen sich über example.com/physicians/login anmelden. Allerdings ist diese Anmeldung mit diesem Fehler

authError => 'You are not authorized to access that location.'

Hier ist mein Code in AppController:

class AppController extends Controller { 
public $helpers = array('Form', 'Html', 'Time', 'Session', 'Js' => array('Jquery')); 

public $components = array(
    'Session', 
    'Auth' => array(
     'autoRedirect' => false, 
     'authorize' => 'Controller' 
    ) 
); 

public function beforeFilter() { 
    $this->Auth->allow('index', 'view', 'edit', 'display', 'featured', 'events', 'contact', 'signup', 'search', 'view_category', 'view_archive', 'addComment', 'schedule', 'login'); 
} 

}

Und hier ist mein UsersController, die funktioniert:

class UsersController extends AppController { 

public $components = array(
    'Auth' => array(
     'authenticate' => array(
      'Form' => array(
       'userModel' => 'User', 
       'fields' => array(
        'username' => 'username', 
        'password' => 'password' 
       ) 
      ) 
     ), 
     'loginRedirect' => array('controller' => 'users', 'action' => 'admin'), 
     'logoutRedirect' => array('controller' => 'pages', 'action' => 'index'), 
     'loginAction' => array('controller' => 'users', 'action' => 'login'), 
     'sessionKey' => 'Admin' 
    ) 
); 


public function beforeFilter() { 
    parent::beforeFilter(); 
    $this->Auth->allow('add', 'login', 'logout'); 
} 

function isAuthorized() { 
    return true; 
} 

public function login() { 
    if ($this->request->is('post')) { 
     if ($this->Auth->login()) { 
      $this->redirect($this->Auth->redirect()); 
     } else { 
      $this->Session->setFlash(__('Invalid username or password, try again')); 
     } 
    } 
} 

public function logout() { 
    $this->Session->destroy(); 
    $this->redirect($this->Auth->logout()); 
} 

Hier ist meine PhysiciansController Code, der nicht funktioniert:

class PhysiciansController extends AppController { 

public $components = array(
    'Auth' => array(
     'authenticate' => array(
      'Form' => array(
       'userModel' => 'Physician', 
       'fields' => array(
        'username' => 'username', 
        'password' => 'password' 
       ) 
      ) 
     ), 
     'loginRedirect' => array('controller' => 'physicians', 'action' => 'dashboard'), 
     'logoutRedirect' => array('controller' => 'pages', 'action' => 'index'), 
     'loginAction' => array('controller' => 'physicians', 'action' => 'login'), 
     'sessionKey' => 'Physician' 
    ) 
); 

public function beforeFilter() { 
    parent::beforeFilter(); 

    $this->Auth->authorize = array(
     'Actions' => array(
      'userModel' => 'Physician', 
      'actionPath' => 'physicians' 
     ) 
    ); 

    $this->Auth->allow('login', 'logout'); 
// $this->Session->write('Auth.redirect','/physicians/index'); 
} 

function isAuthorized() { 
    return true;  
} 

public function login() { 
    if ($this->request->is('post')) { 
     if ($this->Auth->login()) { 
      $this->redirect(array('controller' => 'physicians', 'action' => 'dashboard')); 
     } else { 
      $this->Session->read(); 
      debug($this->Auth); 
      $this->Session->setFlash(__('Invalid username or password, try again')); 
     } 
    } 
} 

public function logout() { 
    $this->Session->destroy(); 
    $this->redirect($this->Auth->logout()); 
} 

Ich möchte wirklich nicht über starten und zu ACL wechseln - ich bin mir nicht sicher, dass nur zwei Anmeldungen notwendig ist. Hilfe wäre sehr willkommen!

EDIT: Joshua Antwort ist super und super hilfreich. Ich habe es implementiert, aber ich erhalte immer noch einen nicht autorisierten Fehler, wenn ich versuche, mich als Arzt über/phys/physican/login (Präfix/Controller/Aktion) anzumelden. Das Admin-Setup funktioniert großartig. Hier ist der Code debuggen, wenn ich versuche, um sich einzuloggen:

object(AuthComponent) { 
    components => array(
    (int) 0 => 'Session', 
    (int) 1 => 'RequestHandler' 
) 
authenticate => array(
    'Form' => array(
     'userModel' => 'Physician' 
    ) 
) 
authorize => false 
ajaxLogin => null 
flash => array(
    'element' => 'default', 
    'key' => 'auth', 
    'params' => array() 
) 
loginAction => array(
    'controller' => 'physicians', 
    'action' => 'phys_login' 
) 
loginRedirect => null 
logoutRedirect => '/' 
authError => 'You are not authorized to access that location.' 
allowedActions => array() 
request => object(CakeRequest) { 
    params => array(
     'prefix' => '*****', 
     'plugin' => null, 
     'controller' => 'physicians', 
     'action' => 'phys_login', 
     'named' => array(), 
     'pass' => array(), 
     'phys' => true, 
     '_Token' => array(
      'key' => 'ad1ea69c3b2c7b9e833bbda03ef18b04079b23c3', 
      'unlockedFields' => array() 
     ), 
     'isAjax' => false 
    ) 
    data => array(
     'Physician' => array(
      'password' => '*****', 
      'username' => 'deewilcox' 
     ) 
    ) 
    query => array() 
    url => 'phys/physicians/login' 
    base => '' 
    webroot => '/' 
    here => '/phys/physicians/login' 
} 
response => object(CakeResponse) { 

} 
settings => array() 

}

Antwort

19

OK ich habe einen Weg, es zu tun. Sie kennen das Präfix-Routing? Wenn nicht, lesen Sie meine Antwort hier: CakePHP/MVC Admin functions placement Diese Antwort beschreibt, wie Sie ein einzelnes Routing-Präfix ('admin') einrichten. Aber Sie können eine beliebige Anzahl haben - wie folgt aus:

Configure::write('Routing.prefixes', array('admin','phys','member','user')); 
// now we have admin, phys, member and user prefix routing enabled. 

Was können Sie tun, ist haben die alle Arzt Methoden ‚admin‘ Präfix-Routing, und alle Ärzte Methoden ‚phys‘ Präfix-Routing.

Also unten ist der Code, den ich ziemlich schnell gehackt habe, also könnte es nicht perfekt sein, aber es sollte das Konzept zeigen.Hier ist es in Pseudo-Code für die vor-Filter-Methode des App Controller:

if (USER IS TRYING TO ACCESS AN ADMIN PREFIXED METHOD) { 
    Then use the users table for auth stuff 
} else if (USER IS TRYING TO ACCESS A PHYS PREFIXED METHOD) { 
    Then use the physicians table for auth stuff 
} else { 
    It's neither an admin method, not a physicians method. So just always allow access. Or always deny access - depending on your site 
} 

Hier ist mein App Controller-Code:

App::uses('Controller', 'Controller'); 

class AppController extends Controller { 

    public $components = array('Security','Cookie','Session','Auth','RequestHandler'); 
    public $helpers = array('Cache','Html','Session','Form'); 

    function beforeFilter() { 

     if ($this->request->prefix == 'admin') { 
      $this->layout = 'admin'; 
      // Specify which controller/action handles logging in: 
      AuthComponent::$sessionKey = 'Auth.Admin'; // solution from https://stackoverflow.com/questions/10538159/cakephp-auth-component-with-two-models-session 
      $this->Auth->loginAction = array('controller'=>'administrators','action'=>'login'); 
      $this->Auth->loginRedirect = array('controller'=>'some_other_controller','action'=>'index'); 
      $this->Auth->logoutRedirect = array('controller'=>'administrators','action'=>'login'); 
      $this->Auth->authenticate = array(
       'Form' => array(
        'userModel' => 'User', 
       ) 
      ); 
      $this->Auth->allow('login'); 

     } else if ($this->request->prefix == 'phys') { 
      // Specify which controller/action handles logging in: 
      AuthComponent::$sessionKey = 'Auth.Phys'; // solution from https://stackoverflow.com/questions/10538159/cakephp-auth-component-with-two-models-session 
      $this->Auth->loginAction = array('controller'=>'users','action'=>'login'); 
      $this->Auth->logoutRedirect = '/'; 

      $this->Auth->authenticate = array(
       'Form' => array(
        'userModel' => 'Physician', 
       ) 
      ); 
     } else { 
      // If we get here, it is neither a 'phys' prefixed method, not an 'admin' prefixed method. 
      // So, just allow access to everyone - or, alternatively, you could deny access - $this->Auth->deny(); 
      $this->Auth->allow();   
     } 
    } 

    public function isAuthorized($user){ 
     // You can have various extra checks in here, if needed. 
     // We'll just return true though. I'm pretty certain this method has to exist, even if it just returns true. 
     return true; 
    } 

} 

Beachten Sie die Zeilen:

AuthComponent::$sessionKey = 'Auth.Admin'; // solution from https://stackoverflow.com/questions/10538159/cakephp-auth-component-with-two-models-session 

und

AuthComponent::$sessionKey = 'Auth.Phys'; // solution from https://stackoverflow.com/questions/10538159/cakephp-auth-component-with-two-models-session 

Was? Das bedeutet, dass eine Person sowohl als Arzt als auch als Administrator in dem einen Browser angemeldet sein kann, ohne sich gegenseitig zu stören. Sie benötigen es möglicherweise nicht in der Live-Site, aber es ist sicherlich hilfreich beim Testen.

Nun, in Ihren jeweiligen Controllern benötigen Sie einfache Anmelde-/Abmeldeverfahren mit dem entsprechenden Präfix.

Also, für den Admin Vorfixierung, in die Benutzer-Controller:

public function admin_login() { 
    if ($this->request->is('post')) { 
     if ($this->Auth->login()) { 
      return $this->redirect($this->Auth->redirect()); 
     } else { 
      $this->Session->setFlash(__('Username or password is incorrect'), 'default', array(), 'auth'); 
     } 
    } 
} 

public function admin_logout() { 
    $this->Session->setFlash('Successfully Logged Out'); 
    $this->redirect($this->Auth->logout()); 
} 

Und in Ihrem Ärzte Controller:

public function phys_login() { 
    if ($this->request->is('post')) { 
     if ($this->Auth->login()) { 
      return $this->redirect($this->Auth->redirect()); 
     } else { 
      $this->Session->setFlash(__('Username or password is incorrect'), 'default', array(), 'auth'); 
     } 
    } 
} 

public function phys_logout() { 
    $this->Session->setFlash('Successfully Logged Out'); 
    $this->redirect($this->Auth->logout()); 
} 

Wie ich sagte, dass alle Code, den ich zusammen ziemlich schnell gehackt, so dass es möglicherweise nicht wörtlich, aber es sollte das Konzept zeigen. Lass es mich wissen, wenn du irgendwelche Fragen hast.

+0

Vielen Dank für diese - Sie schaukeln. Ich habe heute implementiert und habe keine Probleme mit dem Admin-Präfix und dem Benutzer-Controller. Der Controller des Arztes gibt mir jedoch immer noch den Fehler "Sie sind nicht autorisiert". Also hat sich praktisch nichts geändert. Ich werde den Debug-Code oben veröffentlichen, wenn das hilft. – deewilcox

+0

So erhalten Sie "Ungültiger Benutzername oder Passwort, versuchen Sie es erneut" oder erhalten Sie das überhaupt nicht und bekommen nur "Sie sind nicht berechtigt, auf diesen Ort zuzugreifen."? Das heißt, ist Ihr "if ($ this-> Auth-> login()) {" bestanden, und dann bekommen Sie nur ein Problem bei der Post-Login-Umleitung? Oder versagt diese Linie? –

+0

Ich bekomme den Fehler "Sie sind nicht autorisiert". Wenn ich '($ this-> request-> data)' in übergebe, funktioniert es. Ich habe einen ungültigen Benutzernamen und ein ungültiges Passwort mit '$ this-> Auth-> login ($ this-> request-> data);' getestet und die Anmeldung schlägt fehl (wie es sollte), wenn der Benutzername oder das Passwort falsch sind. – deewilcox

0

Statt

$this->Session->write('Auth.redirect','/physicians/index'); 

sollten Sie

setcookie("keys", value);