노드의 PassportJS가 로그 아웃시 세션을 제거하지 않는 이유
내 시스템이 PassportJS로 로그 아웃하는 데 문제가 있습니다. 로그 아웃 경로가 호출되고 있지만 세션을 제거하지 않는 것 같습니다. 사용자가 특정 경로에 로그인하지 않은 경우 401을 반환하고 싶습니다. 사용자가 로그인했는지 확인하기 위해 authenticateUser를 호출합니다.
감사합니다!
/******* This in index.js *********/
// setup passport for username & passport authentication
adminToolsSetup.setup(passport);
// admin tool login/logout logic
app.post("/adminTool/login",
passport.authenticate('local', {
successRedirect: '/adminTool/index.html',
failureRedirect: '/',
failureFlash: false })
);
app.get('/adminTool/logout', adminToolsSetup.authenticateUser, function(req, res){
console.log("logging out");
console.log(res.user);
req.logout();
res.redirect('/');
});
// ******* This is in adminToolSetup ********
// Setting up user authentication to be using user name and passport as authentication method,
// this function will fetch the user information from the user name, and compare the password for authentication
exports.setup = function(passport) {
setupLocalStrategy(passport);
setupSerialization(passport);
}
function setupLocalStrategy(passport) {
passport.use(new LocalStrategy(
function(username, password, done) {
console.log('validating user login');
dao.retrieveAdminbyName(username, function(err, user) {
if (err) { return done(err); }
if (!user) {
return done(null, false, { message: 'Incorrect username.' });
}
// has password then compare password
var hashedPassword = crypto.createHash('md5').update(password).digest("hex");
if (user.adminPassword != hashedPassword) {
console.log('incorrect password');
return done(null, false, { message: 'Incorrect password.' });
}
console.log('user validated');
return done(null, user);
});
}
));
}
function setupSerialization(passport) {
// serialization
passport.serializeUser(function(user, done) {
console.log("serialize user");
done(null, user.adminId);
});
// de-serialization
passport.deserializeUser(function(id, done) {
dao.retrieveUserById(id, function(err, user) {
console.log("de-serialize user");
done(err, user);
});
});
}
// authenticating the user as needed
exports.authenticateUser = function(req, res, next) {
console.log(req.user);
if (!req.user) {
return res.send("401 unauthorized", 401);
}
next();
}
Brice의 대답은 훌륭 하지만 여전히 중요한 차이점을 발견했습니다. Passport 가이드에서는 다음과 같이 사용하도록 제안합니다 .logout()
(라고도 함 .logOut()
).
app.get('/logout', function(req, res){
req.logout();
res.redirect('/'); //Can fire before session is destroyed?
});
그러나 위에서 언급했듯이 이것은 신뢰할 수 없습니다. 다음과 같이 Brice의 제안을 구현할 때 예상대로 작동한다는 것을 알았습니다.
app.get('/logout', function (req, res){
req.session.destroy(function (err) {
res.redirect('/'); //Inside a callback… bulletproof!
});
});
도움이 되었기를 바랍니다!
같은 문제가 발생했습니다. 작품 req.session.destroy();
대신 사용 req.logout();
하지만 이것이 모범 사례인지 모르겠습니다.
session.destroy
사용자가 완전히 로그 아웃되었는지 확인하려면 세션 쿠키도 지워야합니다.
여기서 문제는 애플리케이션이 단일 페이지 앱의 API로도 사용되는 경우 (권장되지는 않지만 매우 일반적 임) 로그 아웃 전에 시작되고 로그 아웃 후에 종료되는 Express에 의해 처리되는 일부 요청이있을 수 있다는 것입니다. 이 경우 더 오래 실행되는이 요청은 삭제 된 후 redis에서 세션을 복원합니다. 다음에 페이지를 열 때 브라우저에 여전히 동일한 쿠키가 있기 때문에 성공적으로 로그인됩니다.
req.session.destroy(function() {
res.clearCookie('connect.sid');
res.redirect('/');
});
그렇지 않으면 일어날 수있는 일입니다.
- 요청 1 (모든 요청)이 수신 됨
- 요청 1은 redis에서 메모리로 세션을로드합니다.
- 로그 아웃 요청 수신
- 로그 아웃 요청이 세션을로드합니다.
- 로그 아웃 요청으로 세션이 파괴됨
- 로그 아웃 요청이 브라우저로 리디렉션을 보냅니다 (쿠키가 제거되지 않음).
- 요청 1이 처리를 완료합니다.
- Req 1은 세션을 메모리에서 redis로 저장합니다.
- 쿠키와 세션이 모두 제자리에 있기 때문에 사용자가 로그인 대화 상자없이 페이지를 엽니 다.
이상적으로는 API 호출에 토큰 인증을 사용하고 페이지 만로드하는 웹 앱의 세션 만 사용해야하지만 웹 앱이 API 토큰을 얻는 데만 사용되는 경우에도이 경쟁 조건은 여전히 가능합니다.
나는 같은 문제를 겪고 있었고 Passport 기능에 전혀 문제가 아니라 내 /logout
경로를 호출하는 방식에 문제가있는 것으로 밝혀졌습니다 . fetch를 사용하여 경로를 호출했습니다.
(나쁜)
fetch('/auth/logout')
.then([other stuff]);
그렇게하면 쿠키를 보내지 않으므로 세션이 계속되지 않고 res.logout()
다른 세션에 적용되는 것 같습니다 . 어쨌든 다음을 수행하면 문제가 해결됩니다.
(좋은)
fetch('/auth/logout', { credentials: 'same-origin' })
.then([other stuff]);
나는 똑같은 문제를 겪고 있었고 자본 O는 그것을 고쳤습니다.
app.get('/logout', function (req, res){
req.logOut() // <-- not req.logout();
res.redirect('/')
});
편집 : 이것은 더 이상 문제가 아닙니다.
나는 최근에 이와 같은 문제를 겪고 있었고 어떤 답변도 나를 위해 문제를 해결하지 못했습니다. 틀릴 수도 있지만 경쟁 조건과 관련이있는 것 같습니다.
세션 세부 정보를 아래 옵션으로 변경하면 문제가 해결 된 것 같습니다. 약 10 번 정도 테스트했는데 모든 것이 제대로 작동하는 것 같습니다.
app.use(session({
secret: 'secret',
saveUninitialized: false,
resave: false
}));
기본적으로 난 그냥 변경 saveUninitialized
과 resave
에서 true
에 false
. 문제가 해결 된 것 같습니다.
참고로 req.logout();
로그 아웃 경로에서 표준 방법을 사용하고 있습니다 . 다른 사람들이 언급 한 것처럼 세션 파괴를 사용하지 않습니다.
app.get('/logout', function(req, res) {
req.logout();
res.redirect('/');
});
나는 둘 다 사용 req.logout()
하고 req.session.destroy()
잘 작동합니다.
server.get('/logout', (req, res) => {
req.logout();
req.session.destroy();
res.redirect('/');
});
언급하자면 Redis를 세션 저장소로 사용합니다.
혼자서 세션을 파괴하는 것이 이상해 보입니다. 다음 구성 에서이 문제에 직면했습니다.
"express": "^4.12.3",
"passport": "^0.2.1",
"passport-local": "^1.0.0",
이 구성 이 잘 작동 한다고 말해야합니다 . 내 문제의 이유는 sessionStore
여기에서 정의한 관습 에 있습니다.
app.use(expressSession({
...
store: dbSessionStore,
...
}));
여기에 문제가 있는지 확인하려면 스토어 라인에 주석을 달고 세션이 지속되지 않고 실행하십시오. 작동한다면 사용자 정의 세션 저장소를 파헤쳐 야합니다. 제 경우에는 set
방법이 잘못 정의되었습니다. 이전에 생각했던 것처럼 호출되지 않은 req.logout()
세션 저장 destroy()
방법 을 사용할 때 . 대신 set
업데이트 된 세션으로 메서드를 호출했습니다 .
행운을 빕니다.이 답변이 도움이되기를 바랍니다.
여권을 제대로 설정하지 않아 가끔 작동하지 않는 경험이 있습니다. 예를 들어, 나는 vhost
했지만 메인 앱에서 나는 잘못된 여권을 이렇게 설정했습니다.
app.js (왜 잘못 되었나요? 아래 blockqoute를 참조하세요)
require('./modules/middleware.bodyparser')(app);
require('./modules/middleware.passport')(app);
require('./modules/middleware.session')(app);
require('./modules/app.config.default.js')(app, express);
// default router across domain
app.use('/login', require('./controllers/loginController'));
app.get('/logout', function (req, res) {
req.logout();
res.redirect('/');
});
// vhost setup
app.use(vhost('sub1.somehost.dev', require('./app.host.sub1.js')));
app.use(vhost('somehost.dev', require('./app.host.main.js')));
실제로는 로그인 할 수 없어야합니다.하지만 계속해서 실수를 더 많이하기 때문에 그렇게 할 수 있습니다. 여기에 다른 여권 설정을 입력하면 세션 양식을 app.js
사용할 수 있습니다.app.host.sub1.js
app.host.sub1.js
// default app configuration
require('./modules/middleware.passport')(app);
require('./modules/app.config.default.js')(app, express);
그래서, 내가 로그 아웃하고 싶을 때 ... 전에 app.js
초기화 passport.js
를 시작하여 잘못된 일을했기 때문에 작동하지 않습니다 express-session.js
.
그러나이 코드는 다른 사람들이 언급했듯이 어쨌든 문제를 해결할 수 있습니다.
app.js
app.get('/logout', function (req, res) {
req.logout();
req.session.destroy(function (err) {
if (err) {
return next(err);
}
// destroy session data
req.session = null;
// redirect to homepage
res.redirect('/');
});
});
하지만 제 경우에는 올바른 방법은 ... passport.js 전에 express-session.js 를 바꾸는 것입니다.
문서 도 언급
세션 지원을 활성화하는 것은 전적으로 선택 사항이지만 대부분의 응용 프로그램에 권장됩니다. 활성화 된 경우, passport.session () 전에 express.session ()을 사용하여 로그인 세션이 올바른 순서로 복원되었는지 확인하십시오.
그래서 제 사건에서 로그 아웃 문제를 해결했습니다.
app.js
require('./modules/middleware.bodyparser')(app);
require('./modules/middleware.session')(app);
require('./modules/middleware.passport')(app);
require('./modules/app.config.default.js')(app, express);
// default router across domain
app.use('/login', require('./controllers/loginController'));
app.get('/logout', function (req, res) {
req.logout();
res.redirect('/');
});
app.host.sub1.js
// default app configuration
require('./modules/app.config.default.js')(app, express);
그리고 지금 req.logout();
은 일입니다.
대답 중 어느 것도 나를 위해 일하지 않았으므로 내 것을 공유하겠습니다.
app.use(session({
secret: 'some_secret',
resave: false,
saveUninitialized: false,
cookie: {maxAge: 1000} // this is the key
}))
과
router.get('/logout', (req, res, next) => {
req.logOut()
req.redirect('/')
})
나는 같은 문제를 겪고 있었다. 내 여권 버전이 Express 4.0과 호환되지 않는 것으로 나타났습니다. 이전 버전을 설치하기 만하면됩니다.
npm install --save express@3.0.0
이것은 나를 위해 일했습니다.
app.get('/user', restrictRoute, function (req, res) {
res.header('Cache-Control', 'no-cache, private, no-store, must-revalidate,
max-stale=0, post-check=0, pre-check=0');
});
페이지가 캐시에 저장되지 않도록합니다.
나는 프로그래머와 함께 일하고 있는데 req의 사용자를 제거하는 것이 좋습니다.
app.get('/logout', function (req, res){
req.session.destroy(function (err) {
req.user = null;
res.redirect('/'); //Inside a callback… bulletproof!
});
});
Reason: we need to remove from req(passportjs also doing this but async way) because there is no use of user data after logout even this will save memory and also might be passportjs found user data and may create new session and redirect(but not yet happen) By the ways, this is our responsibility to remove irrelevant thing. PassportJS assign data into req.user after login and also remove if we use req.logout() but it may not works properly some times as NodeJS Asynchronous in nature
I faced the similar problem with Passport 0.3.2.
When I use Custom Callback for the passport login and signup the problem persisted.
The problem was solved by upgrading to Passport 0.4.0 and adding the lines
app.get('/logout', function(req, res) {
req.logOut();
res.redirect('/');
});
Apparently there are multiple possible causes of this issue. In my case the problem was wrong order of declarations i.e. the logout endpoint was declared before passport initialization. The right order is:
app.use(passport.initialize());
app.use(passport.session());
app.get('/logout', function(req, res) {
req.logout();
res.redirect('/');
});
Since you are using passport authentication which uses it's own session via the connect.sid
cookie this simplest way of dealing with logging out is letting passport handle the session.
app.get('/logout', function(req, res){
if (req.isAuthenticated()) {
req.logOut()
return res.redirect('/') // Handle valid logout
}
return res.status(401) // Handle unauthenticated response
})
All examples here do a redirect after the req.session.destroy. But do realise that Express will create a new session instantly for the page you are redirecting to. In combination with Postman I found the strange behaviour that doing a Passport-Login right after the logout gives the effect that Passport is successful but cannot store the user id to the session file. The reason is that Postman needs to update the cookie in all requests for this group, and this takes a while. Also the redirect in the callback of the destroy does not help.
I solved it by not doing a redirect but just returning a json message.
You shoulde be using req.logout() to destroy the session in the browser.
app.get('/logout', function(req, res) {
req.logout();
res.redirect('/'); // whatever the route to your default page is
});
I don't know how but ng-href="/signout"
solved my problem. Previously I have used service to logout, but instead I've used it directly.
In my case, using a callback passed to req.session.destroy
helped only some of the time and I had to resort to this hack:
req.session.destroy();
setTimeout(function() {
res.redirect "/";
}, 2000);
I don't know why that's the only solution that I've been able to get to work, but unfortunately @JulianLloyd's answer did not work for me consistently.
It may have something to do with the fact that my live login page uses SSL (I haven't been able to reproduce the issue on the staging site or my localhost). There may be something else going on in my app too; I'm using the derby-passport module since my app is using the Derby framework, so it's difficult to isolate the problem.
It's clearly a timing issue because I first tried a timeout of 100 ms, which wasn't sufficient.
Unfortunately I haven't yet found a better solution.
'developer tip' 카테고리의 다른 글
내가 만든 .clj Clojure 파일을 어떻게 실행할 수 있습니까? (0) | 2020.11.17 |
---|---|
ASP.NET MVC에서 Tempdata 사용-모범 사례 (0) | 2020.11.17 |
Homebrew 업데이트 실패 :“제발, 변경 사항을 커밋하거나 병합하기 전에 숨김” (0) | 2020.11.17 |
Websocket onerror-오류 설명을 읽는 방법? (0) | 2020.11.17 |
ASP.NET Core의 get 메서드에 여러 매개 변수를 전달하는 방법 (0) | 2020.11.17 |