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?
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.
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);
});
};
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)
})
}
)
)
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!
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.
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
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
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.
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);
});
});
}));
}
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
}
}
})