了解Passport,序列化失败,401错误

时间:2017-12-20 23:04:28

标签: javascript express authentication jwt passport.js

我今天一直在修改passport-jwt,试图弄清楚如何在我的应用程序中正确设置它。我没有注册用户和保存jwt令牌的问题,但我不认为我使用护照这样做。现在我尝试登录用户,我总是收到错误Error: Failed to serialize user into session。我在下面的一些文章中看到过:

passport.serializeUser((user, done) => {
  done(null, user.id);
});

passport.deserializeUser((id, done) => {
  User.findById(id, (err, user) => {
      done(err, user);
  });
});

但我似乎无法找到任何示例,甚至是护照文档的配置部分,它们解释了在哪里使用这些。它可能是我的问题的根源,但我不确定。我发现令人困惑的Passport的一个方面是JWT提取器。为什么我需要其中任何一个(即使它们是必需的)如果我想要做的就是将我的护照变成jwt令牌并将其保存在我的mongo数据库中?自己使用jsonwebtoken并根据需要对字符串进行散列/取消散列并使用cookie-parser创建自己的会话而不是使用像Passport这样的东西会不会更容易?我还尝试在休息电话中使用passport.authenicate(),但那些返回401。您可以在登录呼叫下面看到失败的尝试被注释掉。

请帮助,我觉得我是唯一一个发现护照比不那么健壮的东西更复杂的人,但我真的很乐意将其整理出来!

import express from 'express';
import path from 'path';
import bodyParser from 'body-parser';
import connection from './database';
import jwt from 'jsonwebtoken';
import cors from 'cors';
import crypto from 'crypto';
import passport from "passport";
import passportJWT from "passport-jwt";
const JwtStrategy = passportJWT.Strategy;
const ExtractJwt = passportJWT.ExtractJwt;
import { User } from './schema';
import { read } from 'fs';
const app = express();
const corsOptions = {
  origin: '*',
  optionsSuccessStatus: 200 // some legacy browsers (IE11, various SmartTVs) choke on 204
}
app.use(cors(corsOptions));
app.use(passport.initialize());
app.use(passport.session());

const jwtOptions = {
  jwtFromRequest: ExtractJwt.fromBodyField('Password'),
  secretOrKey: 'secretKey',
  jsonWebTokenOptions: { expiresIn: 172800 }
}

passport.use(new JwtStrategy(jwtOptions, (jwt_payload, done) => {
  User.findOne({ password: jwt_payload.sub }, (err, user) => {
    user ? done(null, user) : done(null, false);
  });
}));

passport.serializeUser((user, done) => {
  done(null, user.id);
});

passport.deserializeUser((id, done) => {
  User.findById(id, (err, user) => {
      done(err, user);
  });
});

app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());

app.use(express.static(path.join(__dirname, 'build')));

app.get('/*', (req, res) => {
  res.sendFile(path.join(__dirname, 'build', 'index.html'));
});

app.post('/test', (req, res) => {
  console.log('Success');
  console.log(req.body);
  res.json(req.body);
});

app.post('/register', async (req, res) => {
  if (req.body.FirstName
    && req.body.LastName
    && req.body.Email
    && req.body.Password
  ) {
    const token = await jwt.sign(
      { Password: req.body.Password },
      jwtOptions.secretOrKey,
      { expiresIn: '48h' }
    );
    const CreatedAt = await Date.now();
    const newUser = await new User({
      FirstName: req.body.FirstName,
      LastName: req.body.LastName,
      Email: req.body.Email,
      Password: token,

    });
    await newUser.save(err => {
      err ? console.log(err) : res.json(newUser);
    });
  }
  throw new('error');
});

// app.post('/login', passport.authenticate('jwt', { session: false }),
//   (req, res) => {
//     console.log(req.user)
//   if (req.body.Email && req.body.Password) {
//     User.findOne({ Email: req.body.Email }, (err, user) => {
//       if (err) return console.log(err);
//       console.log(user);
//       return user;
//     }).then((res) => {
//       jwt.verify(res.Password, jwtOptions.secretOrKey, (err, decoded) => {
//         err ? console.log(err) :
//         req.login(decoded, (err) => {
//           // if (err) { return next(err); };
//           if (err) {
//             console.log(err) 
//           } else {
//             console.log(decoded)
//           }
//         });
//       });
//     }).catch(err => console.log('Failed ', err));
//   } else {
//     console.log(req.body);
//   }
// });

