2017-10-10 41 views
0

我已经使用RxJS Observer功能在角度4中编写了认证系统。查询Oracle数据库是基于查询流在服务中转换为observer/observable,然后在登录组件中使用登录形式,我订阅服务中的obervable以获得身份验证结果。服务的方法返回的可观察对象在用户进行身份验证时发布“true”或“false”。通过单击登录表单组件中的登录按钮,将显示加载动画并隐藏登录表单。当用户通过身份验证时,路由器会将用户重定向到功能页面。当用户未通过身份验证时,加载动画将被隐藏,并再次显示登录表单。但这并不如预期的那样。在控制台I看到输出该用户没有登录,并在加载动画仍显示的同时,形式是隐藏的,尽管=假和showLoginForm =真为什么在订阅回调中更改组件的属性时,角色4组件的视图不会重新渲染?

login.service.ts组件显示showLoading的性质

import { Injectable } from '@angular/core'; 
 
import { DbSelectService } from '../db/db-select.service'; 
 
import * as md5 from 'js-md5'; 
 
import { AuthModel, CurrentUserModel } from '../../data-models/data-models.interfaces'; 
 
import { DbSelectQueryParams } from '../../data-models/data-models.interfaces'; 
 
import { CurrentUserDbRow } from '../../data-models/db-responses.interfaces'; 
 
import { SessionService } from '../core/session.service'; 
 
import { CacheService } from '../feature/cache.service'; 
 
import { LoggerService } from '../core/logger.service'; 
 
import { Observable } from 'rxjs/Observable'; 
 
import { Observer } from 'rxjs/Observer'; 
 

 
@Injectable() 
 
export class LoginService { 
 

 
    private currentAuthData: AuthModel; 
 
    private currentUser: CurrentUserModel; 
 

 
    constructor (
 
     private dbSelect: DbSelectService, 
 
     private sessionService: SessionService, 
 
     private cacheService: CacheService, 
 
     private logger: LoggerService 
 
    ) { 
 

 
     this.currentAuthData = this.cacheService.getCurrentAuthDataCache(); 
 
     this.currentUser = this.cacheService.getCurrentUser(); 
 

 
    } 
 

 
    checkAccessRights(): Observable<boolean> { 
 

 
     return new Observable((observer: Observer<boolean>) => { 
 

 
      const queryParams: DbSelectQueryParams = { 
 
       fields: [ 
 
        `NAME`, 
 
        `ROLE` 
 
       ], 
 
       tables: [ 
 
        `SINS.P_USER` 
 
       ], 
 
       conditions: [ 
 
        `UPPER(P_USER.NAME) = UPPER(:username)`, 
 
        `AND`, 
 
        `PSWD = :password`, 
 
        `AND`, 
 
        `HASH = :hash`, 
 
        `AND`, 
 
        `LOCKED <> '1'`, 
 
        `AND`, 
 
        `ROWNUM = 1` 
 
       ] 
 
      }; 
 

 
      const bindParams = { 
 
       username: this.currentAuthData.username, 
 
       password: this.currentAuthData.password, 
 
       hash: md5(this.currentAuthData.password) 
 
      }; 
 

 
      let userIsAuthenticated = false; 
 
      const AUTHENTICATED = true; 
 
      const NOT_AUTHENTICATED = false; 
 

 
      this.dbSelect.select<CurrentUserDbRow>(queryParams, bindParams).subscribe(
 
       user => { 
 

 
        console.warn(user); 
 
        this.currentUser.username = user.NAME.toUpperCase(); 
 
        this.currentUser.role = user.ROLE.toLowerCase(); 
 

 
        this.sessionService.getAccessToUser(); 
 

 
        userIsAuthenticated = true; 
 

 
        observer.next(AUTHENTICATED); 
 
        observer.complete(); 
 

 
       }, 
 
       err => { 
 

 
        observer.error(err); 
 
        this.logger.writeError(err); 
 
        this.sessionService.closeSession(); 
 

 
       }, 
 
       () => { 
 

 
        observer.next(NOT_AUTHENTICATED); 
 
        observer.complete(); 
 

 
        if (userIsAuthenticated === NOT_AUTHENTICATED) { 
 
         this.logger.writeNewError('logon denied'); 
 
         this.sessionService.closeSession(); 
 
        } 
 

 
       } 
 
      ); 
 

 
     }); 
 

 
    } 
 

 

 
}

