Как передать JWT через заголовок и получить данные через представления на стороне сервера в Sails.js

Серверная часть: Sails.js

Я уже внедрил JSON Web Token для REST API, где все AJAX-запросы от внешнего интерфейса к действиям различных контроллеров возвращают данные res.json(data); только в том случае, если он получает правильный JWT через заголовок авторизации. Он работает так, как ожидалось.

Теперь я создал представление с помощью EJS с <%= name =>, теперь контроллер имеет детали res.view('/home', {name: "Bill"} ); и настроил маршруты так, чтобы они также указывали на соответствующий контроллер.

Как получить «имя» из контроллера путем аутентификации с помощью уже выпущенного JWT (хранящегося в localStorage) из представления на стороне сервера с атрибутом <%= name =>

Спасибо.

КОД:

просмотры/index.ejs

<%= name =>

API/контроллеры/UsersController.js

info: function(req, res) {

var userId = req.token;

Users.findOne(userId).exec(function(err, profile) {
    if(err) {
    res.json(err);
    } else {
       res.view('index',{
        name: profile.name,
    });
    }
});        
},

API/политики/tokenAuth.js

module.exports = function(req, res, next) {
  var token;

  if (req.headers && req.headers.authorization) {
    var parts = req.headers.authorization.split(' ');
    if (parts.length == 2) {
      var scheme = parts[0],
        credentials = parts[1];

      if (/^Bearer$/i.test(scheme)) {
        token = credentials;
      }
    } else {
      return res.json(401, {err: 'Format is Authorization: Bearer [token]'});
    }
  } else if (req.param('token')) {
    token = req.param('token');
    delete req.query.token;
  } else {
    return res.json(401, {err: 'No Authorization header was found'});
  }

  sailsTokenAuth.verifyToken(token, function(err, token) {
    if (err) return res.json(401, {err: 'Please Logout and Login again!'});

    req.token = token;

    next();
  });
};

API/услуги/sailsTokenAuth.js

var jwt = require('jsonwebtoken');

module.exports.issueToken = function(payload) {
  var token = jwt.sign(payload, process.env.TOKEN_SECRET || "xxxxxxx");
  return token;
};

module.exports.verifyToken = function(token, verified) {
  return jwt.verify(token, process.env.TOKEN_SECRET || "xxxxxxx", {}, verified);
};

конфиг/routes.js

module.exports.routes = {
    '/': {
        controller: 'UsersController',
        action: 'info'
      },
};

РЕШЕНИЕ:

Чтобы использовать JWT в качестве фактора аутентификации от браузера клиента к серверу, можно использовать либо localStorage, либо файл cookie сеанса. Я, наконец, сузил его до использования файла cookie из-за более простой реализации на сервере.

После аутентификации пользователя сохраните JWT в браузере клиентов,

res.cookie('jwttoken', sailsTokenAuth.issueToken(profile.name));

Затем его можно получить с помощью req.cookies.jwttoken и проверить через службу (jwt.verify), чтобы предоставить доступ к запрошенной информации через res.json или res.view.


person Vijay Rajasekaran    schedule 15.01.2016    source источник


Ответы (1)


Не вижу никакого вашего кода, поскольку он не предоставлен, но допустим, что вы настроили пользовательскую политику api/policies/jwt.js и т. д., и там вы проверяете JWTToken по каждому запросу. Что-то вроде (игнорируя любую обработку ошибок для простоты):

module.exports = function (req, res, next) {

    var token = req.headers.authorization.split(' ')[1];
    var payload = jwt.decode(token, config.TOKEN_SECRET);
    req.userId = payload.sub;
    next();
};

Обратите внимание, как я добавил userId к объекту req (req.userId = payload.sub;). Это означает, что в вашем контроллере у вас будет доступ к userId (или, в вашем случае, к любому идентификатору, который вы используете для идентификации вошедшего в систему пользователя и т. д.), так как вы можете просто сослаться на него из входящего объекта req.

Очевидно, что ваша реализация политики JWT может отличаться, но просто настройте ее так, как указано выше. Если вы на самом деле сохранили name в самом токене jwt (не видите свою реализацию), просто добавьте его к объекту req (поиск модели не требуется).

Получив необходимое имя, передайте его в представление (как вы сейчас делаете с жестко заданным значением Bill выше).

Обновление на основе обновленного вопроса

Итак, на основе вашего комментария и обновленного вопроса вам удалось извлечь информацию о профиле из токена JWT и получить необходимую информацию о профиле из поиска модели. Теперь вы не можете отобразить это имя в представлении EJS.

Таким образом, вы можете добиться этого примерно так:

Контроллер:

res.view('index', {
        name: profile.name
    }

Обратите внимание, что я удалил запятую после profile.name ;)

Для config/views.js должно быть задано значение "ejs", если вы используете этот механизм шаблонов.

Остальное выглядит хорошо. По крайней мере, в соответствии с тем, что я ожидал.

Лучше всего либо явно использовать отладчик, либо, по крайней мере, операторы console.log прямо до точки, непосредственно перед возвратом метода controller.info, и убедиться, что profile.name установлено так, как ожидалось. Если вы зайдете так далеко, то поймете, что проблема заключается в маршрутизации для просмотра каким-то образом.

