web-dev-qa-db-ja.com

パスポート:名前とメールアドレスでのサインアップを許可しますか? (地域戦略)

ユーザーが自分のパスワード、電子メール、名前を使用してローカル戦略に登録できるようにする方法はありますか?
オンラインで見つけることができるすべての例では、名前/パスワードまたは電子メール/パスワードのみを使用しています。

また、パスポートのドキュメント全体を検索しましたが、そのドキュメントはまったく役に立ちません。これは、例が豊富な肥大したサイトの1つにすぎません。
私は、パスポートが使用する関数、クラス、変数のリストと、それらとそれらのすべてのパラメーターが何をするのかについての説明が必要です。すべての優れたライブラリにはそのようなものが含まれていますが、なぜパスポート用に見つけられないのですか?

これが私のコードの重要な部分です:

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"
}));

パスポートは本当に制限されているのですか?これを行う方法が必要ですよね?

17
Forivin

少し混乱するかもしれませんが、パスポートはサインアップメソッドを実装していません。それは単なる認可ライブラリです。したがって、そのユースケースは自分で処理する必要があります。

まず、サインアップとチェックを担当するルートを作成します。

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);
}

上記の例はSailsフレームワークに基づいていますが、自分のケースに問題なく適合させることができます。

次のステップは、パスポートのローカル戦略を含めることです。

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));

現在サインインタスクがあります。それは簡単です。

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);
}

この方法はパスポートにより適しており、私にとってはうまくいきます。

23
ghaiklor

これは私のために働いたものです、解決策はマングースベースのodmに基づいています、最初の部分はパスポート関連の部分です、そしてodmからuserの部分も添付しました。

私があなたの質問を理解したなら、あなたはユーザーに彼の電子メールかパスワードのどちらかをタイプして欲しいです。この場合、両方を試すように検索を変更します。つまり、(findOne(...)への呼び出しで)指定されたユーザーIDをユーザー名またはパスワードのいずれかに一致させます。

明確なパスワードを保存しないようにbcryptを使用していることに注意してください。そのため、パスワードをテストするためのカスタマイズされた比較方法があります。また、Google認証を使用する「ヒント」にも注意してください。私のシステムでは両方が有効になっています。関連がある場合は、お知らせください。必要なコードを追加できます。

------------ Auth部分(該当するスニペットのみ)-----------

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');
        }
    });
});

---ユーザー/ ODM、関連パーツ----------------

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);
    });
};
5
Meir
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);
             });
        });
    }));    
}
4
Mohammad Amir

あなたはこれを持っていると言います

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');
    });

.authenticateには明示的なタグがあることに注意してください。

タグは'my-simple-login-strategy'です

つまり、これは...

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)
           })
        }
    )
)

!!! !!!その「ローカル」に注意してくださいISデフォルトのタグ名だけ!!! !!!

passport.useでは、常に明示的なタグを挿入します。そうすれば、はるかに明確になります。戦略を使用するときは、戦略とapp.postに明示的なタグを挿入します。

これがmy-simple-login-strategyです。

実際のdb.findUserByEmailPass sql functionは何ですか?

それはまた戻ってきます!

だから私たちは私のシンプルなログイン戦略を持っています

次は……my-simple-createaccount-strategyが必要です

まだこっそりpassport.authenticateを使用していることに注意してください。

そう:

my-simple-createaccount-strategyという戦略は、実際にアカウントを作成します。

しかしながら .............

まだ構造体を返す必要があります。

My-simple-login-strategyは構造体を返す必要があることに注意してください。

したがって、my-simple-createaccount-strategyも構造体を返す必要があります-まったく同じ方法で。

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');
    });

そしてここに戦略があります........

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)
            })
        }
    )
)

戦略はほとんど同じです。しかし、db呼び出しは異なります。

それでは、db呼び出しを見てみましょう。

Dbの呼び出しを見てみましょう!

通常の戦略の通常のdb呼び出しは次のようになります。

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)
        })
}

つまり、my-simple-login-strategyで使用されるexports.findUserByEmailPassです。

しかし、my-simple-createaccount-strategyのexports.simpleCreateはどうでしょうか?

単純なおもちゃバージョンは

  1. ユーザー名がすでに存在するかどうかを確認します-既に存在する場合は、この時点でfalseを返します。
  2. それを作成し、次に
  3. 実際には、レコードをもう一度返します。

(3)は通常の「検索」呼び出しと同じであることを思い出してください。

覚えておいてください...my-simple-createaccount-strategyが実際に行う戦略はmakeアカウントです。ただし、通常の認証戦略であるmy-simple-login-strategyと同様に、return構造体same wayの構造体を使用する必要があります。

したがって、exports.simpleCreateは3つの呼び出しの単純なチェーンです。

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)
        })
}

そして、それはすべてうまくいきます。

ただし、

パスポートにはアカウントの作成で何もする必要がありません

実際、戦略を使用する必要はまったくありません。

app.post('/createaccount'では、必要に応じてpassport.authenticateを使用して何もすることはできません...コードでそれを言及することすらありません。認証を使用しないでください。先に進んで、SQLユーザーがapp.postに新しいユーザーを挿入するプロセスを実行してください。

ただし、パスポート戦略(例ではmy-simple-createaccount-strategy)を「トリッキー」に使用すると、ユーザーはすぐにセッションでログインし、すべてがログインポストと同じパターンで機能するというボーナスがあります。 。涼しい。

4
Fattie

これは実際にはpassportとは関係がなく、body-parserを使用していると仮定すると、かなり単純です。フォームにinput fieldがあり、属性name="name"が設定されていることを確認します。ここで、次のようにユーザー名を登録します。

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

ルーティングでは、req.body.nameを使用してこのフィールドにアクセスできます。

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;

}));

したがって、フォーム入力フィールドはいくつでも追加でき、name属性の値でアクセスできます。 2番目の例は次のとおりです。

<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                                                                     
       }                                                                          
    }                                                                        
})
1
Yusufbek