login.component.ts

import { Component, OnInit, OnDestroy } from '@angular/core'; 
 
import { Title } from '@angular/platform-browser'; 
 
import { AppConfig } from '../services/core/app-config.service'; 
 
import { remote } from 'electron'; 
 
import { LoginService } from '../services/auth/login.service'; 
 
import { AuthModel } from '../data-models/data-models.interfaces'; 
 
import { ToastService } from '../services/core/toast.service'; 
 
import { CacheService } from '../services/feature/cache.service'; 
 
import { AppConfigParamsModel, MaxLengthAndValueModel } from '../data-models/data-models.interfaces'; 
 
import { Subscription } from 'rxjs/Subscription'; 
 

 
@Component({ 
 
    selector: 'login', 
 
    styleUrls: ['app/login/login.component.css'], 
 
    templateUrl: 'app/login/login.component.html' 
 
}) 
 

 
export class LoginComponent implements OnInit, OnDestroy { 
 

 
    private pagename = 'Логин'; 
 
    private showLoading = false; 
 
    private showLoginForm = true; 
 
    private loginSubscription: Subscription; 
 

 
    private authmodel: AuthModel; 
 

 
    private maxlength: MaxLengthAndValueModel = { 
 
     username: 32, 
 
     password: 32 
 
    }; 
 

 
    constructor (
 
     private titleService: Title, 
 
     private config: AppConfig, 
 
     private loginService: LoginService, 
 
     private toastService: ToastService, 
 
     private cacheService: CacheService 
 
    ) { 
 

 
     this.authmodel = this.cacheService.getCurrentAuthDataCache(); 
 

 
    } 
 

 
    ngOnInit() { 
 

 
     this.config.getParams().then((params: AppConfigParamsModel) => { 
 

 
      this.titleService.setTitle(`${params.appname} - ${this.pagename}`); 
 

 
     }); 
 

 
    } 
 

 

 
    ngOnDestroy() { 
 

 
     if (this.loginSubscription) { 
 
      this.loginSubscription.unsubscribe(); 
 
     } 
 

 
    } 
 

 

 
    private onLogin(): void { 
 

 
     this.showLoadingAnimation(); 
 

 
     this.loginSubscription = this.loginService.checkAccessRights().subscribe(
 
      accessAllowed => { 
 

 
       if (accessAllowed) { 
 

 
        this.toastService.showAdviceToast('Добро пожаловать!'); 
 

 
       } else { 
 

 
        this.hideLoadingAnimation(); 
 
        this.toastService.showErrorToastWithAdvice('ВХОД ЗАПРЕЩЁН', 'Обратитесь к администратору'); 
 

 
       } 
 

 
      }, 
 
      err => { 
 

 
       this.hideLoadingAnimation(); 
 
       this.toastService.showErrorToastWithAdvice('Не удалось войти', 'Попробуйте ещё раз'); 
 

 
      } 
 
     ); 
 

 
    } 
 

 

 
    private closeWindow(): void { 
 

 
     remote.getCurrentWindow().close(); 
 

 
    } 
 

 

 
    private showLoadingAnimation(): void { 
 

 
     this.showLoading = true; 
 
     this.showLoginForm = false; 
 
     console.warn(this); 
 

 
    } 
 

 

 
    private hideLoadingAnimation(): void { 
 

 
     this.showLoading = false; 
 
     this.showLoginForm = true; 
 
     console.warn(this); 
 

 
    } 
 

 

 
}

但是,如果我改变服务方法只是为了实验俨然以下所示的(没有订阅查询结果)组件的视图被重新呈现良好。

