2017-02-27 11 views
1

背景 -Auth0サービス利用

私は最近、私の作業のアプリを取って、lazy loadingを使用するように変換します。既存のアプリに問題はなく、authenticationにはAuth0を使用しています。私がアプリケーションを実行するとlazy loadingに変換された後、すべてが正常に動作するように見えます。 1つの問題を除いて。

問題 -

私はアプリは、通常のように続けてAuth0 widgetからログインをクリックしてください。しかし、2つの事のうちの1つが起こります。

  1. Login作品のユーザーはauthenticationです。
  2. Loginはエラーなしで失敗します。 失敗すると、auth0に転送され、トークンをローカルストレージに保存せずにホームページにすばやくリダイレ​​クトされます。

ログインして10回連続してログインできます。 1つのログインが機能し、10回中に9回失敗します。エラーメッセージや警告は表示されません。私はこの問題を解決する方法を考え出すこともできません。時にはうまくいき、うまくいかないときに何も変わって失敗するためです。

物事は私が試してみた -

  1. lazy loadingを使用していないアプリケーションを実行しました。 完全に動作する

  2. 別のコンピュータからレイジーローディングアプリを実行します。 問題が存在します。

  3. 再起動したサーバー。 問題が存在する

  4. コールバックURLが変更されました。

    誰もがこの問題を解決するために巧妙な方法を知ってい - 問題は

質問が存在しますか? 誰かがこのようなことが起こる原因を知っていますか?

コード例

app.module.ts

/* Routing Module */ 
import { AppRoutingModule } from './app-routing.module'; 

// Shared Stuff 
import { SharedModule } from './shared/shared.module'; 

//Page Modules 
import { HomeModule } from './home/home.module'; 

@NgModule({ 
    declarations: [ 
    AppComponent 
    ], 
    imports: [ 
    BrowserModule, 
    HttpModule, 
    AppRoutingModule, 
    HomeModule, 
    SharedModule 
    ], 
    providers: [], 
    bootstrap: [AppComponent] 
}) 
export class AppModule { } 

APP-routing.module.ts

import { NgModule }    from '@angular/core'; 
import { Routes, RouterModule } from '@angular/router'; 
import { ApiKeyGuard }   from "./shared/services/api.key.guard.service"; 
import { ProfileGuard }   from "./shared/services/profile.guard.service"; 

const routes: Routes = [ 
    { path: '', redirectTo: '/home', pathMatch: 'full' }, 
    { path: 'benefits', loadChildren: './benefits/benefits.module#BenefitsModule' }, 
    { path: 'fcra', loadChildren: './fcra/fcra.module#FcraModule' }, 
    { path: 'croa', loadChildren: './croa/croa.module#CroaModule' }, 
    { path: 'tips', loadChildren: './tips/tips.module#TipsModule' }, 
    { path: 'maintenance', loadChildren: './maintenance/maintenance.module#MaintenanceModule' }, 
    { path: 'verify-email', loadChildren: './verify-email/verify-email.module#VerifyEmailModule' }, 
{ path: 'profile', canActivate: [ProfileGuard], loadChildren: './profile/profile.module#ProfileModule' }, 
    { path: 'recommendations', canActivate: [ApiKeyGuard], loadChildren: './recommendations/recommendations.module#RecommendationsModule' } 
]; 

@NgModule({ 
    imports: [RouterModule.forRoot(routes)], 
    exports: [RouterModule], 
}) 

export class AppRoutingModule { } 

/shared/shared.module.ts

import { NgModule } from '@angular/core'; 
import { CommonModule } from '@angular/common'; 

//Services 
import { ApiKeyGuard }      from './services/api.key.guard.service'; 
import { ProfileGuard }      from './services/profile.guard.service'; 
import { Auth }        from './services/auth.service'; 


