Strongloop/loopback 4:如何通过REST禁用资源管理器组件的认证?

Strongloop/loopback 4: how to disable authentication for Explorer component over REST?

我已通过 @loopback/authentication 关注并设置 但是所有调用的身份验证都添加到 sequence.ts。 我无法跳过 Explorer component

的身份验证

我的开源代码库:opencommerce/questionnaire-server

详情:




    import {BootMixin} from '@loopback/boot';
      import {ApplicationConfig} from '@loopback/core';
      import {
        RestExplorerBindings,
        RestExplorerComponent,
      } from '@loopback/rest-explorer';
      import {RepositoryMixin} from '@loopback/repository';
      import {RestApplication} from '@loopback/rest';
      import {ServiceMixin} from '@loopback/service-proxy';
      import {
        AuthenticationComponent,
        AuthenticationBindings,
      } from '@loopback/authentication';
      import {MyAuthStrategyProvider} from './providers';
      import * as path from 'path';
      import {MySequence} from './sequence';

      export class QuestionnaireApplication extends BootMixin(
        ServiceMixin(RepositoryMixin(RestApplication)),
      ) {
        constructor(options: ApplicationConfig = {}) {
          super(options);

          // Set up the custom sequence
          this.sequence(MySequence);

          // Set up default home page
          this.static('/', path.join(__dirname, '../../public'));

          // Customize @loopback/rest-explorer configuration here
          this.bind(RestExplorerBindings.CONFIG).to({
            path: '/explorer',
          });
          this.component(RestExplorerComponent);

          this.projectRoot = __dirname;

          this.component(AuthenticationComponent);
          this.bind(AuthenticationBindings.STRATEGY).toProvider(
              MyAuthStrategyProvider,
          );

          // Customize @loopback/boot Booter Conventions here
          this.bootOptions = {
            controllers: {
              // Customize ControllerBooter Conventions here
              dirs: ['controllers'],
              extensions: ['.controller.js'],
              nested: true,
            },
          };
        }
      }




    import {inject} from '@loopback/context';
      import {
        FindRoute,
        InvokeMethod,
        ParseParams,
        Reject,
        RequestContext,
        RestBindings,
        Send,
        SequenceHandler,
      } from '@loopback/rest';
      import {AuthenticationBindings, AuthenticateFn} from '@loopback/authentication';

      const SequenceActions = RestBindings.SequenceActions;

      export class MySequence implements SequenceHandler {
        constructor(
          @inject(SequenceActions.FIND_ROUTE) protected findRoute: FindRoute,
          @inject(SequenceActions.PARSE_PARAMS) protected parseParams: ParseParams,
          @inject(SequenceActions.INVOKE_METHOD) protected invoke: InvokeMethod,
          @inject(SequenceActions.SEND) public send: Send,
          @inject(SequenceActions.REJECT) public reject: Reject,
          @inject(AuthenticationBindings.AUTH_ACTION)
          protected authenticateRequest: AuthenticateFn,
        ) {}

        async handle(context: RequestContext) {
          try {
            const {request, response} = context;
            const route = this.findRoute(request);

            // This is the important line added to the default sequence implementation
            await this.authenticateRequest(request);

            // Authentication successful, proceed to invoke controller
            const args = await this.parseParams(request, route);
            const result = await this.invoke(route, args);
            this.send(response, result);
          } catch (err) {
            this.reject(context, err);
          }
        }
      }

访问 / 时出错。

