Советы по Angular 7 и CAS аутентификации? - PullRequest
1 голос
/ 12 апреля 2019

На самом деле я пытаюсь понять, как именно все должно работать, на самом деле логика аутентификации такова.

1) Пользователь заходит в угловое приложение, нажимает кнопку входа и получает перенаправление, чтобы войти в систему.с шаблоном URL, подобным этому, с моим угловым приложением в качестве параметра: cas-example.com/login?service=my-angular-app

2) Если пользователь входит в систему, перенаправьте в угловое приложение сбилет службы в URL-адресе должен выглядеть следующим образом: my-angular-app.com/?ticket=ST-1232431

3) После того, как я отправлю билет в свой бэкэнд и если билет действителен,backend отправьте мне jwt, где я могу войти в систему пользователя

Этот подход хорош?как мне реализовать прослушиватель из тикета, должен ли я проверить, происходит ли перенаправление с cas и проверить URL, или всегда проверять URL?

Это последовательность операций cas: enter image description here

1 Ответ

0 голосов
/ 12 апреля 2019

Сложно быть конкретным, но я постараюсь дать вам несколько советов о том, как обрабатывать аутентификацию в Angular.

Некоторые инструменты, поставляемые с Angular, которые я сосредоточил на этой теме: APP_INITIALIZER ( статья на нем - потому что документы скудны), HttpInterceptor , LoadingComponent или просто типичный AppComponent.

Некоторые зависимости, которые также помогаютЯ в этом процессе ngx-store и ngxs store .Несмотря на сходные названия, они являются разными инструментами.

Я не собираюсь давать вам полный ответ на вашу проблему, но некоторые подсказки:

В службе аутентификации вы можете, например, зарегистрироватьсяобратный вызов для прослушивания изменения определенного файла cookie (благодаря ngx -store).Примерно так:

constructor(public cookiesStorageService: CookiesStorageService,
          @Inject(JWT_COOKIE_NAME) private _JWT_COOKIE_NAME: string) {
this.cookiesStorageService
  .observe(this._JWT_COOKIE_NAME)
  .subscribe((cookie: NgxStorageEvent) => this.checkIfNewToken(cookie.newValue));

} ​​

Обратите внимание, что выше вводится имя файла cookie для токена JWT.Я нахожу это более понятным и придерживаюсь угловых принципов:

export const JWT_COOKIE_NAME = new InjectionToken<string>('ACTUAL_JWT_COOKIE_NAME');

В случае выше, если вы передаете токен JWT через куки (не заголовок аутентификации).Если вы передадите заголовок с токеном, вы можете сделать что-то вроде перехвата HTTP-запросов.Что-то вроде:

@Injectable()
export class AuthenticationInterceptor implements HttpInterceptor {

    constructor(private tokenExtractor: HttpXsrfTokenExtractor,
          private authService: AuthenticationService,
          @Inject(API_ENDPOINT) private _API_ENDPOINT: string) {
    }

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

    if (req.url.match(this._API_ENDPOINT)) {
        // this.authService.intercept$.next(req);

        const XSRFTokenHeaderName = 'X-XSRF-TOKEN';
        const XSRFToken = this.tokenExtractor.getToken() as string;
        if (XSRFToken !== null && !req.headers.has(XSRFTokenHeaderName)) {
          req = req.clone({headers: req.headers.set(XSRFTokenHeaderName, XSRFToken)});
        }

        req = req.clone();

        return next.handle(req);
      } else {
        return next.handle(req).map(event => {
          if (event instanceof HttpResponse) {
              // do something with response like sending it to an authentication service
          }         
          return event;
      });
      }
    }
  }

Я оставляю канонический пример обработки X-XSRF-TOKEN.

Инициализатор приложения может сделать что-то вроде отправки действия входа в систему - или фактически вызвать напрямую службу аутентификации.метод (мне нравится использовать хранилище ngxs для такого рода вещей):

export function appRun(store: Store) {
  return () =>
    store
      .dispatch(new Login())
      .pipe(finalize(() => true)) // let the app handle errors after bootstrapped
      .toPromise();
    }

И в компоненте загрузки или компоненте приложения есть что-то вроде этого:

constructor(
    private router: Router,
    private actions$: Actions
) {}

ngOnInit() {

    this.actions$
      .pipe(ofActionErrored(Login))
      .subscribe(() => this.router.navigate([Routes.PUBLIC]));

    this.actions$
      .pipe(ofActionSuccessful(Logout))
      .subscribe(() => this.router.navigate([Routes.PUBLIC]));
 }

NGXS поставляется сполезные обработчики успеха или действия с ошибкой, которые можно использовать для маршрутизации куда-либо (вышеприведенные маршруты определены в Enum).

Так что я оставляю много шагов из этого ответа (например, объявление состояний, регистрация APP_INITIALIZER), Перехватчик, ...) но не стесняйтесь, если вы полагаете, что это помогает комментировать для получения дополнительной информации.Упомянутые библиотеки очень мощные и могут помочь вам решить вашу проблему по-разному (или могут оказаться просто накладными расходами - просто служба для хранения некоторого состояния и перехватчика может быть достаточно).Это не очень конкретно, но я думаю, что это хороший набор советов, которые помогут вам.

edit: я забыл про охранников маршрута.Они также могут помочь с аутентификацией в угловых.CanLoad (для лениво загруженных модулей) и, в частности, CanActivate.Что-то вроде:

canActivateRead(): Observable<boolean> | boolean {
    const perm = this.store.selectSnapshot(state => state.module.acl);
    if (perm) {
      return this.canRead(perm);
    } else {
      return this.fetchACLAndTestPermission('READ');
    }
}

private fetchACLAndTestPermission(perm: 'READ' | 'CREATE' | 'UPDATE'): Observable<boolean> {
    return this.authService.getPermissionForACL('ACL').pipe(
      tap(permission => this.store.dispatch(new SetMainACL({ permission }))),
      map(perm => this.canRead(perm)),
      tap(isPermitted => (isPermitted ? isPermitted : this.feedback.notAllowed()))
);

}

И вы можете унаследовать в службу охраны:

@Injectable({
  providedIn: 'root'
})
export class ParameterBaseGuard extends ParameterGuards implements CanLoad {
  constructor(public authService: AuthenticationService, public feedback: FeedbackService, public store: Store) {
    super(authService, feedback, store);
  }
  canLoad(): Observable<boolean> | Promise<boolean> | boolean {
    return this.fetchACLAndTestPermission('READ');
  }
  canActivate(): Observable<boolean> | Promise<boolean> | boolean {
    return this.canActivateRead();
  }
}
...