checkAccessRights(): Observable<boolean> { 
 

 
     return new Observable((observer: Observer<boolean>) => { 
 

 
      const AUTHENTICATED = true; 
 
      const NOT_AUTHENTICATED = false; 
 

 
      this.currentUser.username = 'ADMIN'; 
 
      this.currentUser.role = 'admin'; 
 
      this.sessionService.getAccessToUser(); 
 
      observer.next(AUTHENTICATED); 
 
      observer.complete(); 
 

 
     }); 
 

 
    }
我要指出,这一切工作,如果我使用的承诺,而不是观察员。

在服务

checkAccessRights(): Promise<boolean> { 
 

 
     return new Promise((resolve, reject) => { 
 

 
      const queryParams: DbSelectQueryParams = { 
 
       fields: [ 
 
        `NAME`, 
 
        `ROLE` 
 
       ], 
 
       tables: [ 
 
        `SINS.P_USER` 
 
       ], 
 
       conditions: [ 
 
        `UPPER(P_USER.NAME) = UPPER(:username)`, 
 
        `AND`, 
 
        `PSWD = :password`, 
 
        `AND`, 
 
        `HASH = :hash`, 
 
        `AND`, 
 
        `LOCKED <> '1'`, 
 
        `AND`, 
 
        `ROWNUM = 1` 
 
       ] 
 
      }; 
 

 
      const bindParams = { 
 
       username: this.currentAuthData.username, 
 
       password: this.currentAuthData.password, 
 
       hash: md5(this.currentAuthData.password) 
 
      }; 
 

 
      let userIsAuthenticated = false; 
 
      const AUTHENTICATED = true; 
 
      const NOT_AUTHENTICATED = false; 
 

 
      this.dbSelect.select<CurrentUserDbRow>(queryParams, bindParams).subscribe(
 
       user => { 
 

 
        console.warn(user); 
 
        this.currentUser.username = user.NAME.toUpperCase(); 
 
        this.currentUser.role = user.ROLE.toLowerCase(); 
 

 
        this.sessionService.getAccessToUser(); 
 

 
        userIsAuthenticated = true; 
 

 
        resolve(AUTHENTICATED); 
 

 
       }, 
 
       err => { 
 

 
        reject(err); 
 
        this.logger.writeError(err); 
 

 
       }, 
 
       () => { 
 

 
        resolve(NOT_AUTHENTICATED); 
 

 
        if (userIsAuthenticated === NOT_AUTHENTICATED) { 
 
         this.logger.writeNewError('logon denied'); 
 
        } 
 

 
       } 
 
      ); 
 

 
     }); 
 

 
    }

在组分

this.loginService.checkAccessRights().then(
 
      accessAllowed => { 
 

 
       if (accessAllowed) { 
 

 
        this.toastService.showAdviceToast('Добро пожаловать!'); 
 

 
       } else { 
 

 
        this.hideLoadingAnimation(); 
 
        this.toastService.showErrorToastWithAdvice('ВХОД ЗАПРЕЩЁН', 'Обратитесь к администратору'); 
 

 
       } 
 

 
      } 
 
     ).catch(
 
      err => { 
 

 
       this.hideLoadingAnimation(); 
 
       this.toastService.showErrorToastWithAdvice('Не удалось войти', 'Попробуйте ещё раз'); 
 

 
      } 
 
     );

请帮助我解决此问题并按预期进行组件重新渲染。

+0

有时,问题来自于退订方法。 – Wandrille

+0

在此代码的以前版本中,取消订阅方法不存在,并且问题相同 –

回答

0

试图去改变一些事情:

  • 注释你的组件领域正确的输入 - 只是@Input前面加上他们;
  • 通过明确指定或仅删除关键字private来公开这些字段。

@Input() showLoading = false; 
    @Input() showLoginForm = true; 
+0

这也未解决问题。我想说明的是,如果我使用Promise而不是Observer,那么一切正常。 –

相关问题