Api e Auth dipendenza circolare strettamente accoppiata

0

Sto programmando un'applicazione e sto riscontrando problemi nel trovare una buona architettura per alcuni dei suoi componenti.

Come parte dell'app per front-end, ho un sistema di autenticazione utente e un'API che consente agli utenti di eseguire determinate azioni su un server.

Ho creato i seguenti componenti: (Questo è in javascript, ma immagino che l'architettura non sia molto specifica per la lingua)

Un componente che gestisce l'autenticazione con stato (gestisce chi ha effettuato l'accesso e gestisce la memorizzazione e la memorizzazione nella cache dei relativi authtokens)

const Auth = {
    logout() { ... }
    login() { ... }
    isLoggedIn() { ... }
    getUsername() { ... }   
}

E un componente che gestisce le chiamate API.

const API = {
    updateUserSettings() { ... }
    getPublicNotifications() { ... }
    sendEmail() { ... }
}

Il problema è che queste due componenti sono strettamente accoppiate e hanno una dipendenza circolare. Vedete, perché Auth effettui il login, deve usare l'API per fare una richiesta al server.

const Auth = {
    login(email, password) {
        ...
        this.authToken = API.getAuthToken(email, password);
        ...
    }
}

Ma per alcune richieste API (non tutte), l'oggetto API deve recuperare i dati di autenticazione:

const API = {
    updateUserSettings(settings) {
        ...
        this.request({ ...settings, authToken: Auth.getAuthToken() });
        ...
    }
}

Non riesco nemmeno a separare questi due componenti distinti nei propri file, poiché quando si importano a vicenda provocano un ciclo infinito a causa della loro relazione circolare.

Come posso affrontare meglio questo problema? Ho pensato di creare un terzo oggetto che avvolge entrambi, ma ho paura di costruire un superoggetto responsabile di troppe cose. Ci sono parte del programma che interagiscono solo con Auth o solo con l'API, rendendo la loro separazione intuitiva.

Ho anche considerato di suddividere l'API nelle parti che toccano la procedura di autenticazione iniziale e i metodi che già presuppongono l'autenticazione. Ma questi due condividono molto in comune, quindi rompere le API sembra un approccio imperfetto. (Ma forse mi sbaglio nel pensarlo così)

Qualsiasi aiuto o idea sarebbe molto apprezzato. Come gestiresti questo?

    
posta curious-cat 06.09.2017 - 00:47
fonte

1 risposta

1

Ci sono due modi principali che mi piacciono per gestirlo su un'applicazione javascript singola e / o un'applicazione mobile.

  • Autenticazione di base Autentica ogni richiesta con le credenziali dell'utente e quindi non è necessario un accesso esplicito. Tutte le richieste devono essere crittografate con HTTP per mantenere sicure le credenziali.

In un'applicazione a singola pagina, che cos'è l'accesso? È davvero la tua applicazione che pensa di avere credenziali di autenticazione valide. Quindi, quando l'utente prova ad accedere, puoi simularlo chiamando qualcosa come getUsername o qualcosa di simile con credenziali che ritieni siano corrette. Un buon effetto collaterale di questo è che non è necessario chiamare sia Login che amp; qualche altra richiesta se il login funziona, puoi saltare direttamente a chiedere i dati che desideri.

In pratica sarebbe una singola API e quindi è facile da implementare.

const UserApi = {
    checkLogin() { ... }
    getUsername() { ... }   
    updateUserSettings() { ... }
    getPublicNotifications() { ... }
    sendEmail() { ... }
}

Questo non suona come quello che vuoi, e dal punto di vista della sicurezza, non è preferito in quanto devi tenere a portata di mano le credenziali reali dell'utente (o le credenziali con hash) per qualsiasi momento tu voglia fare una richiesta.

  • Autenticazione basata su token Fondamentalmente solo un'area separata della tua applicazione solo per il recupero di un token. Una volta che hai quel token lo usi ovunque per tutte le richieste che richiedono l'autenticazione. Esistono diversi schemi per l'autenticazione basata su token.

Potrebbe finire qualcosa di simile

const TokenApi = {
    getToken() { ... }
    deleteToken() { ... }
}

const UserApi = {
    updateUserSettings(settings) {
        ...
        this.request({ ...settings, authToken: Auth.getAuthToken() });
        ...
    }
    getPublicNotifications() { ... }
    sendEmail() { ... }
    getUsername() { ... }
    logout() { ... Auth.deleteToken() }
}

Alcuni vantaggi dell'uso di token: link

Ci sono molti modi per fare l'autenticazione basata su token. Il più semplice è solo per mantenere una stringa casuale, forse un hash, qualcosa di unico per l'utente che l'utente non ha fornito nel database che rappresenta l'utente. Questo ha alcuni svantaggi soprattutto se non cambia mai, ma anche questo è un enorme passo avanti dal riutilizzo della password dell'utente.

Un esempio di best practice convenzionale di autenticazione basata su token è OAuth 2.

In generale, quando costruisci una nuova applicazione penso che OAuth 2 sia un po 'troppo voluminoso da includere all'inizio. Inoltre, a patto di separare le preoccupazioni di autenticazione dal resto della tua applicazione, non avrai problemi a tornare indietro e sostituire un token zoppo o l'autenticazione di base con qualcosa di più sicuro in poche settimane. Non è quasi mai la prima cosa che costruisco.

Ci sono altri concetti che potresti voler conoscere anche tu. Questi approfittano di alcuni browser e amp; caratteristiche del server.

  • ID sessione. L'esempio più comune di ciò che so è PHP Sessions.
  • Cookie
  • E ... ancora di più: accessi federati, single sign-on, NTLM, Kerberos.
risposta data 06.09.2017 - 02:27
fonte