Вход в JWT - токен авторизации не был найден в промежуточном программном обеспечении - PullRequest
2 голосов
/ 05 апреля 2019

Я следовал руководству, чтобы добавить логин и регистрацию в свое приложение Node.js с использованием токена JWT, и мне трудно войти в систему и перенаправить на мою страницу входа в систему. Регистрация пользователя работает отлично, но часть входа в систему я не могу понять.

Это учебник, которому я следовал: https://medium.freecodecamp.org/learn-how-to-handle-authentication-with-node-using-passport-js-4a56ed18e81e

Мой код для входа выглядит так:

router.post('/login', auth.optional, (req, res, next) => {
console.log(req.body);

var user = {
    email: req.body.email,
    password: req.body.password
}

if (!user.email) {
  return res.status(422).json({
    errors: {
      email: 'is required',
    },
  });
}

if (!user.password) {
  return res.status(422).json({
    errors: {
      password: 'is required',
    },
  });
}

return passport.authenticate('local', { session: false }, (err, passportUser, info) => {

    if (err) {
        return next(err);
    }

    if (passportUser) {
        const user = passportUser;
        user.token = passportUser.generateJWT();
        console.log("TOKEN: " + user.token);

        res.setHeader('Authorization', 'Token ' + user.token);

        return res.json({ user: user.toAuthJSON() });
    }

    return res.status(400).json({
        errors: {
            message: info,
        },
    });

    })(req, res, next);
});

Мой «/ admin» маршрут «залогинен» выглядит так:

router.get("/admin", auth.required, function(req, res) {
    res.render('admin', {
        user : req.user // get the user out of session and pass to template
    });
});

Я не уверен, как я могу перенаправить на свой маршрут '/ admin', также передавая токен, потому что в настоящее время я вижу следующую ошибку после входа в систему. Имеет смысл, так как я не передаю токен в '/ admin 'маршрут ... но как мне это сделать? :)

UnauthorizedError: No authorization token was found at middleware

Заранее спасибо за помощь!

EDIT:

Все еще не могу понять это и не совсем понимаю, как этот поток должен работать ... где заголовки должны быть установлены на токен и как мне перенаправить на мою страницу администратора после входа в систему успешный.

Вот мой код промежуточного программного обеспечения, если это поможет:

const getTokenFromHeaders = (req) => {

    console.log("REQ: " + JSON.stringify(req.headers));

    const { headers: { authorization } } = req;

    if(authorization && authorization.split(' ')[0] === 'Token') {
        return authorization.split(' ')[1];
    }

    return null;
};

const auth = {
    required: jwt({
        secret: 'secret',
        userProperty: 'payload',
        getToken: getTokenFromHeaders,
    }),

    optional: jwt({
        secret: 'secret',
        userProperty: 'payload',
        getToken: getTokenFromHeaders,
        credentialsRequired: false,
    }),
};

Ответы [ 2 ]

1 голос
/ 15 апреля 2019

Ваш код не имеет проблемы. Похоже, вы запутались в потоке входа с сервера на клиент (Frontend / Web).

Давайте сначала рассмотрим способ RESTFUL . В статье также упоминается тот же поток.

Поток RESTFUL API выглядит следующим образом:

Запросы пользователей на вход: POST : /api/v1/auth/login с именем пользователя и паролем в теле запроса. В случае успеха пользователь возвращается с базовой информацией и токеном . Если нет, пользователю возвращается код состояния 401 (неавторизованный). На этом поток входа в систему заканчивается .

Токен, предоставленный ранее пользователю, используется для выполнения последующих вызовов к бэкэнду, который пользователь может использовать для выполнения различных операций с системой. По сути, именно клиент запрашивает у сервера последующие действия с токеном, указанным в запросе на вход в систему.

Так что в вашем случае пользователь после получения токена должен сделать запрос на получение информации администратора из бэкэнда.

Но я предполагаю, что вы визуализируете представления со стороны сервера, и вы хотите визуализировать представление администратора после успешного входа пользователя, и это довольно просто.

