web-dev-qa-db-de.com

Reisepass: Erlauben Sie die Anmeldung mit Name und E-Mail-Adresse? (Lokale Strategie)

Gibt es eine Möglichkeit, dass sich ein Benutzer mit seinem Passwort, seiner E-Mail-Adresse und seinem Namen bei der lokalen Strategie registrieren kann?
Jedes Beispiel, das ich online finden konnte, verwende nur Name/Passwort oder E-Mail/Passwort. 

Ich habe auch die gesamte Passdokumentation durchsucht, aber diese Dokumentation ist überhaupt nicht hilfreich. Es ist nur eine aufgeblähte Seite voller Beispiele.
Ich brauche nur eine Liste von Funktionen, Klassen und Variablen, die der Passport verwendet, mit Erklärungen, was sie und ihre Parameter tun. Jede gute Bibliothek hat so etwas, warum kann ich sie nicht für den Pass finden?

Hier sind die wichtigsten Teile meines Codes:

passport.use('local-signup', new LocalStrategy({
    usernameField: 'email',
    passwordField: 'password',
    //are there other options?
    //emailField did not seem to do anything
    passReqToCallback: true // allows us to pass in the req from our route (lets us check if a user is logged in or not)
},
function(req, email, password, done) {
    //check if email not already in database
        //create new user using "email" and "password"
        //I want an additional parameter here "name"
}));

Ist der Pass wirklich so begrenzt? Es muss einen Weg geben, dies zu tun, richtig?

12
Forivin

Sie können etwas verwirrt sein, aber Passport implementiert keine Anmeldemethoden. Es ist nur eine Berechtigungsbibliothek. Sie müssen also diesen Use-Case selbst behandeln.

Erstellen Sie zunächst eine Route, die für die Anmeldung und Ihre Überprüfungen verantwortlich ist:

signup: function (req, res) {
  User
    .findOne({
      or: [{username: req.param('username')}, {email: req.param('email')}]
    })
    .then(function(user) {
      if (user) return {message: 'User already exists'};          
      return User.create(req.allParams());
    })
    .then(res.ok)
    .catch(res.negotiate);
}

Das obige Beispiel basiert auf dem Sails-Framework, Sie können es jedoch problemlos an Ihren eigenen Fall anpassen.

Der nächste Schritt ist die lokale Passportstrategie.

var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;

var LOCAL_STRATEGY_CONFIG = {
  usernameField: 'email',
  passwordField: 'password',
  session: false,
  passReqToCallback: true
};

function _onLocalStrategyAuth(req, email, password, next) {
  User
    .findOne(or: [{email: email}, {username: email}])
    .then(function (user) {
      if (!user) return next(null, null, {
        code: 'E_USER_NOT_FOUND',
        message: email + ' is not found',
        status: 401
      });

      if (!HashService.bcrypt.compareSync(password, user.password)) return next(null, null, {
        code: 'E_WRONG_PASSWORD',
        message: 'Password is wrong',
        status: 401
      });

      return next(null, user, {});
    })
    .catch(next);
}

passport.use(new LocalStrategy(LOCAL_STRATEGY_CONFIG), _onLocalStrategyAuth));

Wir haben jetzt nur eine Anmeldeaufgabe. Es ist einfach.

signin: function(req, res) {
  passport.authenticate('local', function(error, user, info) {
    if (error || !user) return res.negotiate(Object.assign(error, info));
    return res.ok(user);
  })(req, res);
}

Dieser Weg eignet sich eher für Pass und funktioniert für mich.

19
ghaiklor

Hier ist das, was für mich funktioniert hat, die Lösung basiert auf einem auf Mongoose basierenden Odm. Der erste Teil ist der Pass-bezogene Teil. Ich habe auch den Benutzerteil von Odm angehängt, wer die Verschlüsselung des Passworts vornimmt.