app.post('/login', (req, res) => {
  if (req.body.Email && req.body.Password) {
    User.findOne({ Email: req.body.Email }, (err, user) => {
      if (err) return console.log(err);
      console.log(user);
      return user;
    }).then((res) => {
      // res.password returns the jwt string successfully
      jwt.verify(res.Password, jwtOptions.secretOrKey, (err, decoded) => {
        err ? console.log(err) :
        req.login(decoded, (err) => {
          // if (err) { return next(err); };
          if (err) {
            console.log(err) // always returns the error posted above
          } else {
            console.log(decoded)
          }
        });
      });
    }).catch(err => console.log('Failed ', err));
  } else {
    console.log(req.body);
  }
});

app.listen(9000, () => {
  console.log(`Listening on port 9000`);
});

自定义提取器尝试

    const customExtractor = req => {
  User.findOne({ Email: req.body.Email }, '_id', (err, user) => {
    const token = jwt.sign(
      { id: user },
      'secretKey',
      { expiresIn: '48h' }
    );
    return token;
  });

基于@OrthoHomeDefense的帖子,我创建了以下内容并成功向客户端发送了一个jwt令牌:

app.post("/login", (req, res) => {
  if (req.body.Email && req.body.Password) {
    User.findOne({ Email: req.body.Email }, (err, user) => {
      if(user.Password === req.body.Password) {
        console.log()
        var token = jwt.sign(JSON.stringify(user), jwtOptions.secretOrKey);
        res.json({token: token});
      } else {
        console.log(err);
        res.status(401).json({message:"Passwords did not match."});
      }
    });
  } else {
    res.status(401).json({message:"Please provide an email and a password."});
  }
});

2 个答案:

答案 0 :(得分:1)

首先,@ OrthoHomeDefense解决了我关于设置登录的初始问题,因为我对初始设置和使用护照需要遵循的内容感到困惑。

以下是我从客户端到服务器的电话。

export const test = token => {
  console.log(token)
  return dispatch => {
    axios.post('http://localhost:9000/test',
    {
      headers: {'authorization': token},
      data: {test: 'test', Token: token}
    }
  ).then((res) => {
      console.log(res.data);
    })
    .catch((error) => { console.log(error); });
  }
}

接下来是我在服务器端进行的相关测试。

const customExtractor = req => {
  let token = req.body.headers.authorization;
  console.log(token);
  return token;
}

const jwtOptions = {
  jwtFromRequest: customExtractor,
  secretOrKey: 'secretKey',
}

passport.use(new JwtStrategy(jwtOptions, (jwt_payload, done) => {
  console.log('Success', jwt_payload);
  User.findOne({id: jwt_payload.sub}, (err, user) => {
    if (err) return done(err, false);
    if (user) {
      return done(null, user);
    } else {
      return done(null, false);
    }
  });
}));

我尝试了下面的提取器,每次只收到404,所以我创建了上面非常简单的提取器。如果您将令牌保存在cookie或类似的东西中,请按照您自己的提取器中的适用情况进行编辑,因为我发现自己更容易完成。

jwtFromRequest: ExtractJwt.fromBodyField('Token'), jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), jwtFromRequest: ExtractJwt.fromHeader("authorization"),

答案 1 :(得分:0)

您正在呼叫jwt.verify(...)即验证令牌。您不需要在登录时验证令牌吗?您需要在登录时创建一个。

逐步完成此项/login并告诉我它是如何运行的。

 app.post("/login", function(req, res) {
      if(req.body.name && req.body.password){
        var name = req.body.name;
        var password = req.body.password;
      }
      // usually this would be a database call:
      //find user by username and password
      if( !user ){
        res.status(401).json({message:"no such user found"});
      }

      if(verify user is correct) {

        //token is created here
        var token = jwt.sign(payload, jwtOptions.secretOrKey);
        //here is the response
        res.json({message: "ok", token: token});
      } else {
        error
        res.status(401).json({message:"passwords did not match"});
      }
    });