Bisher habe ich mich nur mit vom Server gerenderten Apps befasst, bei denen sich ein Benutzer über einen Benutzernamen/ein Kennwort oder einen OAuth-Anbieter (Facebook usw.) anmeldet und der Server lediglich ein Sitzungscookie setzt, während er auf die entsprechende Seite umleitet.
Jetzt versuche ich jedoch, eine App mit einem moderneren Ansatz zu erstellen, mit React auf dem Frontend und einem JSON-API-Backend. Anscheinend besteht die Standardauswahl darin, ein JSON-Web-Token für die Authentifizierung zu verwenden. Ich habe jedoch Probleme, herauszufinden, wie ich das JWT dem Client zur Verfügung stellen soll, damit es in einer Sitzung/im lokalen Speicher oder an einem anderen Ort gespeichert werden kann.
Beispiel zur besseren Veranschaulichung:
Der Benutzer klickt auf den Link (/auth/facebook
), um sich über Facebook anzumelden
Der Benutzer wird umgeleitet und erhält das Facebook-Anmeldeformular und/oder den Berechtigungsdialog (falls erforderlich).
Facebook leitet den Benutzer mit einem Autorisierungscode an /auth/facebook/callback
zurück, der Server tauscht diesen gegen ein Zugriffstoken und einige Informationen über den Benutzer aus
Der Server findet oder erstellt den Benutzer in der Datenbank unter Verwendung der Informationen und erstellt dann eine JWT, die eine relevante Teilmenge der Benutzerdaten (z. B. ID) enthält.
???
An dieser Stelle möchte ich nur, dass der Benutzer mit dem JWT im Schlepptau zur Hauptseite für die React-App (sagen wir /app
) umgeleitet wird, damit das Frontend übernehmen kann. Aber ich kann mir keine (elegante) Möglichkeit vorstellen, dies zu tun, ohne dabei das JWT zu verlieren, außer es in die Abfragezeichenfolge für die Umleitung (/app?authtoken=...
) einzufügen - aber das wird in der Adressleiste angezeigt, bis ich es entferne es manuell mit replaceState()
oder was auch immer, und scheint mir ein bisschen komisch.
Wirklich, ich frage mich nur, wie das normalerweise gemacht wird, und ich bin mir fast sicher, dass ich hier etwas verpasse. Der Server ist Node (Koa mit Passport), wenn das hilft.
Bearbeiten: Um klar zu sein, ich frage, was der beste Weg ist, dem Client ein Token bereitzustellen (damit es gespeichert werden kann) nach einem OAuth-Redirect-Flow mit Passport.
Ich bin vor kurzem über das gleiche Problem gestoßen und habe hier und anderswo keine Lösung gefunden und schrieb diesen Blogpost mit meinen tiefgehenden Gedanken.
TL; DR: Ich habe drei mögliche Ansätze gefunden, um die JWT nach OAuth-Logins/Redirects an den Client zu senden:
<script>
-Tag zurück, das Folgendes enthält: localStorage
.(Da das Anmelden bei JWTs im Wesentlichen gleichbedeutend ist mit "Speichern der JWT in localStorage
", war meine Lieblingsoption # 3, aber möglicherweise gibt es Nachteile, die ich nicht berücksichtigt habe. Ich bin daran interessiert, was andere hier denken.)
Hoffentlich hilft das!
Client: Analysieren Sie das Token und speichern Sie es nach dem Neuladen der Seite für die spätere Verwendung im lokalen Speicher.
Ausloggen
hier ist eine Login-Anfrage von der Serverseite. Es speichert das Token im Header:
router.post('/api/users/login', function (req, res) {
var body = _.pick(req.body, 'username', 'password');
var userInfo;
models.User.authenticate(body).then(function (user) {
var token = user.generateToken('authentication');
userInfo = user;
return models.Token.create({
token: token
});
}).then(function (tokenInstance) {
res.header('Auth', tokenInstance.get('token')).json(userInfo.toPublicJSON());
}).catch(function () {
res.status(401).send();
});
});
hier ist die Anmeldeanforderung auf der Antwortseite, wo ich das Token aus dem Header abhole und das Token im lokalen Speicher einstelle, sobald der Benutzername und das Kennwort die Authentifizierung durchlaufen haben:
handleNewData (creds) {
const { authenticated } = this.state;
const loginUser = {
username: creds.username,
password: creds.password
}
fetch('/api/users/login', {
method: 'post',
body: JSON.stringify(loginUser),
headers: {
'Authorization': 'Basic'+btoa('username:password'),
'content-type': 'application/json',
'accept': 'application/json'
},
credentials: 'include'
}).then((response) => {
if (response.statusText === "OK"){
localStorage.setItem('token', response.headers.get('Auth'));
browserHistory.Push('route');
response.json();
} else {
alert ('Incorrect Login Credentials');
}
})
}