2012-10-31 16 views
12

W maju opublikowałem this question. Próbuję zrobić to samo ponownie w innej aplikacji, ale nie znalazłem rozwiązania tego problemu. Mam więcej informacji i lepszy kod, więc mam nadzieję, że pomożesz mi to rozwiązać.CakePHP 2.x Auth z dwoma oddzielnymi logami

Przypadek użycia: Klinika ma stronę z administratorami. Użytkownicy logują się z użyciem Auth CakePHP poprzez model User i UsersController.

Lekarze mają lekarzy kierujących o zupełnie różnych profilach i działaniach. Lekarze muszą zalogować się przez example.com/physicians/login. Jednak to logowanie się niepowodzeniem z tym

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

Oto mój kod w 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'); 
} 

}

A oto mój UsersController że pracuje:

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()); 
} 

Oto mójKodże nie działa:

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()); 
} 

ja naprawdę nie chce zacząć od nowa i przełączyć się na ACL - Nie jestem pewien, że jest to konieczne dla zaledwie dwóch loginów. Pomoc byłaby bardzo ceniona!

EDYCJA: Odpowiedź Joshua poniżej jest niesamowita i bardzo pomocna. Zaimplementowałem go, ale wciąż otrzymuję nieautoryzowany błąd, gdy próbuję zalogować się jako lekarz przez/phys/physican/login (prefiks/kontroler/akcja). Konfiguracja administratora działa świetnie. Oto kod debugowania, gdy próbuję się zalogować:

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() 

}

Odpowiedz

19

OK Mam sposób to zrobić. Wiesz o routingu prefiksów? Jeśli nie, przeczytaj moją odpowiedź tutaj: CakePHP/MVC Admin functions placement Ta odpowiedź opisuje, jak skonfigurować pojedynczy przedrostek routingu ("admin"). Ale można mieć dowolną liczbę - po prostu tak:

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

Co można zrobić, to mieć wszystkie metody lekarz używają „admin” routing prefiksu i metody wszyscy lekarze używać prefiksu routing 'Phys.

Poniżej znajduje się kod, który zhakowałem dość szybko, więc może nie być idealny, ale powinien pokazać koncepcję.Oto ona w pseudo kod do wcześniej metody filtra kontrolerze aplikacji:

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 
} 

Oto mój kod app kontroler:

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; 
    } 

} 

Uwaga linie:

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

i

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

Co Dzięki temu osoba może być zalogowana zarówno jako lekarz, jak i administrator w jednej przeglądarce, bez ingerencji w swoją sesję. Możesz go nie potrzebować w witrynie na żywo, ale jest to z pewnością przydatne podczas testów.

Teraz, w odpowiednich kontrolerach, będziesz potrzebował prostych metod logowania/wylogowywania z odpowiednim prefiksem.

Tak więc dla administratora wstępnym dopasowywaniu w kontrolerze użytkowników:

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()); 
} 

A w kontrolerze lekarzy:

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()); 
} 

Jak powiedziałem, że cały kod I hacked razem dość szybko, więc może nie działać dosłownie, ale powinien pokazać koncepcję. Daj mi znać, jeśli masz jakieś pytania.

+0

Dzięki tak dużo za to - ty kołysać. Zaimplementowałem dzisiaj i nie mam żadnych problemów z prefiksem administratora i kontrolerem użytkowników. Jednak kontroler lekarza nadal daje mi ten sam błąd "Nie masz autoryzacji". Więc praktycznie nic się nie zmieniło. Wezwę powyższy kod debugowania, jeśli to pomoże. – deewilcox

+0

Czy otrzymujesz komunikat "Nieprawidłowa nazwa użytkownika lub hasło, spróbuj ponownie" lub w ogóle go nie otrzymujesz i otrzymujesz komunikat "Nie masz uprawnień dostępu do tej lokalizacji"? To znaczy, czy twoje "if ($ this-> Auth-> login()) {" przekazuje, a wtedy pojawia się tylko problem z przekierowaniem po zalogowaniu? A może linia ta zawodzi? –

+0

Pojawia się błąd "Nie masz autoryzacji". Jeśli przekazuję '($ this-> request-> data)' in, to działa. Przetestowałem używając nieprawidłowej nazwy użytkownika i hasła z '$ this-> Auth-> login ($ this-> request-> data);', a logowanie nie powiedzie się (tak jak powinno), jeśli nazwa użytkownika lub hasło są błędne. – deewilcox

0

Zamiast

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

należy użyć

setcookie("keys", value); 
Powiązane problemy