web-dev-qa-db-de.com

Facebook-Pass mit JWT

Ich habe Passport auf meinem Server zur Benutzerauthentifizierung verwendet. Wenn sich ein Benutzer lokal anmeldet (mit einem Benutzernamen und einem Kennwort), sendet der Server ihmJWT, das in localstorage gespeichert ist und bei jedem API-Aufruf an den Server zurückgesendet wird das erfordert eine Benutzerauthentifizierung.

Nun möchte ich Facebook und Google login ebenso unterstützen. Seit ich mit Passport angefangen habe, dachte ich, es wäre am besten, mit Passport-Strategien fortzufahren, indem ich passport-facebook und passport-google-oauth verwende.

Ich beziehe mich auf Facebook, aber beide Strategien verhalten sich gleich. Beide erfordern eine Umleitung zu einer Server-Route ( '/ auth/facebook' und '/ auth/facebook/callback' ). Der Vorgang ist erfolgreich, sodass Benutzer einschließlich ihrer Facebook\google-IDs und -Token in der Datenbank gespeichert werden.

Wenn der Benutzer auf dem Server erstellt wird, wird eine JWT erstellt (ohne sich auf das von facebook\google erhaltene Token zu verlassen). 

     ... // Passport facebook startegy
     var newUser = new User();
     newUser.facebook = {};
     newUser.facebook.id = profile.id; 
     newUser.facebook.token = token; // token received from facebook
     newUser.facebook.name  = profile.displayName;   
     newUser.save(function(err) {
          if (err)
               throw err;
          // if successful, return the new user
          newUser.jwtoken = newUser.generateJwt(); // JWT CREATION!
          return done(null, newUser);
     });

Das Problem ist, dass nach der Erstellung kein geeigneter Weg gefunden wird, um die JWT an den Client zu senden , da ich auch zu meiner App umleiten sollte.

app.get('/auth/facebook/callback',
    passport.authenticate('facebook', {
        session: false,
        successRedirect : '/',
        failureRedirect : '/'
    }), (req, res) => {
        var token = req.user.jwtoken;
        res.json({token: token});
    });

Der obige Code leitet mich auf die Hauptseite meiner App um, aber ich bekomme das Token nicht . Wenn ich die successRedirect entferne, bekomme ich das Token, aber ich bin es nicht an meine App weitergeleitet .

Irgendwelche Lösung dafür? Ist mein Ansatz falsch? Irgendwelche Vorschläge werden ausreichen. 

16
Bar Kedem

Die beste Lösung, die ich für dieses Problem gefunden habe, wäre, auf die erwartete Seite mit einem Cookie umzuleiten, das die JWT enthält.

Die Verwendung von res.json würde nur eine Json-Antwort senden und nicht umleiten. Deshalb würde die andere vorgeschlagene Antwort das Problem, auf das ich gestoßen bin, nicht lösen.

Meine Lösung wäre also:

app.get('/auth/facebook/callback',
passport.authenticate('facebook', {
    session: false,
    successRedirect : '/',
    failureRedirect : '/'
}), (req, res) => {
    var token = req.user.jwtoken;
    res.cookie('auth', token); // Choose whatever name you'd like for that cookie, 
    res.redirect('http://localhost:3000'); // OR whatever page you want to redirect to with that cookie
});

Nach der Umleitung können Sie das Cookie sicher lesen und diese JWT wie erwartet verwenden. (Sie können das Cookie tatsächlich bei jedem Laden einer Seite lesen, um zu überprüfen, ob ein Benutzer angemeldet ist.)

Wie ich bereits erwähnt habe, ist es möglich, mit dem JWT als Abfrageparameter umzuleiten, aber es ist sehr unsicher. Die Verwendung eines Cookies ist sicherer, und es gibt immer noch Sicherheitslösungen, mit denen Sie ihn im Gegensatz zu noch sicherer machen können ein Abfrageparameter, der eindeutig unsicher ist.

8
Bar Kedem

Hinzufügen zu Bar's Antwort.

Ich habe eine Landekomponente vorbereitet, um das Cookie zu extrahieren, im lokalen Speicher zu speichern, das Cookie zu löschen und dann auf eine autorisierte Seite umzuleiten.

class SocialAuthRedirect extends Component {
  componentWillMount() {
    this.props.dispatch(
      fbAuthUser(getCookie("auth"), () => {
        document.cookie =
          "auth=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
        this.props.history.Push("/profile");
      })
    );
  }

  render() {
    return <div />;
  }
}
3
Tetsuya3850

Eine geeignete Lösung wäre die Implementierung der Umleitung auf der Clientseite.

Verwenden Sie einfach:

app.get('/auth/facebook/callback',
  passport.authenticate('facebook', {
    session: false,
    failureRedirect: '/login'
  }), (req, res) => {
    res.json({
      token: req.user.jwtoken
    })
  }
)

Wenn Sie clientseitig das Token erhalten, dann von dort zur Startseite umleiten, und falls die Anmeldung nicht erfolgreich war, wird sie vom Server direkt umgeleitet.

Oder Sie können sich für die vollständige Verwaltung auf Kundenseite entscheiden, wie ich es tun würde:

app.get('/auth/facebook/callback',
  passport.authenticate('facebook', {
    session: false
  }), (req, res) => {
    if (req.user.jwtoken) {
      res.json({
        success: true,
        token: req.user.jwtoken
      })
    } else {
      res.json({
        success: false
      })
    }
  }
)

Wenn success === true, JWT in LocalStorage speichern, ansonsten auf die Anmeldeseite umleiten.

1
SherloxFR