如何判断用户是否使用passport.js已登录?

114

我已经阅读了两天的 passport.js 信息和示例,但我不确定在那之后我是否完成了所有的认证过程。

例如,如何知道我是否已登录,例如,我将具有带有登录或注销按钮的导航栏,是否有一些类似下面代码的变量?

if (login)
   <button>logout</button>
else 
   <button>login</button>
6个回答

232
如果用户已登录,passport.js 会在每个请求中为 express.js 创建一个 user 对象,并将其存储在 req 中,您可以在任何中间件中检查其是否存在。
if (req.user) {
    // logged in
} else {
    // not logged in
}

您可以创建一个简单的express.js中间件来检查用户是否已登录,如果没有,则重定向到/login页面:

function loggedIn(req, res, next) {
    if (req.user) {
        next();
    } else {
        res.redirect('/login');
    }
}

并使用它:

app.get('/orders', loggedIn, function(req, res, next) {
    // req.user - will exist
    // load user orders and render them
});

3
这并不是全局性的,而是仅限于请求对象。 - supernova
1
在使用express.js和passport.js进行web开发的98.8%的情况下,您将处理请求(如app.get、app.post等),因此讨论在其之外使用passport.js有点无意义。 是的,它只能在express路由中间件处理程序(如app.getapp.post等)中使用。如果您需要不同的功能,则应在问题中详细说明以及您试图实现什么。 - moka
3
我发现如果我不提供任何中间件来检查身份验证,例如“router.get('/', my_controller.index)”,那么passport将永远不会被调用,req.user将始终未定义。这很令人沮丧,因为我想允许任何访问者调用API,但根据请求者的不同定制响应内容。 - Lawrence I. Siden
4
有人能解释一下这个为什么不容易被利用吗?那个检查只是看请求中是否有用户对象。会话验证在哪里? - Michael Ramos
1
@rambossa 用户无法以任何方式直接设置 req.user。所有请求数据都在诸如 req.bodyreq.queryreq.params 之类的子对象中。除非中间件受到破坏,否则请求无法直接设置用户,而此时您已经失去了控制权。 - anon
显示剩余13条评论

52

如果您想像您的代码示例所示那样在模板中使用它,您可以创建以下中间件:

app.use(function (req, res, next) {
  res.locals.login = req.isAuthenticated();
  next();
});

在设置好护照(passport)之后,将该代码放置在某个位置。

然后在您的模板中使用它(swig示例)。

{% if login %}
<button>logout</button>
{% else %} 
<button>login</button>
{% endif %}

由于某些原因,上述中间件在我的模板中导致用户未定义的问题。我不得不重新提供用户对象到视图中来解决它,像这样:`app.use(function(req,res,next){` `res.locals.login = req.isAuthenticated();` `res.locals.user = req.user;` `next();` `});` - Tebbers
1
即使身份验证成功,下一个请求中isAuthenticated为false。您能帮忙回答这个问题吗?http://stackoverflow.com/questions/42842171/detect-if-the-user-was-authenticated-before - Suhail Gupta

5

虽然没有明确文档,但是passport会将一个isAuthenticated()方法插入到req中。
可以按照以下方式使用:

req.isAuthenticated() // returns true if auth, false if not

// auth.js
module.exports = {
  ensureAuthenticated: (req, res, next) => {
    if (req.isAuthenticated()) {
      return next()
    }
    res.redirect('/login') // if not auth
  },

  forwardAuthenticated: (req, res, next) => {
    if (!req.isAuthenticated()) {
      return next()
    }
    res.redirect('/dashboard');  // if auth    
  }
}

// app.js
app.get('/dashboard', ensureAuthenticated, (req, res) => res.render('dashboard'))
app.get('/login', forwardAuthenticated, (req, res) => res.render('login'))
app.get('/register', forwardAuthenticated, (req, res) => res.render('register'))

2

我在搜索解决方案时发现了这个页面。问题是如何在客户端检查登录状态。

登录后,我隐藏了登录按钮并显示了注销按钮。在页面刷新后,我再次看到登录按钮而不是注销按钮。唯一的解决方法是在使用会话时保存一个项目在sessionStorage中(如果您使用JWT,则保存在localStorage中)。在注销时删除此项目。 然后在每个页面加载时检查此sessionStorage项目并相应地执行操作。

if (sessionStorage.getItem('status')) {
    $("#btnlogout").show();
    $("#btnlogin").hide();
// or what ever you want to do
} else {
    $("#btnlogout").hide();
    $("#btnlogin").show();
}



function Login() {
            var data = {
                username: $("#myModal #usr").val(),
                password: $("#myModal #pw").val()

            };
            $.ajax({
                type: 'POST',
                url: '/login',
                contentType: 'application/JSON; charset=utf-8',
                data: JSON.stringify(data),
                success: funcSuccess,
                error: funcFail
            });
            function funcSuccess(res) {
                sessionStorage.setItem('status', 'loggedIn');

                $("#btnlogout").show();
                $("#btnlogin").hide();
            }
            function funcFail() { $("#pp").text('Login Failed'); };
        };

function Logout() {
    $.ajax({
        type: 'GET',
        url: '/logout',
        contentType: 'application/JSON; charset=utf-8',
        success: funcSuccess,
        error: funcFail,
    });
    function funcSuccess(res) {
        $("#btnlogout").hide();
        $("#btnlogin").show();
        sessionStorage.removeItem("status");
    };
    function funcFail() { alert('Login method Failed'); };
}; 

2
在app.get()或router.get()内使用以下代码。原始答案翻译成"最初的回答"。
router.get('/edit/:id', (req, res)=>{
  if(req.isAuthenticated()){
     if(req.isAuthenticated()){
      //

      }
  else{
   res.redirect('/users/login');//your particular login routes
     }
});

1

好问题,我在尝试实现类似功能时遇到了一些问题,当存在未经身份验证的请求时,如果res.locals变量返回一个falsy值,handlebars会跳过if块。为了解决这个问题,您需要在app.js文件中设置一个中间件,使req.user在整个应用程序中全局可用,如下所示...

app.use(function (req, res, next) {
res.locals.login = req.user;
next();

在您的头文件中,您可以检查已认证的用户并根据内容显示如下。

});

                {{#if login }}
                    <li><a href="#">User Account</a></li>
                    <li role="separator" class="divider"></li>
                    <li><a href="#">Logout</a></li>
                {{/if}}
                {{#unless login}}
                    <li><a href="#">Sign up</a></li>
                    <li><a href="#">Sign in</a></li>
                {{/unless}} 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接