@NgModule({ 
    imports: [ 
     CommonModule, 
     RouterModule, 
     FormsModule, 
     ReactiveFormsModule, 
     CollapseModule, 
     ChartsModule, 
     TabsModule.forRoot(), 
     ToastyModule.forRoot(), 
     SignaturePadModule, 
    ], 
    declarations: [ 
     HeaderComponent, 
     BreadcrumbsComponent, 
     FooterComponent, 
     LsideComponent, 
     RsideComponent, 
     NAV_DROPDOWN_DIRECTIVES, 
     SIDEBAR_TOGGLE_DIRECTIVES, 
     AsideToggleDirective 
    ], 
    providers: [ 
      ApiKeyGuard, 
     ProfileGuard, 
     Auth 
     ], 
    exports: [ 
     CommonModule, 
     FormsModule, 
     ReactiveFormsModule, 
     RouterModule, 
     HeaderComponent, 
     BreadcrumbsComponent 
     ] 
}) 
export class SharedModule { } 

ブレッドクラムは、共有ディレクトリに存在する共有コンポーネントです。このコンポーネントは、ウェブサイトに表示されるすべてのページにレンダリングされ、app.component.tsapp.component.htmlに挿入されます。

認証サービスは、ブレッドクラムコンポーネントに注入されます。

import { Component }        from '@angular/core'; 
import { Router, ActivatedRoute } from '@angular/router'; 
import { Auth }      from './../services/auth.service'; 

@Component({ 
    selector: 'breadcrumbs', 
    templateUrl: './breadcrumb.component.html' 
}) 
export class BreadcrumbsComponent { 
    constructor(private router:Router, private route:ActivatedRoute, private auth: Auth) {} 
    ngOnInit(): void { } 
} 

auth.serviceのログイン機能は、breadcrumb.component.htmlファイルで呼び出されます。

breadcrumb.component.html

<a class="nav-link" (click)="auth.login()" *ngIf="!auth.authenticated()">Login/SignUp</a> 

認証サービス

import { Injectable }      from '@angular/core'; 
import { tokenNotExpired, JwtHelper }  from 'angular2-jwt'; 
import { Router }       from '@angular/router'; 
import { myConfig }      from './auth.config'; 
import {Http, Response, Headers, URLSearchParams}   from '@angular/http'; 
import { User }       from './../models/user'; 
import { LogReg }       from './../models/logreg'; 
import { STATICS }       from './../static/static'; 

declare var Auth0Lock: any; 

var options = { 
    theme: { 
    logo: 'assets/img/logo.png', 
    primaryColor: '#779476' 
    }, 
    languageDictionary: { 
    emailInputPlaceholder: "[email protected]", 
    title: "Login or SignUp" 
    }, 
}; 

@Injectable() 
export class Auth { 
    lock = new Auth0Lock(myConfig.clientID, myConfig.domain, options, {}); 
    userProfile: Object; 
    logreg: LogReg; 
    user: User; 

    constructor(private router: Router, private http: Http) { 

    this.userProfile = JSON.parse(localStorage.getItem('profile')); 
    this.user = JSON.parse(localStorage.getItem('user')); 
    this.lock.on('authenticated', (authResult: any) => { 
     localStorage.setItem('access_token', authResult.idToken); 
     this.lock.getProfile(authResult.idToken, (error: any, profile: any) => { 
     if (error) { 
      console.log(error); 
      return; 
     } 

      // Login Or Register User On Our Server 
     this.logreg = new LogReg(profile.email_verified, profile.email); 

     this.checkRegister(this.logreg).subscribe(
      (res)=>{ 
       console.log("Hey this runs"); 
       console.log(res); 
       if (res.email_verified === false) { 
       localStorage.removeItem('profile'); 
       localStorage.removeItem('api_key'); 
       localStorage.removeItem('access_token'); 
       localStorage.removeItem('user'); 
       this.userProfile = null; 
       this.user = null; 
       this.router.navigate(['/verify-email']); 

       } 
      else if (res.api_key_exist === false) { 
        console.log("Hey this works") 
       localStorage.setItem('profile', JSON.stringify(profile)); 
       this.userProfile = profile; 
       console.log(this.userProfile); 
       this.user = new User(profile.email, '', '', '', '', '', '', '', '', '', '', res.api_key_exist, '') 
       localStorage.setItem('user', JSON.stringify(this.user)); 
       this.router.navigate(['/profile']); 

      } else if (res.api_key_exist === true) { 
       this.user = new User(res.user.email, 
        res.user.first_name, 
        res.user.middle_name, 
        res.user.last_name, 
        res.user.dob, 
        res.user.phone, 
        res.user.street_address, 
        res.user.city_address, 
        res.user.state_address, 
        res.user.zip_address, 
        res.user.client_ss, 
        res.api_key_exist, 
        res.api_key); 
       console.log(this.user); 
       localStorage.setItem('api_key', JSON.stringify(res.api_key)); 
       localStorage.setItem('user', JSON.stringify(this.user)); 
       localStorage.setItem('profile', JSON.stringify(profile)); 
       this.router.navigate(['/overview']); 
      } 
     }, 
      (err)=>{ console.log(err);} 

     ); 
     }); 
     this.lock.hide(); 
    }); 
    } 

