Angular中的身份验证

时间:2018-01-08 18:39:59

标签: angular

我正在尝试使用sessionStorage存储在AppComponent的ngInit中检索的用户信息。 但是,由于此检索使用httpClient,因此即使在存储键值之前,也可以在另一个组件中访问它。这是唯一一次设置此密钥。

@Injectable()
export class AuthService {

  public currentuser = new BehaviorSubject<User>(<User>JSON.parse(sessionStorage.getItem('currentuser')));

  constructor(private _http: HttpClient, private _trace: TraceService) { }

  public  authenticate(): void {
     this._http.get<User>(AppSettings.AuthUrl, {withCredentials: true})
                      .subscribe(user => {
                        sessionStorage.setItem('currentuser', JSON.stringify(user));
                        this.currentuser.next(user);
                      },
                           e => {
                             if (e.status === 403) {
                              this.currentuser.next(null);
                              this._trace.handleAuthError(e);
                             } else {
                               this.currentuser.next(null);
                               this._trace.handleError('Authenticating...', e);
                             }
                           });

  }
}

在auth guard组件中我有

@Injectable()
export class AuthGuard implements CanActivate {

  constructor(private _router: Router,
              private _authService: AuthService) { }

  public canActivate() {
    this._authService.currentuser.subscribe(u => {
      if (u === null) {
        this._router.navigateByUrl(AppSettings.NotAuthenticatedRoute);
        return false;
      }});
    return true;
  }
}

路由模块

const routes: Routes = [ { path: AppSettings.LegalTermsRoute,  component: LegalTermComponent, canActivate: [AuthGuard] }];

在AppComponent

  ngOnInit(): void {
      this._authService.authenticate();
  }

问题在于,我不是以正确的方式设置此订阅,当应用程序出现时,auth guard会阻止LegalTermComponent

2 个答案:

答案 0 :(得分:1)

sessionStorage.getItem会返回一个值,因此我不确定您是否可以使用Observable.from,但我认为它适合您。这更像是Observable.of - 无论哪种方式,这都会将一个值转换为一个立即发出然后完成的Observable,这不是你想要的。

您需要创建一个自定义Observable,该值在可用时发出值。 BehaviorSubject适用于此,因为只要您订阅它,您将获得其最后一个值,即使您在设置值后碰巧订阅,也可以获得所述值。

export class AuthService {
  currentuser = new BehaviorSubject<User>(sessionStorage.getItem('currentuser') as User);

  authenticate() {
    // Do whatever authenticate usually does ... this is an example
    this.http.post<User>('/auth').subscribe(user => this.currentuser.next(user));
  }
  /* your other methods and properties ... */

我也会避免在组件中实现副作用(例如更新会话存储),而是在服务中执行。

答案 1 :(得分:0)

我认为这样就发布了我的回答,以防万一这可能对我的情况有帮助,这是Web API中的简单Windows身份验证。我使用Kendo - 所以使用加载微调器来使事情同步。

// app.component.ts
  ngOnInit(): void {
  sessionStorage.clear();
  sessionStorage.setItem('requestedRoute', window.location.pathname);
  this._router.navigateByUrl(AppSettings.AuthRoute, {skipLocationChange: true});
}


 // AuthRoute -> auth.component.ts
 @Component({
 selector: 'app-auth',
template: `
<div *ngIf="isAuthenticating()" class="k-i-loading"></div>
<div style="padding:20px"><h4>Authenticating...</h4><div>
<div kendoDialogContainer></div>
`,
styles: []
})
   ngOnInit() {
this._authService.authenticate().subscribe((user: User) => {
  if (user !== undefined) {
    user.isAuthencated = true;
    sessionStorage.setItem('currentuser', JSON.stringify(user));
    this._router.navigateByUrl(sessionStorage.getItem('requestedRoute'));
  }
 });
}

public isAuthenticating() {
  return this._authService.isAuthenticating;
}

 //auth.service.ts
 public isAuthenticating = true; // loading spinner

 constructor(private _http: HttpClient, private _trace: TraceService) { }

 public  authenticate(): Observable<User> {
 this.isAuthenticating = true;
 return this._http.get<User>(AppSettings.AuthUrl, {withCredentials: true})
                    .catch<any, User>((e, u) => this._trace.handleAuthError(e))
                    .catch<any, User>(this._trace.handleError('GET ' + AppSettings.AuthUrl, []))
                    .finally(() => this.isAuthenticating = false);
}

  //auth.guard.ts
  public canActivate(): Observable<boolean> | boolean {
  const user = <User>JSON.parse(sessionStorage.getItem('currentuser'));
  if (user !== null && user.isAuthencated) {
    return true;
  } else {
  this._router.navigateByUrl(AppSettings.NotAuthenticatedRoute);
  return false;
 }
}