Wenn ich Ihre Frage verstanden habe, soll der Benutzer entweder seine E-Mail-Adresse oder sein Kennwort eingeben. Ändern Sie in diesem Fall die Suche so, dass beide versucht werden, d. H. Die angegebene Benutzerkennung (in Ihrem Aufruf an findOne (...) entweder mit dem Benutzernamen oder dem Kennwort übereinstimmt.

Beachten Sie, dass ich bcrypt verwende, um zu vermeiden, dass eindeutige Kennwörter gespeichert werden. Aus diesem Grund gibt es eine angepasste Vergleichsmethode zum Testen von Kennwörtern. Beachten Sie auch die 'Hinweise' zur Verwendung von google auth. Mein System hat beide aktiviert. Wenn es relevant ist, bitte lemme wissen und ich kann den erforderlichen Code hinzufügen.

------------ Auth-Part (nur relevante Ausschnitte) -----------

var passport = require('passport'),
LocalStrategy = require('passport-local').Strategy;

passport.serializeUser(function(user, done) {
    // the values returned here will be used to deserializeUser
    // this can be use for further logins
    done(null, {username: user.username, _id: user.id, role: user.role});
});

passport.deserializeUser(function(user, done) {
    done(null, user);
});


passport.use(new LocalStrategy(function(username, password, done){
    odm.User.findOne({username: username, authType: 'direct'}, function(err, user){
        if(err){
            return done(err, false);
        }
        if(!user){
            return done(null, false);
        }
        if(user.role === 'new'){
            console.log('can not use new user!');
            return done('user not activated yet, please contact admin', false);
        }
        user.comparePassword(password,function(err, isMatch){
            if(err){
                return done(err, false);
            }
            if(isMatch){
                return done(null, user);//{username: username});
            }
            return done(null, false);
        });
    });
}));
app.post('/login',  function(req, res, next){
        passport.authenticate('local', {
            failureRedirect: '/logout?status=login failed'
        }, function(err, user, info){
                if(err){
                    return next(err);
                }
                if(!user){
                    return res.redirect('/login');
                }
                req.logIn(user, function(err){
                    if (req.body.rememberme) {
                        req.session.cookie.maxAge = 30*24*60*60*1000 ;//Rememeber 'me' for 30 days
                    } else {
                        req.session.cookie.expires = false;
                    }
                    var redirect = req.param('redirect') || '/index';
                    res.redirect(redirect);
                });
            }
        )(req, res, next);
    }
);

app.post('/register',function(req, res){
    var user = new odm.User({username: req.body.username, password: req.body.password, email: req.body.email, authType: 'direct'});
    user.save(function(err, user){
        if(err){
            console.log('registration err: ' , err);
        } else {
            res.redirect('/list');
        }
    });
});

--- Benutzer/Odm, relevante Teile ----------------

var bcrypt = require('bcrypt-nodejs');

// --------------------- User ------------------------------------------ //
var userSchema = new Schema({
    name: String,
    email: String,
    username: {type: String, required: true, unique: true},
    password: String,
    role: {type: String, required: true, enum: ['new', 'admin', 'user'], default: 'new'},
    authType: {type: String, enum: ['google', 'direct'], required: true}
});

userSchema.pre('save', function (next) {
    var user = this;
    if (!user.isModified('password')) return next();

    console.log('making hash...........');
    bcrypt.genSalt(SALT_WORK_FACTOR, function (err, salt) {
        if (err) return next(err);

        bcrypt.hash(user.password, salt, null, function (err, hash) {
            if (err) return next(err);
            user.password = hash;
            next();
        });
    });
});

userSchema.methods.comparePassword = function (candidatePassword, cb) {
    bcrypt.compare(candidatePassword, this.password, function (err, isMatch) {
        if (err) return cb(err);
        cb(null, isMatch);
    });
};
4
Meir

Sagen Sie, Sie haben das

app.post('/login', urlencodedParser,
    // so, user has been to /loginpage and clicked submit.
    // /loginpage has a post form that goes to "/login".
    // hence you arrive here.
    passport.authenticate('my-simple-login-strategy', {
        failureRedirect: '/loginagain'
    }),
        function(req, res) {
            console.log("you are in ............")
            res.redirect('/stuff');
    });

Beachten Sie, dass .authenticate Ein explizites Tag hat.

Die Tags sind 'my-simple-login-strategy'

Das heißt, Sie haben diese ...

passport.use(
    'my-simple-login-strategy',
    // !!!!!!!!!!!!!note!!!!!!!!!!, the DEFAULT there (if you have nothing)
    // is 'local'. A good example of defaults being silly :/
    new Strategy(
        STRAT_CONFIG,
        function(email, password, cb) {
           // must return cb(null, false) or cb(null, the_user_struct) or cb(err)
           db.findUserByEmailPass(email, password, function(err, userFoundByDB) {
                if (err) { return cb(err); }
                if (!userFoundByDB) { return cb(null, false); }
                console.log('... ' + JSON.stringify(userFoundByDB) )
                return cb(null, userFoundByDB)
           })
        }
    )
)

!!! !!! BEACHTEN SIE, DASS 'local' IS JUST THE DEFAULT TAG NAME !!! !!!

In passport.use Wird immer ein explizites Tag eingefügt. Es ist viel klarer, wenn Sie dies tun. Fügen Sie ein explizites Tag in die Strategie und in den app.post Ein, wenn Sie die Strategie verwenden.

Das ist also meine-einfache-Login-Strategie.

Was ist die tatsächliche db.findUserByEmailPass SQL-Funktion?

Wir werden darauf zurückkommen!

Also haben wir meine-simple-Login-Strategie

Weiter ...... wir brauchen meine-simple-createaccount-Strategie

Beachten Sie, dass wir immer noch passport.authenticate verwenden:

Damit:

die Strategie my-simple-createaccount-strategy wird tatsächlich einen Account erstellen.

Jedoch .............

du solltest trotzdem eine struct. zurückgeben

Beachten Sie, dass my-simple-login-strategy eine Struktur zurückgeben muss.

My-simple-createaccount-strategy muss also auch eine Struktur zurückgeben - genauso.

app.post('/createaccount', urlencodedParser,
    // so, user has been to /createanaccountform and clicked submit,
    // that sends a post to /createaccount. So we are here:
    passport.authenticate('my-simple-createaccount-strategy', {
        failureRedirect: '/loginagain'
    }),
        function(req, res) {
            console.log("you are in ............")
            res.redirect('/stuff');
    });

Und hier ist die Strategie ..........

passport.use(
    'my-simple-createaccount-strategy',
    new Strategy(
        STRAT_CONFIG,
        function(email, password, cb) {
            // return cb(null, false), or cb(null, the_user_struct) or cb(err)
            db.simpleCreate(email, password, function(err, trueOrFalse) {
                if (err) { return cb(err); }
                if (!trueOrFalse) { return cb(null, false); }
                return cb(null, trueOrFalse)
            })
        }
    )
)

Die Strategie ist ziemlich ähnlich. Aber der DB-Aufruf ist anders.

Schauen wir uns jetzt die db calls an.

Schauen wir uns die db calls an!

Der normale DB-Aufruf für die normale Strategie sieht folgendermaßen aus:

exports.findUserByEmailPass = function(email, password, cb) {
    // return the struct or false via the callback
    dc.query(
        'select * from users where email = ? and password = ?',
        [email, password],
        (error, users, fields) => {
            if (error) { throw error } // or something like cb(new Error('blah'));
            cb(null, (users.length == 1) ? users[0] : false)
        })
}

Das ist also exports.findUserByEmailPass, das von my-simple-login-strategy verwendet wird.

Aber was ist mit exports.simpleCreate für meine-simple-createaccount-Strategie?

Eine einfache Spielzeugversion wäre

  1. überprüfen Sie, ob der Benutzername bereits vorhanden ist. Geben Sie an dieser Stelle false zurück, falls er bereits vorhanden ist
  2. erstelle es und dann
  3. eigentlich nur die aufzeichnung nochmal zurückgeben.

Erinnern Sie sich daran, dass (3) genau wie beim normalen "find" -Aufruf ist.

Denken Sie daran, dass ... die Strategie my-simple-createaccount-strategy tatsächlich zu einem Account macht. Aber Sie sollten immer noch eine Struktur auf die gleiche Weise zurückgeben wie Ihre gewöhnliche Authentifizierungsstrategie, my-simple-login-strategy.

Exports.simpleCreate ist also eine einfache Kette von drei Aufrufen:

exports.simpleCreate = function(email, password, cb) {
    // check if exists; insert; re-select and return it
    dc.query(
        'select * from users where email = ?', [email],
        (error, users, fields) => {
            if (error) { throw error } // or something like cb(new Error('blah'));
            if (users.length > 0) {
                return cb(null, false)
            }  
            else {
                return partTwo(email, password, cb)
            }
        })
}

partTwo = function(email, password, cb) {
    dc.query(
        'insert into users (email, password) values (?, ?)', [email, password],
        (error, users, fields) => {
            if (error) { throw error } // or something like cb(new Error('blah'));
            partThree(email, password, cb)
        })
}

partThree = function(email, password, cb) {
    dc.query(
        'select * from users where email = ? and password = ?', [email, password],
        (error, users, fields) => {
            if (error) { throw error } // or something like cb(new Error('blah'));
            cb(null, (users.length == 1) ? users[0] : false)
        })
}

Und das alles funktioniert.

Aber beachte das

reisepass hat nichts mit Kontoerstellung zu tun !

Tatsächlich müssen Sie überhaupt keine Strategie anwenden.

In app.post('/createaccount' Können Sie, wenn Sie möchten, nichts mit passport.authenticate Tun ... erwähnen Sie es nicht einmal im Code. Verwenden Sie überhaupt nicht authentifizieren. Führen Sie einfach den SQL-Prozess zum Einfügen eines neuen Benutzers in app.post aus.

Wenn Sie jedoch eine Passstrategie "knifflig" anwenden - im Beispiel "my-simple-createaccount-strategy" -, haben Sie den Vorteil, dass der Benutzer sofort mit einer Sitzung angemeldet wird und alles nach dem Muster des Anmeldeposts funktioniert . Cool.

4
Fattie
var localStrategy = require('passport-local').Strategy;
var User = require('../public/models/user');

module.exports = function(passport){

    passport.serializeUser(function(user, done){
        done(null, user.id);
    });

    passport.deserializeUser(function(id, done){
        User.findById(id, function(err, user){
            done(err, user);
        });
    });

    passport.use('local-signup', new localStrategy({
        usernameField: 'email',
        passwordField: 'password',
        passReqToCallback: true
    },
    function(req, email, password, done){
        process.nextTick(function(){
             User.findOne({'local.enroll': email}, function(err, user){
                 if(err)
                     return done(err);
                 if(user){
                     return done(null, false, req.flash('signupmessage', 'The email already taken'));
                 } else{
                     var newUser = new User();
                     newUser.local.enroll = email;
                     newUser.local.password = newUser.generateHash(password);                     
                     newUser.save(function(err){
                         if(err)
                             throw err
                         return done(null, newUser);
                     });
                 }

             });
        });
    }));

    passport.use('local-login', new localStrategy({
        usernameField: 'email',
        passwordField: 'password',
        passReqToCallback: true
    },
    function(req, email, password, done){
        process.nextTick(function(){
             User.findOne({'local.enroll': email}, function(err, user){
                 if(err)
                     return done(err);
                 if(!user){
                     return done(null, false, req.flash('loginmessage', 'No user found'));
                 }
                 if(!user.validPassword(password)){
                     return done(null, false, req.flash('loginmessage', 'Invalid password'));
                 }
                 return done(null, user);
             });
        });
    }));    
}
1
Mohammad Amir

Das hat eigentlich nichts mit passport zu tun und ist ziemlich einfach, vorausgesetzt, Sie verwenden body-parser. Stellen Sie sicher, dass Sie in Ihrem Formular einen input field mit dem Attribut name="name" haben, in dem Sie den Namen des Benutzers wie folgt registrieren:

<div class="form-group">
    <label for="signup-name">Name</label>
    <input type="text" placeholder="Name" name="name">
</div> 

In Ihrem Arbeitsplan können Sie mit req.body.name auf dieses Feld zugreifen:

passport.use('local-signup', new LocalStrategy({
    usernameField: 'email',
    passwordField: 'password',
    //are there other options?
    //emailField did not seem to do anything
    passReqToCallback: true
},
function(req, email, password, done) {
    //check if email not already in database
    //create new user using "email" and "password"
    //I want an additional parameter here "name"

    user.email = email;
    user.password = password; // Do some hashing before storing

    user.name = req.body.name;

}));

Sie können also beliebig viele Formulareingabefelder hinzufügen und über den Wert des Namensattributs darauf zugreifen. Ein zweites Beispiel wäre:

<input type="text" placeholder="City" name="city">
<input type="text" placeholder="Country" name="country">

// Access them by
user.city = req.body.city;
user.country = req.body.country;
UserModel.find({email: req.body.email}, function(err, user){                                               
    if(err){                                                                  
       res.redirect('/your sign up page');                                                                          
    } else {                                                                  
      if(user.length > 0){                                                    
       res.redirect('/again your sign up page');                                                                      
      } else{                                                               
        //YOUR REGISTRATION CODES HERE                                                                     
       }                                                                          
    }                                                                        
})
0
Y. Alimatov