Проблема с настройкой NbAuthJWTInterceptor для надлежащего форматирования токенов JWT - PullRequest
0 голосов
/ 10 июля 2019

Я использую ngx-admin для моего нового приложения.Я использовал инфраструктуру Nebular Auth для использования токенов JWT для обеспечения доступа к внутреннему REST-серверу.

Я могу успешно аутентифицироваться и получать доступ к REST-серверу при использовании Postman для тестирования API путем форматирования заголовка HTTP авторизациис токеном в формате JWT <token>.Проблема с доступом к API из моего приложения на основе ngx-admin заключается в том, что класс NbAuthJWTInterceptor представляет HTTP-заголовок авторизации в формате Bearer JWT <token>, и, следовательно, мой внутренний API не может извлечь токен.

Как настроить или переопределить класс NbAuthJWTInterceptor для установки HTTP-заголовка авторизации в формате JWT <token>?

На стороне клиента я использую:

  • ngx-admin3.2.1
  • угловой 7.2.1
  • nebular / auth 3.4.2

На сервере я использую следующее с MongoDB:

  • экспресс 4.6.13
  • паспорт 0.4.0
  • passport-jwt 4.0.0
  • jsonwebtoken 8.5.1
  • mongoose 5.1.7

Я протестировал различные вызовы (GET, POST, PUT, DELETE) для моего API с помощью токена, который я успешно выполнил, используя Postman, и отформатировал токен авторизации как JWT <token> и запросбыл авторизован и верные данные были возвращены.

Когда мое приложение отправляло те же запросы, класс NbAuthJWTInterceptor форматирует маркер авторизации как Bearer JWT <token>, поэтому запрос отклоняется как «Неавторизованный»

Доступ и декодирование авторизациитокен на стороне сервера REST:

module.exports = function (passport) {
    var opts = {};
    opts.jwtFromRequest = ExtractJwt.fromAuthHeaderWithScheme('JWT');
    opts.secretOrKey = config.secret;

    passport.use(new JwtStrategy(opts, function (jwt_payload, done) {
        User.findOne({
            id: jwt_payload._id        
        }, function (err, user) {
            if (err) {
                return done(err, false);
            }
            if (user) {
                done(null, user);
            } else {
                done(null, false);
            }
        });
    }));
};

Настройка конечных точек API и HTTP-перехватчика для внедрения токена авторизации на стороне клиента:

@NgModule({
    declarations: [AppComponent],
    imports: [
        BrowserModule,
        BrowserAnimationsModule,
        HttpClientModule,
        AppRoutingModule,

        // NbEvaIconsModule,

        NgbModule.forRoot(),
        ThemeModule.forRoot(),
        CoreModule.forRoot(),

        NbAuthModule.forRoot({
            strategies: [
                NbPasswordAuthStrategy.setup({
                    name: 'email',
                    token: {
                        class: NbAuthJWTToken,
                        key: 'token',
                    },

                    baseEndpoint: '/api',
                    login: {
                        endpoint: '/auth/signin',
                        method: 'post',
                    },
                    register: {
                        endpoint: '/auth/signup',
                        method: 'post',
                    },
                    logout: {
                        endpoint: '/auth/sign-out',
                        method: 'post',
                    },
                    requestPass: {
                        endpoint: '/auth/request-pass',
                        method: 'post',
                    },
                    resetPass: {
                        endpoint: '/auth/reset-pass',
                        method: 'post',
                    },
                }),
            ],
            forms: {
                login: formDelaySetting,
                register: formDelaySetting,
                requestPassword: formSetting,
                resetPassword: formSetting,
                logout: {
                    redirectDelay: 0,
                },
            },
        }),

        NbThemeModule.forRoot({ name: 'corporate' }),

        NbToastrModule.forRoot(),

        NbLayoutModule,
    ],
    bootstrap: [AppComponent],
    providers: [
        { provide: APP_BASE_HREF, useValue: '/' }, 
        { provide: HTTP_INTERCEPTORS, useClass: NbAuthJWTInterceptor, multi: true },
        { provide: NB_AUTH_TOKEN_INTERCEPTOR_FILTER, useValue: (req) => { return false; } },
    ],
})

1 Ответ

0 голосов
/ 11 июля 2019

Я закончил копаться во всем коде модуля @Nebular/auth и в итоге нашел виновника. NbAuthJWTInterceptor имеет жестко запрограммированную часть «Bearer» веб-токена. Поэтому мне пришлось клонировать класс и создать, а затем использовать свой собственный HTTP-перехватчик:

import { Inject, Injectable, Injector } from '@angular/core';
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { Observable } from 'rxjs';
import { switchMap } from 'rxjs/operators';
import { NbAuthToken } from '@nebular/auth';
import { NbAuthService } from '@nebular/auth';
import { NB_AUTH_TOKEN_INTERCEPTOR_FILTER } from '@nebular/auth';

@Injectable()
export class NgxAuthJWTInterceptor implements HttpInterceptor {

  constructor(private injector: Injector,
              @Inject(NB_AUTH_TOKEN_INTERCEPTOR_FILTER) protected filter) {
  }

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    // do not intercept request whose urls are filtered by the injected filter
      if (!this.filter(req)) {
        return this.authService.isAuthenticatedOrRefresh()
          .pipe(
            switchMap(authenticated => {
              if (authenticated) {
                  return this.authService.getToken().pipe(
                    switchMap((token: NbAuthToken) => {
                      //const JWT = `Bearer ${token.getValue()}`;  <--- replace this line with the next
                      const JWT = `${token.getValue()}`;
                      req = req.clone({
                        setHeaders: {
                          Authorization: JWT,
                        },
                      });
                      return next.handle(req);
                    }),
                  )
              } else {
                 // Request is sent to server without authentication so that the client code
                 // receives the 401/403 error and can act as desired ('session expired', redirect to login, aso)
                return next.handle(req);
              }
            }),
          )
      } else {
      return next.handle(req);
    }
  }

  protected get authService(): NbAuthService {
    return this.injector.get(NbAuthService);
  }

}
...