    public checkRegister(model: LogReg) { 
     // Parameters obj- 
     let params: URLSearchParams = new URLSearchParams(); 
     params.set('email', model.email); 
     params.set('email_verified', model.email_verified); 

     return this.http.get(STATICS.API_BASE + STATICS.API_LOGIN, 
      { search: params }).map((res:Response) => res.json()); 
     } 

    public login() { 
    this.lock.show(); 
    } 

    private get accessToken(): string { 
     return localStorage.getItem('access_token'); 
    } 

    private get apiKey(): string { 
     var apiKey = JSON.parse(localStorage.getItem('api_key')); 
     return apiKey 
    } 

    public authenticated(): boolean { 
    try { 
     var jwtHelper: JwtHelper = new JwtHelper(); 
     var token = this.accessToken; 
     if (jwtHelper.isTokenExpired(token)) 
      return false; 
     return true; 
    } 
    catch (err) { 
     return false; 
    } 
    } 

    public logout() { 
    var apiKeyExist = this.user.api_key_exist; 
    console.log(apiKeyExist); 
    if (apiKeyExist === true) { 
     let params: URLSearchParams = new URLSearchParams(); 
     params.set('email', this.user.email); 
     params.set('api_key', this.apiKey); 

     localStorage.removeItem('profile'); 
     localStorage.removeItem('api_key'); 
     localStorage.removeItem('access_token'); 
     localStorage.removeItem('user'); 
     this.userProfile = null; 
     this.user = null; 
     this.router.navigateByUrl('/home'); 

     return this.http.get(STATICS.API_BASE + STATICS.API_LOGOUT, 
     { search: params }) 
     .map((res: Response) => res.json()) 
     .subscribe((res) => { 
      console.log(res); 
      this.user = null; 
      console.log(this.user); 
     }); 
    } else { 
     localStorage.removeItem('profile'); 
     localStorage.removeItem('api_key'); 
     localStorage.removeItem('access_token'); 
     localStorage.removeItem('user'); 
     this.userProfile = null; 
     this.user = null; 
     this.router.navigateByUrl('/home'); 
    } 
    }; 
} 

******************** UPDATE **** ******************** shared.module.tsでは私は変更を加えました。

私は今、私は成功した行に5回ログインし、アウトすることができた、ファイルの一番下にこれに

export class SharedModule { 
    static forRoot(): ModuleWithProviders { 
    return { 
     ngModule: SharedModule, 
     providers: [Auth] 
    }; 
    } 
} 

をエクスポートを変更しました。しかし、auth0レスポンスから提供されるユーザーのイメージは表示されません。私は今、ちょっとglitchyなのかどうか疑問に思っています。なぜなら、forRootとforChildを適切な場所に指定する必要があるからです。

上記のコードで見られるアプリケーションのルートにあるapp-routing.moduel.tsファイル内のすべてのルートを指定しています。

遅延ロードされている各モジュールにはルートファイルがあります。ここでforChildがRouterModule上にあることを

import { NgModule } from '@angular/core'; 
import { Routes, RouterModule } from '@angular/router'; 
import { HomeComponent } from './home.component'; 

const routes: Routes = [ 
    { path: '', redirectTo: 'home', pathMatch: 'full'}, 
    { path: 'home', component: HomeComponent } 
]; 

@NgModule({ 
    imports: [RouterModule.forChild(routes)], 
    exports: [RouterModule], 
}) 
export class HomeRoutingModule {} 

お知らせ

家庭routing.module.tsを提出ホームルートの一例です。

これは正しく設定されていますか?また、すべてのモジュールにshared.module.tsを追加するだけでいいですか?

+0

