FeathersJS Auth Recipe: Create Endpoints with Mixed Auth

Auk релиз FeathersJS содержит новый мощный набор authentication suite построенный на основе PassportJS. Он может быть настроен для обработки большинства потребностей аутентификации приложения. В этом руководстве мы рассмотрим наиболее частый сценарий: иногда конечная точка (роут) должна предоставлять разную информацию на основе данных аутентификации пользователя. Например неавторизованный пользователь может просматривать только публичные записи. А авторизованный пользователь может видеть какую-либо дополнительную информацию.

Установка конечной точки Аутентифкации

Для начала создадим рабочую конфигурацию. To get started, we need a working authentication setup. Below is a default configuration and authentication.js. They contain the same code generated by the feathers-cli. You can create the below setup using the following terminal commands:

  1. npm install -g feathers-cli@pre
    or
    yarn global feathers-cli@pre
  2. mkdir feathers-demo-local; cd feathers-demo-local
    or a folder name you prefer.
  3. feathers generate app
    use the default prompts.
  4. feathers generate authentication
    • Select Username + Password (Local) when prompted for a provider.
    • Select the defaults for the remaining prompts.

config/default.json:

{
  "host": "localhost",
  "port": 3030,
  "public": "../public/",
  "paginate": {
    "default": 10,
    "max": 50
  },
  "authentication": {
    "secret": "99294186737032fedad37dc2e847912e1b9393f44a28101c986f6ba8b8bc0eaab48b5b4c5178f55164973c76f8f98f2523b860674f01c16a23239a2e7d7790ae9fa00b6de5cc0565e335c6f05f2e17fbee2e8ea0e82402959f1d58b2b2dc5272d09e0c1edf1d364e9911ecad8172bdc2d41381c9ab319de4979c243925c49165a9914471be0aa647896e981da5aec6801a6dccd1511da11b696d4f6cce3a4534dab9368661458a466661b1e12170ad21a4045ce1358138caf099fbc19e05532336b5626aa376bc158cf84c6a7e0e3dbbb3af666267c08de12217c9b55aea501e5c36011779ee9dd2e061d0523ddf71cb1d68f83ea5bb1299ca06003b77f0fc69",
    "strategies": [
      "jwt",
      "local"
    ],
    "path": "/authentication",
    "service": "users",
    "jwt": {
      "header": {
        "type": "access"
      },
      "audience": "https://yourdomain.com",
      "subject": "anonymous",
      "issuer": "feathers",
      "algorithm": "HS256",
      "expiresIn": "1d"
    },
    "local": {
      "entity": "user",
      "service": "users",
      "usernameField": "email",
      "passwordField": "password"
    }
  },
  "nedb": "../data"
}

src/authentication.js:

'use strict';

const authentication = require('feathers-authentication');
const jwt = require('feathers-authentication-jwt');
const local = require('feathers-authentication-local');

module.exports = function () {
  const app = this;
  const config = app.get('authentication');

  app.configure(authentication(config));
  app.configure(jwt());
  app.configure(local(config.local));

  app.service('authentication').hooks({
    before: {
      create: [
        authentication.hooks.authenticate(config.strategies)
      ],
      remove: [
        authentication.hooks.authenticate('jwt')
      ]
    }
  });
};

Set up a “Mixed Auth” Endpoint

Установка конечной точки для "Смешанной авторизации"

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

{
  id: 1,
  email: '[email protected]'
  password: "password",
  public: true
}

Если user содержит public: true, то неаутентифицированые пользователи могут получить доступ к этой записи (просматривать её). Посмотрим как это сделать используя условия iff и else (из feathers-hooks-common) в хуках. Не забудьте познакомится с iff hook API docs и else hook API docs если еще не сделали этого.

Будем использовать iff хук чтобы аутентифицировать только пользователей в запросах которых есть токен. Плагин feathers-authentication-jwt, который мы используем, содержит возможность получить токен из запроса. Если запрос содержит токен, он будет автоматически доступен в объекте hook по ключу hook.params.token.

src/services/users/users.hooks.js

(Это пример показывает работу только с хуками метода find)

'use strict';

const { authenticate } = require('feathers-authentication').hooks;
const commonHooks = require('feathers-hooks-common');

module.exports = {
  before: {
    find: [
      // Если токен включен, аутентифицируем его со стратегией `jwt`
      commonHooks.iff(
        hook => hook.params.token,
        authenticate('jwt')
        // Если токена нет, устанавливаем ограничение в запросе `public: true`
      ).else( hook => Object.assign(hook.params.query, { public: true }) )
    ]
  }
};

Разберем пример подробнее. Мы настроили метод find сервиса /users c использованием условия iff в хуке before:

iff(
  hook => hook.params.token,
  authenticate(‘jwt’)
)

Для данного приложения, код примера вверху равнозначен коду ниже

hook => {
  if (hook.params.token) {
    return authenticate(‘jwt’)
  } else {
    return Promise.resolve(hook)
  }
}

На самом деле хук iff более эффективен, чем пример выше. It can handle an async predicate expression. This would be equivalent to being able to pass a promise inside the if statement's parentheses. It also allows us to chain an .else() statement, which will run if the predicate evaluates to false.

.else( hook => Object.assign(hook.params.query, { public: true }) )

The above statement simply adds public: true to the query parameters. This limits the query to only find user records that have the public property set to true.

Wrapping Up

With the above code, we’ve successfully setup a /users service that responds differently to unauthenticated and authenticated users. We used the hook.params.token attribute to either authenticate a user or to limit the search query to only public users. If you become familiar with the Common Hooks API, you’ll be able to solve almost any authentication puzzle.

results matching ""

    No results matching ""