2017-02-27 41 views
1

背景 -Auth0服務使用在延遲加載NG2應用

最近,我把我的工作程序,並把它轉換使用lazy loading。現有的應用程序沒有問題,我使用Auth0authentication。當我運行應用程序時,轉換爲lazy loading一切似乎運行正常。除了一個問題。

問題 -

當我點擊從Auth0 widget登錄應用程序繼續進行正常。但是有兩件事發生。

  1. Login成功工作authentication該用戶。
  2. Login失敗,沒有錯誤。 當它失敗時,它轉發到auth0,然後快速重定向到主頁而不將該令牌保存到本地存儲。

我可以連續登出10次。 1的登錄將工作,那麼它將失敗9次10。我沒有提供任何錯誤消息或警告。我什至不能想出一種方法來解決這個問題,因爲有時它的工作原理,當它不工作,沒有任何改變,導致它失敗。

事情我已經試過了 -

  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 { } 

breadcrumb是共享目錄中的共享組件。該組件呈現在網站上出現的每個頁面中,並被注入到app.component.tsapp.component.html

將auth服務注入到麪包屑組件中。

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我做了一個改變。

我改變了出口這在文件的底部,

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

現在我已經能夠登錄和註銷5次連續成功。但用戶的圖像並未顯示auth0響應提供的圖像。我現在想知道它是否仍然有點不好,因爲我需要確保在正確的位置指定forRoot和forChild。

我指定了app-routing.moduel.ts文件中的所有路徑,它位於應用程序的根目錄中,可以在上面的代碼中看到。

在每個延遲加載的模塊中都有一個路由文件。這裏是家庭路線的一個例子文件

家庭routing.module.ts

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 {} 

注意,forChild是在RouterModule。

配置是否正確?我也應該將shared.module.ts添加到每個模塊或只?

+0

能否請您提供一些小的代碼段,你的延遲加載是如何在你的路由配置,以及您導入或提供您的身份驗證服務?包括您的角度版和路由器。 另外,請您詳細說明第2種情況下發生的具體情況,發生故障時無誤嗎?你沒有被Auth0重定向,你沒有獲得令牌,或者**它看起來如何「失敗」?** – jgranstrom

+0

我按照你的要求更新了我的問題。我向2號場景添加了解釋,並添加了解釋該過程的所有代碼。如果你能幫我解決這個問題,我將不勝感激。我甚至無法弄清楚如何排除故障。我在驗證服務中使用console.log。當登錄工作時,console.log起作用。當登錄不起作用時,console.log不會輸出。所以有時候authservice有效,有時不會。 – wuno

+0

我沒有看到您的身份驗證和延遲加載之間的連接。從你的代碼看起來''Auth'服務是被急切加載的(通過'SharedModule'),所以它不應該被懶惰地加載一堆* other模塊所影響。你能否確認**所有認證相關的任務**在Auth服務**中執行**並且此服務不是延遲加載的? – AngularChef

回答

0

既然你說當它失敗它實際上是重定向你但不保存令牌,我有一個理論認爲,Auth0重定向到你的應用程序中的某個頁面,其中你的Auth服務尚未初始化,或者令牌片段正在被路由清除。

由於角度在做客戶端路由默認情況下,Auth0重定向並不總是定向回當前可見網址,但更有可能是最後一次完整導航。有時,當您測試可能是"/",並且由於您立即在根路由上進行重定向時,作爲片段傳遞的令牌將按角度清除,因此可能不會被Auth服務拾取。

有兩件事你可以嘗試。分別測試兩個建議的解決方案併合並

1.明確指定Auth0應與所獲得的令牌重定向 我建議你先試試這個

// 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', ..)並聆聽路由器更改

在您的Auth服務構造函數中,將驗證的事件偵聽器替換爲以下內容。請記得在獲得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會揭示問題。我不能包裹我的頭是爲什麼這個工作完美的懶惰加載之前,現在它不。或者最糟糕的是爲什麼它能在20分鐘內完成1次。 – wuno

+0

嘿,我做了一個巨大的突破。幸運的是。您能否在我添加更新的地方閱讀我的問題的結尾? – wuno