Вместо вашего res.json() после успешного входа в систему. Вам нужно использовать res.render().

res.render('admin', {
    user: user.toAuthJSON() // assuming your user contains the token already
})

Edit:

Так как res.render() не меняет URL в браузере. Для этого вам нужно использовать res.redirect(). Но проблема в том, что вы не можете отправить контекст в res.redirect().

Для этого вам нужно будет передать маркер пользователя в качестве параметра запроса. Смотрите здесь .

TL; DR

// assuming you are using Node v7+
const querystring = require('querystring');
const query = querystring.stringify({
         token: user.token,
});
const adminRoute = '/admin?' + query;
res.redirect(adminRoute)

А в вашем админ-маршруте вам нужно немного изменить код.

  1. Убедитесь, что токен принадлежит реальному пользователю, и получите информацию о пользователе из токена.
  2. Визуализация шаблона admin с информацией о пользователе, полученной на шаге 1.
router.get("/admin", function(req, res) {
    // verify the token
    const token = req.query.token;
    const user = null;
    jwt.verify(token, 'secret', function (err, decoded) {
    if (err) {
      res.status(401).send('Unauthorized user')
    }
    // decoded contains user
    user = decoded.user  
  });

    res.render('admin', {
        user : user
    });
});

1 голос
/ 11 апреля 2019

Я тоже немного новичок в этом, но у меня это работает следующим образом.

В вашем файле server.js:

const passport = require("passport");
const JwtStrategy = require("passport-jwt").Strategy;
const ExtractJwt = require("passport-jwt").ExtractJwt;
app.use(passport.initialize());
const opts = {};
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
opts.secretOrKey = Keys.secretOrKey;
passport.use(
  new JwtStrategy(opts, (jwt_payload, done) => {
    // somefunction looks up the id in jwt payload and 
    // supplies passport the authenticated user via the "Done" function
    somefunction.user(jwt_payload.id)
      .then(user => {
        if (user) {
          return done(null, user);
        }
        return done(null, false);
      });
  })
);

В ваших определениях API

const jwt = require("jsonwebtoken");

router.post("/login", (req, res) => {
  const { userInfo } = req.body;

  // userInfo has username and password in it
  // anotherFuction validates the user id and password combo
  anotherFunction(userInfo.id, userInfo.password)
    .then(isAuthenticated => {
      if (isAuthenticated) {

        const payload = {
          id: user.sAMAccountName,
          firstname: user.givenName,
          lastname: user.sn
        };

        // Sign Token with the payload
        jwt.sign(
          payload,
          Keys.secretOrKey,
          { expiresIn: 3600 },
          (err, token) => {
            res.json({
              success: true,
              token: "Bearer " + token
            });
          }
        );
      } else {
        // don't mind the statuses ^_^'
        return res.status(401).json({ error: "Login failed." });
      }
    })
    .catch(err => {
      return res.status(400).json(err);
    });
});

После вызова API вы хотите установить токен аутентификации.Следующее позволяет вам удалить токен, если ничего не передано, фактически «Выход из системы».

const setAuthToken = token => {
  if (token) {
    // Apply to every request
    axios.defaults.headers.common["Authorization"] = token;
  } else {
    // Delete Auth Header
    delete axios.defaults.headers.common["Authorization"];
  }
};

Если вы пытаетесь использовать его во внешнем интерфейсе, вам нужно использовать jwt_decode, чтобы получить значенияот токена и установите его так, как считаете нужным.Если для хранения данных входа в систему используется Redux, он должен выглядеть примерно так.Поскольку я чувствую, что обсуждение использования localstorage для jwtToken выходит за рамки этого, просто знайте, что нужно проверить токен.

if (localStorage.jwtToken) {
  setAuthToken(localStorage.jwtToken);
  const decoded = jwt_decode(localStorage.jwtToken);
  store.dispatch({
    type: USER_LOGIN,
    payload: decoded
  });
}

Надеюсь, это помогло.

От одного новичка в JWT к другому.Удачи.

...