Unhandled error in GET /: 500 Error: The key controller.current.ctor was not bound to any value.
at QuestionnaireApplication.getBinding (/opt/lampp7.2/htdocs/opencommerce/questionnaire-server/node_modules/@loopback/context/dist/src/context.js:225:15)
at RestServer.getBinding (/opt/lampp7.2/htdocs/opencommerce/questionnaire-server/node_modules/@loopback/context/dist/src/context.js:221:33)
at RequestContext.getBinding (/opt/lampp7.2/htdocs/opencommerce/questionnaire-server/node_modules/@loopback/context/dist/src/context.js:221:33)
at RequestContext.getValueOrPromise (/opt/lampp7.2/htdocs/opencommerce/questionnaire-server/node_modules/@loopback/context/dist/src/context.js:260:30)
at resolution_session_1.ResolutionSession.runWithInjection.s (/opt/lampp7.2/htdocs/opencommerce/questionnaire-server/node_modules/@loopback/context/dist/src/resolver.js:73:24)
at value_promise_1.tryWithFinally (/opt/lampp7.2/htdocs/opencommerce/questionnaire-server/node_modules/@loopback/context/dist/src/resolution-session.js:89:53)
at Object.tryWithFinally (/opt/lampp7.2/htdocs/opencommerce/questionnaire-server/node_modules/@loopback/context/dist/src/value-promise.js:162:18)
at Function.runWithInjection (/opt/lampp7.2/htdocs/opencommerce/questionnaire-server/node_modules/@loopback/context/dist/src/resolution-session.js:89:32)
at resolve (/opt/lampp7.2/htdocs/opencommerce/questionnaire-server/node_modules/@loopback/context/dist/src/resolver.js:66:59)
at value_promise_1.resolveList (/opt/lampp7.2/htdocs/opencommerce/questionnaire-server/node_modules/@loopback/context/dist/src/resolver.js:144:16)
at Object.resolveList (/opt/lampp7.2/htdocs/opencommerce/questionnaire-server/node_modules/@loopback/context/dist/src/value-promise.js:135:32)
at resolveInjectedArguments (/opt/lampp7.2/htdocs/opencommerce/questionnaire-server/node_modules/@loopback/context/dist/src/resolver.js:128:28)
at Object.instantiateClass (/opt/lampp7.2/htdocs/opencommerce/questionnaire-server/node_modules/@loopback/context/dist/src/resolver.js:37:27)
at Binding._getValue (/opt/lampp7.2/htdocs/opencommerce/questionnaire-server/node_modules/@loopback/context/dist/src/binding.js:338:50)
at resolution_session_1.ResolutionSession.runWithBinding.s (/opt/lampp7.2/htdocs/opencommerce/questionnaire-server/node_modules/@loopback/context/dist/src/binding.js:189:90)
at value_promise_1.tryWithFinally (/opt/lampp7.2/htdocs/opencommerce/questionnaire-server/node_modules/@loopback/context/dist/src/resolution-session.js:69:53)

您可能遇到的一个问题是您在设置序列后绑定了值。然后,当 Loopback 尝试解析它们时,绑定不存在。你应该放更多这样的东西:

      this.bind(RestExplorerBindings.CONFIG).to({
        path: '/explorer',
      });
      this.component(RestExplorerComponent);

      this.component(AuthenticationComponent);
      this.bind(AuthenticationBindings.STRATEGY).toProvider(
          MyAuthStrategyProvider,
      );

      this.sequence(MySequence);

您的自定义序列不会跳过静态路由的身份验证 /。 可以跳过auth如下:

if (!(route instanceof StaticAssetsRoute)) {
  // do your login stuff here
}

现在更新后的 sequence.ts 将是:

import {inject} from '@loopback/context';
import {
  FindRoute,
  InvokeMethod,
  ParseParams,
  Reject,
  RequestContext,
  RestBindings,
  Send,
  SequenceHandler,
  StaticAssetsRoute,
} from '@loopback/rest';
import {AuthenticationBindings, AuthenticateFn} from '@loopback/authentication';

const SequenceActions = RestBindings.SequenceActions;

export class MySequence implements SequenceHandler {
  constructor(
    @inject(SequenceActions.FIND_ROUTE) protected findRoute: FindRoute,
    @inject(SequenceActions.PARSE_PARAMS) protected parseParams: ParseParams,
    @inject(SequenceActions.INVOKE_METHOD) protected invoke: InvokeMethod,
    @inject(SequenceActions.SEND) public send: Send,
    @inject(SequenceActions.REJECT) public reject: Reject,
    @inject(AuthenticationBindings.AUTH_ACTION)
    protected authenticateRequest: AuthenticateFn,
  ) {}

  async handle(context: RequestContext) {
    try {
      const {request, response} = context;
      const route = this.findRoute(request);

      // This is the important line added to the default sequence implementation
      if (!(route instanceof StaticAssetsRoute)) {
        await this.authenticateRequest(request);
      }

      // Authentication successful, proceed to invoke controller
      const args = await this.parseParams(request, route);
      const result = await this.invoke(route, args);
      this.send(response, result);
    } catch (err) {
      this.reject(context, err);
    }
  }
}

我正在使用以下内容来确定路由是否是静态的。

private static isStaticRoute(route: ResolvedRoute): boolean {
  return route.path.search(/^\/explorer\/*/) === 0;
}