Angular2 - Как лучше всего использовать истекший токен аутентификации?
Я использую Angular 2.1.2.
У меня есть токен аутентификации (с использованием angular2 -jwt), и, если он истекает, мой вызов webApi завершается с ошибкой 401. Я ищу решение, в котором пользователь не потеряет никаких входных данных.
Я могу поймать этот 401 и открыть модаль с логином. Затем пользователь входит в систему, модаль уходит, и они видят экран ввода. Однако неудавшиеся запросы показывают ошибки, поэтому мне нужно перепрограммировать запросы. Если это был переход к маршрутизатору, исходные данные не были загружены.
Я могу перезагрузить страницу, но если я роутер.навигаюсь на той же странице, она, похоже, не перезагружает страницу. Я не хочу делать полную перезагрузку страницы в приложении с одной страницей. Есть ли способ заставить router.navigate работать, даже если это текущая страница?
Повторная навигация по-прежнему является проблемой, потому что я потеряю любые новые входные данные, которые не были сохранены.
В идеале запрос будет просто "приостанавливаться", пока пользователь не войдет в систему из модального. Я не нашел способ реализовать это.
Любые идеи?
Есть ли наилучшая практика?
Ответы
Ответ 1
Обычно я предлагаю HttpService
сам, а не напрямую Http
. Поэтому с вашим требованием я могу предоставить свой собственный метод get()
, чтобы связать аутентификацию перед отправкой любых реальных HTTP-запросов.
Вот сервис:
@Injectable()
class HttpService {
constructor(private http: Http, private auth: Authentication) {}
public get(url: string): Observable<Response> {
return this.auth.authenticate().flatMap(authenticated => {
if (authenticated) {
return this.http.get(url);
}
else {
return Observable.throw('Unable to re-authenticate');
}
});
}
}
Вот компонент для вызова службы:
@Component({
selector: 'my-app',
template: `<h1>Hello {{name}}</h1>
<button (click)="doSomething()">Do Something</button>
<div [hidden]="!auth.showModal">
<p>Do you confirm to log in?</p>
<button (click)="yes()">Yes</button><button (click)="no()">No</button>
</div>
`,
})
export class AppComponent {
name = 'Angular';
constructor(private httpSvc: HttpService, public auth: Authentication) {}
ngOnInit() {
}
doSomething() {
let a = this.httpSvc.get('hello.json').subscribe(() => {
alert('Data retrieved!');
}, err => {
alert(err);
});
}
yes() {
this.auth.confirm.emit(true);
}
no() {
this.auth.confirm.emit(false);
}
}
По цепочке наблюдаемых служба Authentication
определяет, следует ли прерывать нормальный поток, чтобы показать модальный (хотя в настоящее время он живет только с компонентом App, он может быть реализован отдельно). И как только положительный ответ получен из диалога, служба может возобновить поток.
class Authentication {
public needsAuthentication = true;
public showModal = false;
public confirm = new EventEmitter<boolean>();
public authenticate(): Observable<boolean> {
// do something to make sure authentication token works correctly
if (this.needsAuthentication) {
this.showModal = true;
return Observable.create(observer => {
this.confirm.subscribe(r => {
this.showModal = false;
this.needsAuthentication = !r;
observer.next(r);
observer.complete();
});
});
}
else {
return Observable.of(true);
}
}
}
У меня есть полный живой пример здесь.
http://plnkr.co/edit/C129guNJvri5hbGZGsHp?open=app%2Fapp.component.ts&p=preview
Ответ 2
В идеале запрос будет просто "приостанавливаться", пока пользователь не войдет в систему из модального. Я не нашел способ реализовать это.
Вы пытались переключить свою кнопку, используя атрибут tokenNotExpired
, как в этом примере: https://github.com/auth0/angular2-jwt#checking-authentication-to-hideshow-elements-and-handle-routing
Это позволяет вам предотвратить 401...
Ответ 3
Использовать сеанс браузера:
https://developer.mozilla.org/de/docs/Web/API/Window/sessionStorage
Храните данные как строку json и затем создавайте данные формы, если запрос не работает.
Ответ 4
Ну, перезагрузка проста: (<any>window).location.reload(true);
Хорошая идея показать всплывающее окно входа/пароля и разрешить пользователю продолжать работу, если он может предоставить пароль, если пользовательский клик отменяет, просто перенаправляйте страницу входа.
Существуют также проблемы с подключением, тайм-ауты, ошибки сервера. Проблема в том, что трудно надежно реализовать надлежащую обработку с помощью модуля Angular 2 Http
и rxjs
. Лично я отказался от использования модуля Http
, потому что его обработка ошибок имела плохую конструкцию и реализовала мой собственный модуль http, который позволяет настраивать обработку ошибок и прозрачные попытки.
Ответ 5
После того, как я сделаю логин и получаю токен (который в моем случае истекает через 60 минут), я устанавливаю интервал, который проверяет каждую минуту, чтобы проверить, прошло ли 59 минут. Если да, то я открываю диалоговое окно входа в систему.
Идея, однако, заключается в том, что диалоговое окно входа в систему - это не маршрут, а просто оверлей, который открывается поверх любого экрана, на котором находится пользователь (таким образом, я поместил компонент входа в html корневого компонента приложения, и используйте наблюдаемое для вызова диалогового окна входа в систему из любого места приложения).
Когда пользователь правильно заново войдет в систему, я закрою диалоговое окно входа в систему, и пользователь весело идет по пути с каким-либо экраном, который они использовали, прежде чем им пришлось повторно войти в систему.
Я не знаю, является ли это "лучшей практикой", но она работает в ситуации, которую вы описываете. Дайте мне знать, и я могу поместить код.