から、あなたの遅延ロードがあなたのルーティングに設定されている方法についていくつかの小さなコードスニペットを提供してくださいすることができている、とどこがあなたの認証サービスをインポートまたは提供?あなたのバージョンの角度とルータを含めてください。 また、ケース2でエラーが発生してもエラーが発生しても、具体的に何が起こっているのか詳しく教えてください。あなたはAuth0によってリダイレクトされていませんか、トークンを取得していませんか?**どのように「失敗する」ように見えますか?** – jgranstrom

+0

質問どおりに質問を更新しました。私は2番のシナリオに説明を追加し、プロセスを説明するすべてのコードを追加しました。これを理解するのを助けることができれば、私はそれを感謝します。私はそれをトラブルシューティングする方法を見つけることさえできません。私はauthサービスのconsole.logです。ログインが有効になると、console.logが機能します。ログインが機能しない場合、console.logは出力されません。時にはauthserviceが動作し、時にはauthserviceが動作しないことがあります。 – wuno

+0

authとlazy-loadingの接続が表示されません。あなたのコードから 'Auth'サービスが(SharedModuleを介して)熱心に読み込まれるように見えるので、*他の*モジュールを遅れて読み込むことによって影響を受けるべきではありません。 ** Auth関連のタスク**がAuthサービス**内で実行され**、このサービスが遅延ロードされていないことを確認できますか? – AngularChef

答えて

0

あなたが実際にリダイレクトしてもトークンを保存していないと言っているので、あなたのAuthサービスが初期化されていないアプリケーションでAuth0リダイレクトがいくつかのページに行くという理論があります。ルーティングによってトークンフラグメントがクリアされていることを示します。

角度がクライアントサイドルーティングであるため、Auth0リダイレクトは、デフォルトで現在の表示可能なURLに常に向いているとは限りませんが、最後の完全なナビゲーションが可能性が高くなります。場合によっては"/"のようなテストをしていて、ルートルート上で直ちにリダイレクトが行われるため、フラグメントとして渡されたトークンは角で消去されるため、Authサービスでは検出されないことがあります。

2つのことを試すことができます。提案されたソリューションを個別にテストし、組み合わせてテストします。 Auth0は、取得したトークンでリダイレクトする必要がどこ

1.

は、明示的に指定する 私はあなたがこの最初の

// in your Auth service 
var options = { 
    theme: { 
    logo: 'assets/img/logo.png', 
    primaryColor: '#779476' 
    }, 
    languageDictionary: { 
    emailInputPlaceholder: "[email protected]", 
    title: "Login or SignUp" 
    }, 
    auth: {        // Added 
    redirectUrl: window.location.href, // Added 
    responseType: 'token',    // Added 
    }         // Added 
}; 

2を試してみてくださいお勧めします。lock.on('authenticated', ..)のリスナーをルーターの変更をリッスンして置き換えます。

認証サービスコンストラクターで、認証されたイベントリスナーを次のものに置き換えます。 authResultを取得する際には、追加のロジックを含めることを忘れないでください。

constructor(private router: Router, private http: Http) { 
    /*...*/ 

    router 
    .events 
    .filter(event => event.constructor.name === 'NavigationStart') 
    .filter(event => (/access_token|id_token|error/).test(event.url)) 
    .subscribe(() => { 
     this.lock.resumeAuth(window.location.hash, (error, authResult) => { 
     if (error) return console.log(error); 
      localStorage.setItem('id_token', authResult.idToken); 
      // TODO: Add the logic you currently have in the authenticated listener 
     }); 
    }); 

    /*...*/ 
} 

第二の例は、ストレートAngular 2 Auth0 docs

+0

私を助ける時間をとってくれてありがとう、ありがとう。私はあなたの提案を試みたが、同じ問題が続く。私はすべてのロジックを取り除き、トークンを保存しようとしています。 Mabeがそれを1行ずつ実行すると、問題が明らかになります。私が頭を抱えることができないのは、これが怠惰な読み込みの前に完全に機能していて、今はそうでない理由です。それとも20日に1回働くのが最悪なのですか。 – wuno

+0

私は巨大な突破口を作りました。幸いにも。あなたは私の質問の最後を読んで、アップデートをどこに追加したのですか? – wuno