web-dev-qa-db-ja.com

Angular2-期限切れの認証トークンを最適に処理する方法は?

私はAngular 2.1.2。

認証トークン(angular2-jwtを使用)があり、有効期限が切れると、webApi呼び出しが401エラーで失敗します。ユーザーが入力データを失うことのないソリューションを探しています。

この401をキャッチして、ログインでモーダルを開くことができます。ユーザーがログインすると、モーダルは消え、入力画面が表示されます。ただし、失敗したリクエストにはエラーが表示されるため、リクエストを再処理する必要があります。ルーターナビゲートの場合、初期データはロードされていません。

ページをリロードできましたが、同じページにrouter.navigateした場合、実際にページをリロードしていないようです。単一ページのアプリで全ページの再読み込みを行いたくありません。現在のページであっても、router.navigateを強制的に実行する方法はありますか?

保存していない新しい入力データは失われるため、再ナビゲートは依然として問題です。

理想的には、ユーザーがモーダルからログインするまで、リクエストは「一時停止」するだけです。私はこれを実装する方法を見つけていません。

何か案は?ベストプラクティスはありますか?

15
Don Chambers

通常、HttpServiceを直接使用する代わりに、自分でHttpを指定します。そのため、実際のHTTPリクエストを送信する前に、独自のget()メソッドを提供して認証を連鎖させることができます。

サービスは次のとおりです。

@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

5
yuxhuang

ログインしてトークンを受け取ったら(私の場合は60分で期限切れになります)、59分が経過したかどうかを毎分チェックする間隔を設定します。はいの場合、ログインダイアログを開きます。

ただし、アイデアは、ログインダイアログはルートではなく、ユーザーがたまたま画面上に開くオーバーレイであるということです(したがって、アプリのルートコンポーネントのhtml内にログインコンポーネントを配置し、アプリ内の任意の場所からログインダイアログを呼び出すためのオブザーバブル)。

ユーザーが正しく再ログインしたら、ログインダイアログを閉じます。ユーザーは、再ログインする前に使用していた画面で楽に進みます。

これが「ベストプラクティス」であるかどうかはわかりませんが、説明している状況では機能します。私に知らせて、コードを作成することができます。

3
brando

理想的には、ユーザーがモーダルからログインするまで、リクエストは「一時停止」するだけです。私はこれを実装する方法を見つけていません。

この例のようにtokenNotExpiredattributeを使用してボタンを切り替えようとしましたか? https://github.com/auth0/angular2-jwt#checking-authentication-to-hideshow-elements-and-ハンドルルーティング

401を防ぐことができます...

3
Karbos 538

ブラウザセッションを使用します。

https://developer.mozilla.org/de/docs/Web/API/Window/sessionStorage

データをJSON文字列として保存し、リクエストが失敗した場合にフォームデータを再作成します。

2
igorzg

リロードは簡単です:(<any>window).location.reload(true);

ログイン/パスワードのポップアップを表示し、ユーザーがパスワードを入力できる場合、ユーザーがキャンセルを押した場合はログインページにリダイレクトするだけで作業を続行できるようにすることをお勧めします。

接続の問題、タイムアウト、サーバーエラーもあります。問題は、Angular 2 Httpモジュールとrxjsを使用して適切な処理を確実に実装することが難しいことです。個人的に、私はHttpモジュールを使用して、エラー処理の設計が不適切で、独自のhttpモジュールを実装しているため、構成可能なエラー処理と透過的な再試行が可能です。

2
kemsky