Вы можете попробовать создать подпапку в представлениях, а также переименовать файл представления (индекс немного особенный..). Сделайте что-нибудь вроде views/xxx/yyy.ejs

Также временно закомментируйте свой метод controller.info и замените его чем-то действительно простым, например:

res.view('xxx/yyy', {
            name: 'bob'
        });

Дальнейшее обновление на основе дальнейших отзывов пользователей

Из вашего последнего комментария ваш вопрос постепенно развивается...

Я думаю, что вы сейчас говорите, что весь код Sails работает и доказал свою работу с помощью Postman. Но сбой при использовании клиента веб-браузера, потому что ваш клиентский код не передает правильную информацию о токене в заголовке http.

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

Например. (просто фрагмент, взятый из фабрики Angular authInterceptor, но здесь ничего конкретного для Angular не показано):

 request: function (config) {
      var token = authToken.getToken();

      if (token) {
        config.headers.Authorization = 'Bearer ' + token;
      }

      return config;
    },

Выше, по запросу, JWT извлекается из локального хранилища (которое, как вы говорите, у вас работает), и, если токен существует, информация заголовков http обновляется заголовком авторизации в форме «Токен носителя'.

Я не смотрел ваше репо, и, честно говоря, я чувствую, что уже дал вам МНОГО информации. Основываясь на том, что я предоставил, и, возможно, немного погуглив/проверив, вы сможете получить работающее решение.

person arcseldon    schedule 16.01.2016
comment
Большое спасибо за ваш ответ. Я добавил образцы кода с вопросом. Как вы сказали, я уже внедрил userId в секрет JWT и отлично работает для вызовов REST API. Подобно тому, как клиент/внешний интерфейс запрашивает информацию с заголовком авторизации с токеном JWT, он затем поступает в серверную часть (контроллер/действие) с использованием req.token, который преобразуется в идентификатор пользователя для обработки запрошенной информации. Но что меня смущает, так это то, как получить ту же информацию из представлений на стороне сервера. - person Vijay Rajasekaran; 16.01.2016
comment
Что я на самом деле пытаюсь сделать: 1. Просмотр входа: получить идентификатор пользователя и пароль -> создать JWT -> сохранить его в локальном хранилище браузера пользователей 2. перенаправить на просмотр профиля (только пользователи с действительным JWT могут получить к нему доступ) при доступе с использованием вызовов AJAX , он работает так, как ожидалось, я могу получить информацию с помощью «res.json», но я хотел бы, чтобы он работал с использованием «res.view» вместо использования представлений на стороне сервера без использования запросов AJAX, поскольку эти файлы * .ejs уже находятся на сервере . - person Vijay Rajasekaran; 16.01.2016
comment
Я создал репозиторий: github.com/vijayrajasekaran/sails-auth-jwt. Я могу получить имя: bob в представлении с отключенным JWT с помощью контроллера. Он также работает с включенным JWT, когда я передаю вызов REST API с заголовком авторизации (токен JWT), но не могу понять, как я могу аутентифицировать пользователя после успешного входа в систему и позволить ему просматривать несколько представлений, защищенных JWT, поскольку я не отправляю заголовок авторизации в качестве вызовов REST API для получения запрошенной информации. Когда представление посещается напрямую с помощью localhost/profile, оно отображает заголовок «Нет авторизации». - person Vijay Rajasekaran; 16.01.2016
comment
Scenerio (для репозитория, который я добавил в GitHub): 1. Пользователь имеет JWT в локальном хранилище своего браузера 2. Когда он посещает, localhost :1337/profile 3. Он должен отобразить страницу с именем: smith.. Это отлично работает при выполнении вызовов REST API с вызовами Postman REST Client/jQuery AJAX с заголовком авторизации: Bearer 'token' - person Vijay Rajasekaran; 16.01.2016
comment
@VijayRajasekaran - обновил мой ответ - обратите внимание, у меня не было времени посмотреть ваше репо. Будьте благодарны, если вы могли бы проголосовать за мой ответ / отметить его как правильный, если вы нашли, что информация помогла вам. - person arcseldon; 17.01.2016
comment
Большое спасибо за ваше время, чтобы помочь мне. Ваш ответ был действительно полезен. Чтобы использовать JWT в качестве фактора аутентификации от браузера клиента к серверу, можно использовать либо localStorage, либо файл cookie сеанса. Я, наконец, сузил его до использования файла cookie из-за более простой реализации на сервере. - person Vijay Rajasekaran; 18.01.2016
comment
@VijayRajasekaran - рад, что помог, и рад видеть, что вы используете JWT. Да, для клиентской стороны часто лучше полагаться на библиотеку, которая делает всю тяжелую работу. например, satellizer для angular делает это проще простого — npmjs.com/package/satellizer. Пожалуйста, отметьте мой ответ как правильный, если вы считаете, что он был действительно полезен: D, и удачи в работе над вашим проектом. - person arcseldon; 18.01.2016
comment
Я буду смотреть в него. Большое спасибо. :) - person Vijay Rajasekaran; 18.01.2016