2016-12-09 25 views
2

は、私は、Express持っているとパスポートはそうのように構成:passport.deserializeUser()でエラーを処理するにはどうすればよいですか?

var db = require("./database.js"); // exports models e.g. db.User 

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

var express = require("express"); 
var site = express(); 
var flash = require("connect-flash"); 
var passport = require("passport"); 

site.use(require("cookie-parser")()); 
site.use(require("body-parser").urlencoded({extended:false})); 
site.use(require("express-session")(...)); 
site.use(flash()); 
site.use(passport.initialize()); 
site.use(passport.session()); 

は、私は(私は本棚を経由してのMySQLに裏打ちされたlocal認証を使用しています)deserializeUserのかなりの株式の実装を持っています

私は次の特定の問題に取り組んでいます。ログインしたユーザーがデータベースから削除されたとき(サイト管理者がユーザーを削除したときなど)に、デシリアライズが期待どおりブックシェルフのCustomError("EmptyResponse")で失敗します。しかし、私はそれをどのように扱うべきか分かりません。 done(err, null)最終的には、エラーメッセージとスタックトレースがHTMLとしてクライアントに返されます。

質問:エラーの場合、deserializeUserからカスタムの優雅なエラー処理をどうやって行うことができますか?それは物事を単純化した場合

今、私は私の代わりに、エラーのnullユーザーを与えるためにdb.User.findByIdコールに{require:false}を追加することができますが、私はまだそれを処理する方法がわからない(とも私はまだする必要がありますかデータベースサーバがダウンして接続エラーが発生した場合など、エラーオブジェクトを処理します。

私が失敗した場合の対処方法は、ログインページにユーザをリダイレクトすることです(潜在的に説明的なフラッシュメッセージが表示されますが、deserializeUserのリクエスト/レスポンスへのアクセス権がありません)。どのように返信するか。 Passport docs "Configure" section

+0

あなただけのエラー( 'err.message')内のメッセージをチェックし、ユーザーのために良さそうに見えますいくつかのカスタム応答を返送することはできますか? ( 'catch'コールバックで) –

+0

@ JoshBeamそれは私がやりたいことですが、そこからどのように応答オブジェクトにアクセスするのですか? 'deserializeUser'にパラメータとして渡されません。 –

答えて

3

私は1つの解決策を考え出しました。ここでのエラーは、Expressミドルウェアのエラーハンドラで処理できます。したがって、たとえば:

// Note: Must be used *after* passport middleware. 
site.use(function(err, req, res, next) { 
    if (err) { 
     // Handle deserialization errors here. 
    } else { 
     next(); 
    } 
}); 

一つの重要な注意点しかし、逆シリアル化が失敗した場合は非回復可能、パスポート(認証を必要としないものも含め)を介してアクセスしすべてルートは、を失敗し続けるである可能性が高いていますまた、ログインエンドポイントとログアウトエンドポイントも含まれているため、ユーザーがクッキーをクリアするまでアクセスが永久に中断されます。だから、それが回復する唯一の現実的な方法だ、ログアウトを強制する必要があります。

site.use(function(err, req, res, next) { 
    if (err) { 
     req.logout(); // So deserialization won't continue to fail. 
    } else { 
     next(); 
    } 
}); 

その上さらに建物を、私の場合、私はフラッシュメッセージとバックログインページにリダイレクトしたかったです。エラーがそう、ログインページ自体に発生したあなたは無限のリダイレクトを回避するために必要がある場合:

site.use(function(err, req, res, next) { 
    if (err) { 
     req.logout(); 
     if (req.originalUrl == "/loginpage") { 
      next(); // never redirect login page to itself 
     } else { 
      req.flash("error", err.message); 
      res.redirect("/loginpage"); 
     } 
    } else { 
     next(); 
    } 
}); 

そしてもちろん、あなたはおそらく唯一のCustomError("EmptyResponse")のためにこれをしたい、あるいはエラーをやり直しをしかし、あなたは注意する必要がありますデシリアライズ実装で処理することで、独自のより具体的なエラーが発生します。

奇妙なアプローチの種類ですが、仕事を完了するようです。清潔な提案に開放する。

+0

優雅な解決策を見つけ出すためによくできました。私はなぜこの流れのための公式のレシピがないのか不思議です。これは有効なアプローチ以上のものですが、私はここで何かが欠けていると感じています。パスポートは、クライアントがスタックトレースで標準の500エラーを予想していると仮定しているのはなぜですか?これは何らかの形で生産では起こらないと考えられていますか? – Boaz

+0

非常に良い答え! –

0

、彼らは、特定のメッセージ送信する能力を示しています。

return done(null, false, { message: 'Incorrect username.' }); 

上記の例では、そのドキュメントにありますが、あなたのケースでは、あなたが何かを行うことができます:

passport.deserializeUser(function(id, done) { 
    db.User.findById(id).then(function (user) { 
     done(null, user); 
    }).catch(function (err) { 
     done(err, null, { message: 'User does not exist' }); 
    }); 
}); 
+0

いいえ、そうではありません。 done' 'の形態は、(戦略を設定するときにドキュメントの一例である)は、認証戦略の文脈でのみ有効であり、フラッシュメッセージパラメータは、Express鎖の残りの部分に利用可能にされてしまいます。それは(ERR、...)は 'ちょうどクライアントに送り返さに直ちに停止するチェーンと完全なエラーメッセージとスタックトレースを起こし' '行わdeserializeUser'、中には効果がありません。それ以上のハンドラは実行されません。私はその応答で何もする機会がありません。 –

関連する問題