OAuth2身份验证

npm version Changelog

$ npm install @feathersjs/authentication-oauth2 --save

@feathersjs/authentication-oauth2 is a server side module that allows you to use any Passport OAuth2 authentication strategy within your Feathers application. There are hundreds of them! Some commonly used ones are:

This module contains 2 core pieces:

  1. The main initialization function

  2. The Verifier class

Configuration

在大多数情况下, 初始化模块就像这样做一样简单:

const feathers = require('@feathersjs/feathers');
const authentication = require('@feathersjs/authentication');
const jwt = require('@feathersjs/authentication-jwt');
const oauth2 = require('@feathersjs/authentication-oauth2');
const FacebookStrategy = require('passport-facebook').Strategy;
const app = feathers();

// Setup authentication
app.configure(authentication({ secret: 'super secret' }));
app.configure(jwt());
app.configure(oauth2({
  name: 'facebook',
  Strategy: FacebookStrategy,
  clientID: '<your client id>',
  clientSecret: '<your client secret>',
  scope: ['public_profile', 'email']
}));

// Setup a hook to only allow valid JWTs to authenticate
// and get new JWT access tokens
app.service('authentication').hooks({
  before: {
    create: [
      authentication.hooks.authenticate(['jwt'])
    ]
  }
});

This will pull from your global authentication object in your config file. It will also mix in the following defaults, which can be customized.

Registering the OAuth2 plugin will automatically set up routes to handle the OAuth redirects and authorization.

Options

{
    idField: '<provider>Id', // The field to look up the entity by when logging in with the provider. Defaults to '<provider>Id' (ie. 'facebookId').
    path: '/auth/<provider>', // The route to register the middleware
    callbackURL: 'http(s)://hostname[:port]/auth/<provider>/callback', // The callback url. Will automatically take into account your host and port and whether you are in production based on your app environment to construct the url. (ie. in development http://localhost:3030/auth/facebook/callback)
    successRedirect: undefined,
    failureRedirect: undefined,
    entity: 'user', // the entity that you are looking up
    service: 'users', // the service to look up the entity
    passReqToCallback: true, // whether the request object should be passed to `verify`
    session: false, // whether to use sessions,
    handler: middleware, // Express middleware for handling the oauth callback. Defaults to the built in middleware.
    errorHandler: middleware, // Express middleware for handling errors. Defaults to the built in middleware.
    formatter: middleware, // The response formatter middleware. Defaults to the the built in feathers-rest formatter, handling only JSON.
    Verifier: Verifier, // A Verifier class. Defaults to the built-in one but can be a custom one. See below for details.
    makeQuery: function // Makes query for finding an existing user. Defaults to (profile, options) => ({ [options.idField]: profile.id })
}

Additional passport strategy options can be provided based on the OAuth1 strategy you are configuring.

注解

如果您的api和前端位于不同的域中, 则需要手动设置处理程序以将访问令牌传递回前端应用程序. `请参阅此常见问题<https://docs.feathersjs.com/faq/readme.html#oauth-is-not-setting-the-cookie>`_.

Verifier

这是验证类, 它通过在给定服务上查找实体(通常是“用户”)来处理OAuth2验证, 并创建或更新实体并返回它们.它具有以下可以覆盖的方法.除了 verify 之外, 所有方法都返回一个promise, 它与 passport-oauth2 具有完全相同的签名.

{
    constructor(app, options) // the class constructor
    _updateEntity(entity) // updates an existing entity
    _createEntity(entity) // creates an entity if they didn't exist already
    _normalizeResult(result) // normalizes result from service to account for pagination
    verify(req, accessToken, refreshToken, profile, done) // queries the service and calls the other internal functions.
}

可以扩展 s``Verifier`` 类, 以便您可以自定义它的行为, 而无需重写和测试完全自定义的本地Passport实现.虽然如果您不想使用此插件, 这始终是一个选项.

An example of customizing the Verifier:

import oauth2, { Verifier } from '@feathersjs/authentication-oauth2';

class CustomVerifier extends Verifier {
  // The verify function has the exact same inputs and
  // return values as a vanilla passport strategy
  verify(req, accessToken, refreshToken, profile, done) {
    // do your custom stuff. You can call internal Verifier methods
    // and reference this.app and this.options. This method must be implemented.

    // the 'user' variable can be any truthy value
    // the 'payload' is the payload for the JWT access token that is generated after successful authentication
    done(null, user, payload);
  }
}

app.configure(oauth2({
  name: 'facebook',
  Strategy: FacebookStrategy,
  clientID: '<your client id>',
  clientSecret: '<your client secret>',
  scope: ['public_profile', 'email'],
  Verifier: CustomVerifier
}));

Customizing The OAuth Response

每当您使用OAuth2提供程序(如Facebook)进行身份验证时, 提供程序都会发回一个“accessToken”, “refreshToken”和一个“profile”, 其中包含基于OAuth2“scopes”的经过身份验证的实体信息.你已经要求并获得了批准.

默认情况下, Verifier``接受提供程序返回的所有内容, 并将其附加到提供程序名称下的``entity``(即用户对象).您可能希望自定义返回的数据.这可以通过在``entity 的服务上为``update``和``create``服务方法添加一个``before``挂钩来完成.

app.configure(oauth2({
  name: 'github',
  entity: 'user',
  service: 'users',
  Strategy,
  clientID: 'your client id',
  clientSecret: 'your client secret'
}));

function customizeGithubProfile() {
  return function(context) {
    console.log('Customizing Github Profile');
    // If there is a github field they signed up or
    // signed in with github so let's pull the primary account email.
    if (context.data.github) {
      context.data.email = context.data.github.profile.emails.find(email => email.primary).value;
    }

    // If you want to do something whenever any OAuth
    // provider authentication occurs you can do this.
    if (context.params.oauth) {
      // do something for all OAuth providers
    }

    if (context.params.oauth.provider === 'github') {
      // do something specific to the github provider
    }

    return Promise.resolve(context);
  };
}


app.service('users').hooks({
  before: {
    create: [customizeGithubProfile()],
    update: [customizeGithubProfile()]
  }
});

Client Usage

当该模块是注册服务器端时, 无论您是否使用``feathers-authentication-client``, 用户都必须导航到身份验证策略URL.这可以通过设置``window.location``或通过应用程序中的链接来实现.

例如, 您可能有Facebook的登录按钮:

<a href="/auth/facebook" class="button">Login With Facebook</a>