私はAngular.jsを初めて使用し、Webサイトのローカル認証を構築しようとしています。私はさまざまな情報源を調べましたが、 シングルページアプリケーションでの認証 は非常に役に立ちました。ローカルホストで同じものをビルドしようとすると、コードがループしました。
app.post('/login',.....)
は応答でユーザーを返しますが、その後、管理ページの読み込み中に、app.get('/loggedin',... )
を呼び出してユーザーがログインしているかどうかを確認し、req.isAuthenticated()
はfalse
を返しますログイン後もループします。なぜこれが起こっているのか理解できません。助けてください。
サーバーサイドコード
var express = require('express');
var http = require('http');
var path = require('path');
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
//==================================================================
// Define the strategy to be used by PassportJS
passport.use(new LocalStrategy(
function(username, password, done) {
if (username === "admin" && password === "admin") // stupid example
return done(null, {name: "admin"});
return done(null, false, { message: 'Incorrect username.' });
}
));
// Serialized and deserialized methods when got from session
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(user, done) {
done(null, user);
});
// Define a middleware function to be used for every secured routes
var auth = function(req, res, next){
if (!req.isAuthenticated())
res.send(401);
else
next();
};
//==================================================================
// Start express application
var app = express();
// all environments
app.set('port', process.env.PORT || 3000);
app.use(express.favicon());
app.use(express.cookieParser());
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.session({ secret: 'securedsession' }));
app.use(passport.initialize()); // Add passport initialization
app.use(passport.session()); // Add passport initialization
app.use(app.router);
app.all('*', function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
// development only
if ('development' == app.get('env')) {
app.use(express.errorHandler());
}
//==================================================================
// routes
app.get('/', function(req, res){
res.render('index', { title: 'Express' });
});
app.get('/users', auth, function(req, res){
res.send([{name: "user1"}, {name: "user2"}]);
});
//==================================================================
//==================================================================
// route to test if the user is logged in or not
app.get('/loggedin', function(req, res) {
res.send(req.isAuthenticated() ? req.user : '0');
});
// route to log in
app.post('/login', passport.authenticate('local'), function(req, res) {
res.send(req.user);
});
// route to log out
app.post('/logout', function(req, res){
req.logOut();
res.send(200);
});
//==================================================================
http.createServer(app).listen(app.get('port'), function(){
console.log('Express server listening on port ' + app.get('port'));
});
クライアント側のJsファイル
'use strict';
/**********************************************************************
* Angular Application
**********************************************************************/
var app = angular.module('app', ['ngResource','ngRoute'])
.config(function($routeProvider, $locationProvider, $httpProvider) {
//================================================
// Check if the user is connected
//================================================
var checkLoggedin = function($q, $timeout, $http, $location, $rootScope){
// Initialize a new promise
var deferred = $q.defer();
// Make an AJAX call to check if the user is logged in
$http.get('http://localhost:3000/loggedin').success(function(user){
// Authenticated
if (user !== '0')
$timeout(deferred.resolve, 0);
// Not Authenticated
else {
$rootScope.message = 'You need to log in.';
$timeout(function(){deferred.reject();}, 0);
$location.url('/login');
}
});
return deferred.promise;
};
//================================================
//================================================
// Add an interceptor for AJAX errors
//================================================
$httpProvider.responseInterceptors.Push(function($q, $location) {
return function(promise) {
return promise.then(
// Success: just return the response
function(response){
return response;
},
// Error: check the error status to get only the 401
function(response) {
if (response.status === 401)
$location.url('/login');
return $q.reject(response);
}
);
}
});
//================================================
//================================================
// Define all the routes
//================================================
$routeProvider
.when('/', {
templateUrl: 'views/main.html'
})
.when('/admin', {
templateUrl: 'views/admin.html',
controller: 'AdminCtrl',
resolve: {
loggedin: checkLoggedin
}
})
.when('/login', {
templateUrl: 'views/login.html',
controller: 'LoginCtrl'
})
.otherwise({
redirectTo: '/login'
});
//================================================
}) // end of config()
.run(function($rootScope, $http){
$rootScope.message = '';
// Logout function is available in any pages
$rootScope.logout = function(){
$rootScope.message = 'Logged out.';
$http.post('http://localhost:3000/logout');
};
});
/**********************************************************************
* Login controller
**********************************************************************/
app.controller('LoginCtrl', function($scope, $rootScope, $http, $location) {
// This object will be filled by the form
$scope.user = {};
// Register the login() function
$scope.login = function(){
$http.post('http://localhost:3000/login', {
username: $scope.user.username,
password: $scope.user.password,
})
.success(function(user){
// No error: authentication OK
$rootScope.message = 'Authentication successful!';
$location.url('/admin');
})
.error(function(){
// Error: authentication failed
$rootScope.message = 'Authentication failed.';
$location.url('/login');
});
};
});
/**********************************************************************
* Admin controller
**********************************************************************/
app.controller('AdminCtrl', function($scope, $http) {
// List of users got from the server
$scope.users = [];
// Fill the array to display it in the page
$http.get('http://localhost:3000/users').success(function(users){
for (var i in users)
$scope.users.Push(users[i]);
});
});
Cookieとセッション変数は状態管理を機能させるものの一部であるため、rdeggesはアイデアの一部であると思います。 bodyParserも必要だと思いますが、ここでは省略しました。
私は自分のWebサイトでPassportを使用しています(MongoDBユーザーテーブルへの認証)。これが私のコードからの抜粋です。
/server.js:
var cookieParser = require('cookie-parser');
...
var passport = require('passport');
var expressSession = require('express-session');
var initPassport = require('./passport/init');
initPassport(passport);
...
self.app.use(cookieParser());
self.app.use(expressSession({secret: 'MYSECRETISVERYSECRET', saveUninitialized: true, resave: true}));
self.app.use(passport.initialize());
self.app.use(passport.session());
...
var routes = require('./routes/index')(passport);
self.app.use('/', routes);
/passport/init.js:
var login = require('./login');
var signup = require('./register');
var User = require('../models/user');
module.exports = function(passport) {
// Passport needs to be able to serialize and deserialize users to support persistent login sessions
passport.serializeUser(function(user, done) {
console.log('serializing user: ');
console.log(user);
done(null, user._id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
console.log('deserializing user:', user);
done(err, user);
});
});
// Setting up Passport Strategies for Login and SignUp/Registration
login(passport);
signup(passport);
}
/routes/index.js:
var passport = require('passport');
var User = require('../models/user');
...
var isAuthenticated = function (req, res, next) {
// if user is authenticated in the session, call the next() to call the next request handler
// Passport adds this method to request object. A middleware is allowed to add properties to
// request and response objects
if (req.isAuthenticated())
return next();
// if the user is not authenticated then redirect him to the login page
res.redirect('/login');
}
IsValidated()関数がどこにも定義されていないのは価値があります。
非常に多くのことができます。
1。) PassportJS Facebook login isAuthenticatedは、認証が成功してもfalseを返します (あなたの場合は順序は正しいようです)のように注文します。
2。) PassportおよびPassport Local req.isAuthenticatedは常にfalseを返します のようにreq.login()はありません
この場合、私は後者を選びますが、その質問とは異なる理由で。独自のLocalStrategy
を提供しました。ユーザーをログインさせるには、自分でreq.login()
を呼び出す必要があります。 passport
ドキュメントで説明されているように、独自のカスタムコールバックを定義する場合と同じように: http://passportjs.org/guide/authenticate/ 。
私の場合、セッション保存を手動で呼び出すためにJMeasによって提案された解決策を試しましたが、機能しませんでした
https://github.com/jaredhanson/passport/issues/482
req.session.save(function() { successRedirect(); })
いくつかの実験の後、すべてのミドルウェア呼び出しの先頭にapp.use(session({...}))を移動したところ、req.isAuthenticated()が期待どおりに機能するようになりました。セッションのセットアップは、最初のミドルウェアとして、または少なくともCookieを設定する前に行う必要があると思います。
壊れた電話:
var app = express();
app.use(query.json());
app.use(query.urlencoded({ extended: false }));
app.use(cookies());
app.use(express.static(path.join(__dirname, 'public')));
app.use(passport.initialize());
app.use(passport.session());
app.use(session({
secret: 'card',
resave: true,
saveUninitialized: true
}));
app.use('/', routes); // this is where I call passport.authenticate()
固定呼び出し:
app.use(session({
secret: 'card',
resave: true,
saveUninitialized: true
}));
app.use(query.json());
app.use(query.urlencoded({ extended: false }));
app.use(cookies());
app.use(express.static(path.join(__dirname, 'public')));
app.use(passport.initialize());
app.use(passport.session());
app.use('/', routes);
ブラウザはセッションCookieを保持していますか?ログイン後にブラウザがセッションCookieを保持していないように聞こえます。そのため、/loggedin
への後続のリクエストは失敗します。
追加するのを忘れて同じ問題が発生しました
request.login()
オン
app.post('/login',
function(request, response, next) {
console.log(request.session)
passport.authenticate('login',
function(err, user, info) {
if(!user){ response.send(info.message);}
else{
request.login(user, function(error) {
if (error) return next(error);
console.log("Request Login supossedly successful.");
return response.send('Login successful');
});
//response.send('Login successful');
}
})(request, response, next);
}
);
また、初期化のために次のものがあることを確認してください order
var session = require('express-session');
// required for passport session
app.use(session({
secret: 'secrettexthere',
saveUninitialized: true,
resave: true,
// using store session on MongoDB using express-session + connect
store: new MongoStore({
url: config.urlMongo,
collection: 'sessions'
})
}));
// Init passport authentication
app.use(passport.initialize());
// persistent login sessions
app.use(passport.session());