Frontend de inicio de sesión angular lógica -- javascript campo con security campo con authentication campo con typescript campo con angular-2+ camp codereview Relacionados El problema

Angular Frontend login logic


4
vote

problema

Español

Este es un seguimiento de esta pregunta NOde.js Backend Logic < / a>. Escribí la siguiente lógica de inicio de sesión Angular Angular para mi backend de Nodo.js (consulte la pregunta anterior anterior). ¿Es bueno en términos de seguridad, eficiencia, construcción, asinc / sincronización, registro? seguridad es mi principal preocupación. En un formato más bonito, la pregunta sería:

  • seguridad : ¿Es mi sitio web seguro de alguna manera, forma o forma? Me pregunto si podría implementar cualquier medida de seguridad que no sean los que están incorporados a los métodos proporcionados por Angular . ¿No es la transmisión de la contraseña en texto plante un problema de seguridad? ¿Qué pasa con XSS y problemas similares? ¿No puede mi inicio de sesión simplemente ser excepcionado? Eso sería un error crítico.
  • eficiencia : ¿Cómo estoy revisando los nombres de usuario y la contraseña eficientes? ¿Hay alguna mejor manera de hacer esto?
  • edificio : ¿Cómo cargué mi sitio web aceptable?
  • async / sync : Sé que i Preforme async y import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { BehaviorSubject, Observable } from 'rxjs'; import { map } from 'rxjs/operators'; import { environment } from '../../environments/environment'; import { User } from '../models/user.model'; import { Router } from '@angular/router'; import { GlobalDataService } from './global-data.service'; @Injectable({ providedIn: 'root' }) export class AuthenticationService { constructor(private http: HttpClient, private router: Router, public DataService: GlobalDataService) { this.currentUserSubject = new BehaviorSubject<User>(JSON.parse(localStorage.getItem('currentUser'))); this.currentUser = this.currentUserSubject.asObservable(); this.LoggedIn = true; } public LoggedIn = true; public get currentUserValue(): User { return this.currentUserSubject.value; } private currentUserSubject: BehaviorSubject<User>; public currentUser: Observable<User>; getRedirectUrl() { throw new Error('Method not implemented.'); } isUserLoggedIn() { throw new Error('Method not implemented.'); } login(email: string, password: string) { return this.http.post<any>(`${environment.apiUrl}/api/login`, { email, password }, {withCredentials: true}) .pipe(map(user => { // login successful if there's a jwt token in the response if (user && user.token) { // store user details and jwt token in local storage to keep user logged in between page refreshes // https://dev.to/rdegges/please-stop-using-local-storage-1i04 localStorage.setItem('currentUserToken', JSON.stringify(user)); this.currentUserSubject.next(user); } // set firstname & email of loggedin user this.DataService.loggedinfirstname = user['firstname']; this.DataService.loggedinemail = user['eMail']; this.redirtoDashboard(); this.Toolbar(); this.DataService.prefillSenderData(); return user; })); } redirtoDashboard() { this.router.navigate(['order']); } Toolbar() { this.LoggedIn = !this.LoggedIn; } } 2 Llamadas al mismo tiempo. ¿Hay algún problema para esto?
  • logging : logro todas las conexiones al servidor y todos los intentos de inicio de sesión. ¿Es esta una buena práctica, o estoy exagerando qué tala se supone que debe cumplir?
  • misc : ¿Hay algún error en la obra entre el backend y el frontend? Si olvidara otros puntos importantes sobre el código que me alegraría si los mencionara también. (Fuente: servidor de inicio de sesión con node.js )

mi código :

autenticación.service.ts:

  import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { BehaviorSubject, Observable } from 'rxjs'; import { map } from 'rxjs/operators';  import { environment } from '../../environments/environment'; import { User } from '../models/user.model'; import { Router } from '@angular/router'; import { GlobalDataService } from './global-data.service';  @Injectable({ providedIn: 'root' }) export class AuthenticationService {     constructor(private http: HttpClient,                 private router: Router, public DataService: GlobalDataService) {         this.currentUserSubject = new BehaviorSubject<User>(JSON.parse(localStorage.getItem('currentUser')));         this.currentUser = this.currentUserSubject.asObservable();         this.LoggedIn = true;     }     public LoggedIn = true;     public get currentUserValue(): User {         return this.currentUserSubject.value;     }     private currentUserSubject: BehaviorSubject<User>;     public currentUser: Observable<User>;   getRedirectUrl() {     throw new Error('Method not implemented.');   }   isUserLoggedIn() {     throw new Error('Method not implemented.');   }    login(email: string, password: string) {     return this.http.post<any>(`${environment.apiUrl}/api/login`, { email, password }, {withCredentials: true})         .pipe(map(user => {             // login successful if there's a jwt token in the response             if (user && user.token) {                  // store user details and jwt token in local storage to keep user logged in between page refreshes                 // https://dev.to/rdegges/please-stop-using-local-storage-1i04                 localStorage.setItem('currentUserToken', JSON.stringify(user));                 this.currentUserSubject.next(user);             }             // set firstname & email of loggedin user             this.DataService.loggedinfirstname = user['firstname'];             this.DataService.loggedinemail = user['eMail'];             this.redirtoDashboard();             this.Toolbar();             this.DataService.prefillSenderData();             return user;         }));   }    redirtoDashboard() {       this.router.navigate(['order']);   }    Toolbar() {       this.LoggedIn = !this.LoggedIn;   } }    

login.component.ts:

  import { Component, OnInit } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { first } from 'rxjs/operators';  import { AuthenticationService } from '../services/authentication.service';  @Component({   selector: 'app-login',   templateUrl: './login.component.html',   styleUrls: ['./login.component.css'] }) export class LoginComponent implements OnInit {    returnUrl: string;   loginForm: FormGroup;   submitted = false;   error = '';   loading = false;   public errorMsg = 'Please login to continue.';   public redirected: boolean;   public utm_source: string;    constructor(private router: Router, private formBuilder: FormBuilder,               private authenticationService: AuthenticationService, private activatedRoute: ActivatedRoute) {       if (this.authenticationService.currentUserValue) {         this.router.navigate(['order']);     }       this.activatedRoute.queryParams.subscribe(params => {       const param = params['utm_source'];        if (param === 'order' || param === 'work-document' || param === 'profile') {         this.redirected = true;         this.utm_source = param;       } else {         this.redirected = false;       }   });   }    ngOnInit(): void {     this.loginForm = this.formBuilder.group({       email: ['', [Validators.required, Validators.email]],       password: ['', [Validators.required, Validators.minLength(6)]]   });   }  // convenience getter for easy access to form fields get f() { return this.loginForm.controls; }    onSubmit(loginsubmit) {     this.submitted = true;     // stop here if form is invalid     if (this.loginForm.invalid) {         return console.log('LoginForm Invalid');     }     this.loading = true;     this.authenticationService.login(this.f.email.value, this.f.password.value)         .pipe(first())         .subscribe(             data => {                 if (this.redirected) {                   this.router.navigate([this.utm_source]);                 } else {                   this.router.navigate(['order']);                 }              },             error => {                 console.log('Login->authservice->err: ', error);                 this.error = error;                 this.loading = false;             }); }  }    

login.component.html:

  <div class="container">   <div class="row">     <div class="col-sm-9 col-md-7 col-lg-5 mx-auto">       <div class="card card-signin my-5">         <div class="card-body">           <h5 class="card-title text-center">Login</h5>           <br>             <form [formGroup]="loginForm" class="form-signin" (ngSubmit)="onSubmit(this.loginForm.value)">               <div class="form-label-group">                 <input #userName formControlName="email" type="text" id="inputUser" class="form-control" placeholder="E-Mail" required autofocus [ngClass]="{ 'is-invalid': submitted && f.email.errors }">                   <div *ngIf="submitted && f['email'].errors" class="invalid-feedback">                     <div *ngIf="f['email'].errors.required">E-Mail is required</div>                   </div>                 </div>                 <br>                   <div class="form-label-group">                     <input #password type="password" formControlName="password" id="inputPassword" class="form-control" placeholder="Password" required [ngClass]="{ 'is-invalid': submitted && f.password.errors }">                       <div *ngIf="submitted && f['password'].errors" class="invalid-feedback">                         <div *ngIf="f['password'].errors.required">Password is required</div>                       </div>                     </div>                     <br>                       <div *ngIf="redirected">                         <mat-error>                           <p class="alert alert-danger">                             {{errorMsg}}                           </p>                         </mat-error>                       </div>                       <button [disabled]="!loginForm.valid" class="btn btn-dark btn-block" id="loginSubmit" type="submit">Login</button>                       <div class="forgot-password-link">                         <a routerLink="/forgot-password">Forgot password</a>                       </div>                     </form>                   </div>                 </div>               </div>             </div>           </div>    
Original en ingles

This is a follow-up to this question Node.js backend login logic. I wrote the following login Angular frontend logic for my Node.js Backend (see the previous question above). Is it any good in terms of security, efficiency, building, async/sync, logging? SECURITY is my main concern. On in a prettier format the question would be:

  • SECURITY: Is my website secure in any way, shape, or form? I'm wondering if I could implement any security measures other than the ones that are built in to the methods provided by Angular. Isn't the transmission of the password in plaintext a security issue? What about XSS and similar troubles? Can't my login just simply be circumvented? That would be a critical mistake.
  • EFFICIENCY: Is how I'm checking usernames and password efficient? Is there any better way to do this?
  • BUILDING: Is how I loaded my website acceptable?
  • ASYNC/SYNC: I know I preform async and sync calls at the same time. Is there any problem to this?
  • LOGGING: I log all connections to the server, and all login attempts. Is this a good practice, or am I overdoing what logging is supposed to accomplish?
  • MISC: Are there any mistakes in the play between the backend and frontend? If I forgot some other important points about the code I would be glad if you mentioned them as well (Source: Login Server with Node.js)

My code:

authentication.service.ts:

import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { BehaviorSubject, Observable } from 'rxjs'; import { map } from 'rxjs/operators';  import { environment } from '../../environments/environment'; import { User } from '../models/user.model'; import { Router } from '@angular/router'; import { GlobalDataService } from './global-data.service';  @Injectable({ providedIn: 'root' }) export class AuthenticationService {     constructor(private http: HttpClient,                 private router: Router, public DataService: GlobalDataService) {         this.currentUserSubject = new BehaviorSubject<User>(JSON.parse(localStorage.getItem('currentUser')));         this.currentUser = this.currentUserSubject.asObservable();         this.LoggedIn = true;     }     public LoggedIn = true;     public get currentUserValue(): User {         return this.currentUserSubject.value;     }     private currentUserSubject: BehaviorSubject<User>;     public currentUser: Observable<User>;   getRedirectUrl() {     throw new Error('Method not implemented.');   }   isUserLoggedIn() {     throw new Error('Method not implemented.');   }    login(email: string, password: string) {     return this.http.post<any>(`${environment.apiUrl}/api/login`, { email, password }, {withCredentials: true})         .pipe(map(user => {             // login successful if there's a jwt token in the response             if (user && user.token) {                  // store user details and jwt token in local storage to keep user logged in between page refreshes                 // https://dev.to/rdegges/please-stop-using-local-storage-1i04                 localStorage.setItem('currentUserToken', JSON.stringify(user));                 this.currentUserSubject.next(user);             }             // set firstname & email of loggedin user             this.DataService.loggedinfirstname = user['firstname'];             this.DataService.loggedinemail = user['eMail'];             this.redirtoDashboard();             this.Toolbar();             this.DataService.prefillSenderData();             return user;         }));   }    redirtoDashboard() {       this.router.navigate(['order']);   }    Toolbar() {       this.LoggedIn = !this.LoggedIn;   } }  

login.component.ts:

import { Component, OnInit } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { first } from 'rxjs/operators';  import { AuthenticationService } from '../services/authentication.service';  @Component({   selector: 'app-login',   templateUrl: './login.component.html',   styleUrls: ['./login.component.css'] }) export class LoginComponent implements OnInit {    returnUrl: string;   loginForm: FormGroup;   submitted = false;   error = '';   loading = false;   public errorMsg = 'Please login to continue.';   public redirected: boolean;   public utm_source: string;    constructor(private router: Router, private formBuilder: FormBuilder,               private authenticationService: AuthenticationService, private activatedRoute: ActivatedRoute) {       if (this.authenticationService.currentUserValue) {         this.router.navigate(['order']);     }       this.activatedRoute.queryParams.subscribe(params => {       const param = params['utm_source'];        if (param === 'order' || param === 'work-document' || param === 'profile') {         this.redirected = true;         this.utm_source = param;       } else {         this.redirected = false;       }   });   }    ngOnInit(): void {     this.loginForm = this.formBuilder.group({       email: ['', [Validators.required, Validators.email]],       password: ['', [Validators.required, Validators.minLength(6)]]   });   }  // convenience getter for easy access to form fields get f() { return this.loginForm.controls; }    onSubmit(loginsubmit) {     this.submitted = true;     // stop here if form is invalid     if (this.loginForm.invalid) {         return console.log('LoginForm Invalid');     }     this.loading = true;     this.authenticationService.login(this.f.email.value, this.f.password.value)         .pipe(first())         .subscribe(             data => {                 if (this.redirected) {                   this.router.navigate([this.utm_source]);                 } else {                   this.router.navigate(['order']);                 }              },             error => {                 console.log('Login->authservice->err: ', error);                 this.error = error;                 this.loading = false;             }); }  }  

login.component.html:

<div class="container">   <div class="row">     <div class="col-sm-9 col-md-7 col-lg-5 mx-auto">       <div class="card card-signin my-5">         <div class="card-body">           <h5 class="card-title text-center">Login</h5>           <br>             <form [formGroup]="loginForm" class="form-signin" (ngSubmit)="onSubmit(this.loginForm.value)">               <div class="form-label-group">                 <input #userName formControlName="email" type="text" id="inputUser" class="form-control" placeholder="E-Mail" required autofocus [ngClass]="{ 'is-invalid': submitted && f.email.errors }">                   <div *ngIf="submitted && f['email'].errors" class="invalid-feedback">                     <div *ngIf="f['email'].errors.required">E-Mail is required</div>                   </div>                 </div>                 <br>                   <div class="form-label-group">                     <input #password type="password" formControlName="password" id="inputPassword" class="form-control" placeholder="Password" required [ngClass]="{ 'is-invalid': submitted && f.password.errors }">                       <div *ngIf="submitted && f['password'].errors" class="invalid-feedback">                         <div *ngIf="f['password'].errors.required">Password is required</div>                       </div>                     </div>                     <br>                       <div *ngIf="redirected">                         <mat-error>                           <p class="alert alert-danger">                             {{errorMsg}}                           </p>                         </mat-error>                       </div>                       <button [disabled]="!loginForm.valid" class="btn btn-dark btn-block" id="loginSubmit" type="submit">Login</button>                       <div class="forgot-password-link">                         <a routerLink="/forgot-password">Forgot password</a>                       </div>                     </form>                   </div>                 </div>               </div>             </div>           </div>  
              
   
   

Lista de respuestas

5
 
vote
vote
La mejor respuesta
 

Lo siento, no eché un vistazo a su código de backend, así que esto es solo una gran revisión.

para sus preguntas:

  • seguridad
    Como Sam ya se analizó, no hay un problema obvio en la parte frontend (siempre y cuando se ejecute con HTTPS). Espero que la contraseña haya sido hash (con una sal) en el backend, y solo el hash se almacena en la base de datos, para que nadie pueda extraer las contraseñas reales de la base de datos.

  • eficiencia
    Sí, los validadores son la forma de ir en angular. Técnicamente, sería un poco más temerario para usar la validación HTML, pero esas fractales de milisegundos definitivamente no valen la pena perder la flexibilidad de los validadores.

  • edificio

  • async / sync
    El problema con llamar a un método de ASYNC sin manejar el resultado es que no se dará cuenta de que si algo no funcionó como se esperaba. Está bien, si sabe que el código que está utilizando fue desarrollado y mantenido por un desarrollador de Dios que está por encima de los errores. Si el desarrollador es un humano, siempre debe esperar que haya un problema. Y si llama a un método y sabe que cualquier problema, no hay un problema para su código, luego hágalo explícito en su código, de modo que los siguientes desarrolladores (por ejemplo, en 3 meses) también lo sabrán. - -)

  • logging
    La pregunta es, lo que pretende con el registro. Si desea monitorear todo para obtener conocimiento sobre sus usuarios, su infraestructura, etc., etc., que está bien. De acuerdo, entonces usaría uno de los marcos existentes para hacerlo para mí y no reinventar la rueda.
    Si solo está interesado en las cosas malas, entonces solo registrará esos (como intentos de inicio de sesión fallidos).
    Entonces, como siempre, no hay "sí" o "no". Depende de tu intención.
    Como una aclaración If VarType(argValue) >= vbArray 3 no es "Registrar" para mí, porque solo es visible para el usuario y para él solo si tiene la consola abierta.

  • misc Ver lo siguiente

Refactoring

Me gustaría refactorizar primero el código un poco para la legibilidad. En mi experiencia, hace que sea más fácil detectar errores. Puedes ignorarlo y saltar a la parte interesante si quieres.

En general, me gusta mucho usar siempre If VarType(argValue) >= vbArray 4 y If VarType(argValue) >= vbArray 5 y ser lo más restrictivo posible. Muestra al lector que pensé en el alcance de un método / variable. Y reduce la posibilidad de mal uso. Si no estoy seguro, entonces comience con If VarType(argValue) >= vbArray 6 .
Si no se usa nada, su público por defecto. Y como lector, entonces no sé si el desarrollador elige eso por intención o simplemente lo olvidé.

Authenticationservice

If VarType(argValue) >= vbArray 7 se establece en TIEMPO DE DEFINICIÓN REALIZADO ( 99887776655443378 ) y nuevamente en el constructor. Prefiero personalmente la asignación del valor inicial en la definición. Además, este valor se utiliza como "medios verdaderos que no están conectados". Eso es irritante, por lo tanto, cambiaría el nombre a If VarType(argValue) >= vbArray 9 e inicializarlo con FALSO.

VarType0 es público, pero parece no ser usado fuera de la clase.

No me gustan las cadenas constantes en mi código, así que las extraigo en constantes. Como
VarType1

Me gusta usar los operadores de RXJS "Hablando". El VarType2 MÉTODO EN VarType3 no cambia la transmisión, para ello usaría VarType4 en su lugar. Eso hace que sea obvio que solo hay un efecto secundario. Ya lo hemos podido omitir el 99887776655443385 Línea.

me gusta el código SpeedReading. Por lo tanto, si puedo extraer algunas líneas de código en un método de habla, estoy haciendo eso, porque entonces solo tengo que leer el nombre del método, no todo el código detrás de él y puede decidir si me gustaría bucear más profundo o simplemente continuar.
Para ello, cambiaría el código en el método VarType6655443386 99887776655443387 .

También parece que el método "Barra de herramientas" solo se usa para cambiar el estado VarType8 una vez. Así que podríamos simplemente establecer el valor, sin un palanca.
También hay un problema aquí (consulte más adelante en el Capítulo de la Emisión), para ello, moveré la llamada de esa funcionalidad a la declaración de IF.

Normalmente, la redirección es lo último que debería suceder, a la que lo muevo hasta el final del grifo

  VarType9  

LOGINCOMPONENTE

En Variant0 No necesita un Variant1 . Detrás de Variant2 es una solicitud HTTP. Y los terminan automáticamente después del primer resultado. Debido a la misma razón que no necesita darse de baja esas suscripciones.

Problemas

Authenticationservice

En el método Variant3 Parece que incluso en el caso de un inicio de sesión no exitoso (sin información de usuario o sin token), todavía intenta enviar datos en el 99887766655443394 y hace cosas. Aquí separaría muy claramente las cosas que siempre deben suceder después de un intento de inicio de sesión, y aquellos que solo pueden suceder después de un inicio de sesión exitoso.
Específicamente "Actualmente cambiará Variant5 Incluso si el inicio de sesión no fue exitoso.

LOGINCOMPONENTE

Mejores prácticas

Aquí algunas mejores prácticas (al menos en mis ojos :-))

En el Código, la información del usuario se usa para dos cosas. Para obtener información detallada sobre el usuario y, en segundo lugar, como implícito "El usuario está conectado". En el Servicio de Autentificaciones, esta conexión es válida. Pero al exterior, proporcionaría información al usuario y, además, una información de "islogedin". De esa manera, un desarrollador no tiene que "saber" que la formación de usuarios implica que un usuario ha iniciado sesión.

Es un buen hábito de darse de baja, cuando abandone el componente. Así que normalmente hago algo como este

  Variant6  

De esa manera, tan pronto como se destruya el componente, esas suscripciones se dan de baja automáticamente. Tenga en cuenta, un componente solo se destruye si se retira completamente del DOM. Si está oculto, entonces sigue vivo.

Espero que una o dos cosas te ayuden.

Saludos cordiales

 

Sorry I didn't took a look at your backend code, so this is just half a review.

For your questions:

  • Security
    As Sam already analyzed, there is no obvious problem on the frontend part (as long as you run with HTTPS). I expect that the password is hashed (with a salt) in the backend, and only the hash is stored in the database, so that nobody can extract the real passwords from the database.

  • Efficiency
    Yep, Validators is the way to go in Angular. It would be technically a bit more performant to use HTML Validation, but those fractals of milliseconds are definitely not worth to lose the flexibility of Validators.

  • Building

  • Async / Sync
    The problem with calling an async method without handling the result is, that you will not realize if something did not worked as expected. Thats okay if you know that the code that you are using was developed and maintained by a godlike developer who is above errors. If the developer is a human, you should always expect that there may be a problem. And if you call a method and you know that any problem there is NOT a problem for your code, then make it explicit in you code, so that the following developers (e.g. you in 3 months) will know that too. :-)

  • Logging
    The question is, what you intend with the logging. If you would like to monitor everything to get knowledge about your users, your infrastructure, etc etc, than thats fine. Okay, i would then use one of the existing frameworks to do that for me and not reinvent the wheel.
    If you are just interested in the bad things, then i would only log those (like failing login attempts).
    So as always, there is no "YES" or "NO". It depends on your intention.
    As a clarification console.log is not "logging" for me, because its only visible to the user and for him only if he has the console open.

  • MISC
    See the following

Refactoring

I would like to first refactor the code a bit for readability. In my experience it makes it easier to spot mistakes. You can ignore it and skip to the interesting part if you want.

In general i really like to use always privateand public and be as restrictive as possible. It shows the reader that i thought about the scope of a method/variable. And it reduces the chance of misuse. If i am not sure, then i start with private.
If nothing is used, its public by default. And as a reader then i do not know if the developer choose that by intention or just forgot it.

AuthenticationService

LoggedIn is set to true at definition time (public LoggedIn = true) and again in the constructor. I personally prefere the assignment of the initial value at definition time. Also this value is used as "true means not logged in". Thats irritating, therefore i would change the name to isLogedIn and initialize it with false.

DataService is public but seems not be used outside the class.

I don't like constant strings in my code, so i extract them into constants. Like
private loginUrl: string = `${environment.apiUrl}/api/login`;

I like to use "speaking" RxJs Operators. The mapMethod in login does not change the stream, therefor i would use tapinstead. That makes it obvious that there is only a side effect.`Also we then could skip the return line.

I like speedreading code. Therefor, if i can extract some lines of code into a speaking method, i am doing that, because then i only have to read the methodname, not all the code behind it and can decide if i would like to dive deeper or just continue.
Therefor i would change the code in the mapof the login method a bit.

Also it seems that the "Toolbar" method is only used to change the LogedInstatus once. So we could just set the value, without a toggle.
There is also an issue here (see later in the issue chapter), therefor i will move the call of that functionality into the if statement.

Normally the redirect is the last thing that should happen, therefor i move it to the end of the tap

export class AuthenticationService {     public isLoggedIn = false;     public currentUser: Observable<User>      public get currentUserValue(): User {         return this.currentUserSubject.value;     }              private currentUserSubject: BehaviorSubject<User> = new BehaviorSubject<User>(JSON.parse(localStorage.getItem('currentUser')));     private loginUrl: string = `${environment.apiUrl}/api/login`;      constructor(private DataService: GlobalDataService,                 private http: HttpClient,                 private router: Router) {         this.currentUser = this.currentUserSubject.asObservable();     }           private getRedirectUrl() {     throw new Error('Method not implemented.');   }      private isUserLoggedIn() {     throw new Error('Method not implemented.');   }    public login(email: string, password: string):Observable<User> {     return this.http.post<User>(loginUrl, { email, password }, {withCredentials: true})         .pipe(             tap(user => {             // login successful if there's a jwt token in the response             if (this.isLoginSuccessful(user)) {                 this.setLogedInUser(user);                 this.isLoggedIn = true;             }             this.setDataServiceForUser(user);                         this.toggleLoginStatus();             this.redirectToDashboard();         })     );   }      private isLoginSuccessful(user:User):boolean{         return user && user.token;     }    private redirectToDashboard():void {       this.router.navigate(['order']);   }      private setLogedInUser(user: User):void{         // store user details and jwt token in local storage to keep user logged in between page refreshes         // https://dev.to/rdegges/please-stop-using-local-storage-1i04         localStorage.setItem('currentUserToken', JSON.stringify(user));         this.currentUserSubject.next(user);     }      private setDataServiceForUser(user:User):void{         // set firstname & email of loggedin user         this.DataService.loggedinfirstname = user['firstname'];         this.DataService.loggedinemail = user['eMail'];         this.DataService.prefillSenderData();     } } 

LoginComponent

In onSubmityou do not need a first(). Behind this.authenticationService.login is a http request. And those terminate automatically after the first result. Because of the same reason you do not need to unsubscribe those subscriptions.

Issues

AuthenticationService

In the loginmethod it seems that even in the case of a not successful login (no user or no token information), it still tries to send data into the DataService and does stuff. Here i would very clearly separate those things that should ALWAYS happen after a login attempt, and those that only may happen after a successful login.
Specifically `currently it will change LogedIneven if the login was not successful.

LoginComponent

Best Practices

Here some Best Practices (at least in my eyes :-) )

In the code, the User Information is used for two things. For detailed information about the user and secondly as an implicit "the user is logged in". In the AuthentificationService this connection is valid. But to the outside, i would provide User-Information and additionally a "isLogedIn" information. In that way, a developer don't have to "know" that userinformation implies that a user is logged in.

It's a good habit to unsubscribe, when you leave the component. Therefor I normally do something like this

private subscriptions: Subscription() = new Subscription(); ... this.subscriptions.add(     sourceA.subscribe(...) ) this.subscriptions.add(     sourceB.subscribe(...) )  ngOnDestroy(){     this.subscriptions.unsubcribe(); } 

That way, as soon as the component gets destroyed, those subscriptions all get automatically unsubscribed. Be aware, a component gets only destroyed if its completely removed from the DOM. If it's hidden, then it's still alive.

I hope one or two things were helpful for you.

warm regards

 
 
       
       
2
 
vote

Prefacio

Hace unos años de Angularjs hace unos años, pero no me metí en angular2 +, por lo que mi conocimiento de ella es delgado a nadie. Sin embargo, tengo una buena cantidad de familiar con JavaScript y varios marcos.

Respuestas de preguntas

seguridad ¿No es la transmisión de la contraseña en el texto plante un problema de seguridad?

Encontré publicaciones sobre esta pregunta en múltiples sitios SE. Por ejemplo, encontré ¿Está bien enviar una contraseña de texto sin formato a través de HTTPS? [duplicado] . Para citar la respuesta aceptada por Buffalo5ix :

Es una práctica estándar para enviar contraseñas de "texto simple" a través de HTTPS. Las contraseñas no se muestran en última instancia, ya que la comunicación del cliente-servidor está cifrado según TLS.

Esa pregunta está marcada como un duplicado de otros dos puestos, incluido este: Acabo de enviar el nombre de usuario y la contraseña a través de HTTPS. ¿Está bien? . Tiene dos respuestas y la segunda respuesta de Steve ofrece una opción:

Una cosa adicional que podría hacer sería usar certificados de clientes. El servidor solo puede garantizarse a sí mismo que no hay MITM solicitando un certificado de cliente. De lo contrario, tiene que confiar en el cliente para validar adecuadamente la ausencia de un MITM. Esto es más de lo que muchos servicios deben estar dispuestos a confiar.

No he oído hablar de nadie haciendo eso, pero tal vez esté hecho y simplemente no lo sabemos.

Hay incluso una pila de desbordamiento de una pregunta sobre la pregunta , con La respuesta aceptada muy similar a la respuesta aceptada de la primera pregunta (de la seguridad se) mencionada anteriormente.

eficiencia ¿Cómo estoy revisando los nombres de usuario y la contraseña eficientes? ¿Hay alguna mejor manera de hacer esto?

No estoy al tanto de ninguna mejor manera de hacer esto, pero sí noté estas líneas en Variant7 que deberían poder usar la notación de puntos:

  Variant8  

Nombre del método

Pregunté por la actualización de la propiedad Variant9 y señaló que se estableció en el constructor y luego se modificó en el método Private Sub ExampleOne() Dim bar() As Long ReDim bar(-10 To -5) Dim idx As Long For idx = LBound(bar) To UBound(bar) Debug.Print idx Next End Sub 00 . Un nombre como Private Sub ExampleOne() Dim bar() As Long ReDim bar(-10 To -5) Dim idx As Long For idx = LBound(bar) To UBound(bar) Debug.Print idx Next End Sub 01 parece que podría estar asociado con la obtención de una barra de herramientas. Los otros métodos en esa clase tienen un verbo, por ejemplo. Iniciar sesión , RedirTodaShboard . Un nombre de método más apropiado para ese método puede ser Private Sub ExampleOne() Dim bar() As Long ReDim bar(-10 To -5) Dim idx As Long For idx = LBound(bar) To UBound(bar) Debug.Print idx Next End Sub 02 o algo así.

Simplificación o Condiciones

Esta línea en Private Sub ExampleOne() Dim bar() As Long ReDim bar(-10 To -5) Dim idx As Long For idx = LBound(bar) To UBound(bar) Debug.Print idx Next End Sub 03 :

  Private Sub ExampleOne()     Dim bar() As Long     ReDim bar(-10 To -5)      Dim idx As Long     For idx = LBound(bar) To UBound(bar)         Debug.Print idx     Next End Sub 04  

podría simplificarse usando Private Sub ExampleOne() Dim bar() As Long ReDim bar(-10 To -5) Dim idx As Long For idx = LBound(bar) To UBound(bar) Debug.Print idx Next End Sub 05 que realiza una comparación estricta 1 2 :

  Private Sub ExampleOne()     Dim bar() As Long     ReDim bar(-10 To -5)      Dim idx As Long     For idx = LBound(bar) To UBound(bar)         Debug.Print idx     Next End Sub 06  
 

Preface

I used AngularJS a few years ago but didn't get into Angular2+ so my knowledge of it is slim-to-none. I do however have a fair amount of familiar with Javascript and various frameworks.

Question responses

Security Isn't the transmission of the password in plaintext a security issue?

I found posts about this question on multiple SE sites. For example, I found Is it ok to send plain-text password over HTTPS? [duplicate]. To quote the accepted answer by Buffalo5ix:

It is standard practice to send "plaintext" passwords over HTTPS. The passwords are ultimately not plaintext, since the client-server communication is encrypted as per TLS.

That question is marked as a duplicate of two other posts, including this one: I just send username and password over https. Is this ok?. It has two answers and the second answer by Steve offers an option:

One additional thing you could do would be to use client certificates. The server can only guarantee to itself that there is no MitM by requiring a client cert. Otherwise, he has to trust the client to properly validate the absence of a MitM. This is more than a lot of services should be willing to trust.

I haven't heard of anyone doing that but perhaps it is done and we just don't know about it.

There is even a Stack Overflow question about the question, with the accepted answer very similar to the accepted answer of the first question (from Security SE) mentioned above.

EFFICIENCY Is how I'm checking usernames and password efficient? Is there any better way to do this?

I am not aware of any better way to do this, but I do notice these lines in AuthenticationService.login() that should be able to use dot notation:

 this.DataService.loggedinfirstname = user['firstname'];  this.DataService.loggedinemail = user['eMail']; 

Method name

I asked about the updating of the property LoggedIn and noted that it was set in the constructor and then modified in the method Toolbar. A name like Toolbar seems like it might be associated with fetching a toolbar. The other methods in that class have a verb - e.g. login, redirtoDashboard. A more appropriate method name for that method might be ToggleLoggedIn or something along those lines.

Simplifying OR conditions

This line in LoginComponent::constructor():

       if (param === 'order' || param === 'work-document' || param === 'profile') { 

could be simplified using Array.prototype.includes() which does a strict comparison1 2:

  if ([ 'order', 'work-document', 'profile'].includes(param)) { 
 
 
       
       

Relacionados problema

6  Control angular para ingresar latitud y longitud con validación  ( Angular control for inputting latitude and longitude with validation ) 
He construido un control personalizado para manejar la entrada del usuario en un formato legible por humanos, pero ahorre en un formato de máquina. Debe tene...

9  Formularios angulares 5 - extendiendo el control de la forma  ( Angular 5 forms extending form control ) 
Estoy tomando un primer pase a formas angulares con algunos colegas y notó un patrón de diseño interesante implementado por un compañero de trabajo donde el ...

3  Servicio angular 2 para cargar un trabajo por lotes y una encuesta para obtener resultados  ( Angular 2 service to upload a batch job and poll for results ) 
Tengo que escribir una interfaz web para uno de mis proyectos de Homebrew. Ya que no estoy familiarizado con HTML y CSS, he decidido tomar un marco de trabajo...

2  Angular ng-para escenario impar / incluso  ( Angular ng for odd even scenario ) 
Solo quiero crear una disposición vertical de mampostería con dos divisores size5 .card-derecha`. ¿Alguien tiene una idea de colocar size6 en la izquierda...

0  Angular2 y RXJs pasan objetos con un servicio  ( Angular2 and rxjs passing objects around with a service ) 
Digamos que quiero compartir un objeto entre múltiples componentes. Este servicio permitirá que los componentes envíen o reciban el objeto. Esta funcionalid...

2  Efectos ngrx en aplicación angular  ( Ngrx effects in angular application ) 
@Effect() createQuiz$: Observable<Action> = this.actions$.pipe( ofType<quizAction.CreateQuiz>(quizAction.CREATE_QUIZ), switchMap((action) => { ...

3  Efectos simples en la aplicación Angular 2+ utilizando Firsebase, NGRX y RXJS  ( Simple effects in angular 2 application using firebase ngrx and rxjs ) 
Hizo una aplicación angular con Firebase, RXJS y NGRX. get_pool0 Estos son los efectos NGRX. Están activando una función reductora, luego llame a una fu...

6  Reproductor de audio en Angular 2  ( Audio player in angular 2 ) 
Acabo de construir un reproductor de audio en Angular 2 usando un componente de reproductor y un servicio de jugador. Todo está funcionando bien, solo siento ...

2  Juego Simple TictoCtoe en TIPSCRIST  ( Simple tictactoe game in typescript ) 
Estoy preguntando principalmente si puedo simplificar el código. Me han dicho que es innecesariamente complicado. html: <div class="board"> <div id="tl...

1  Compare múltiples valores de una matriz al mismo tiempo en JavaScript [CERRADO]  ( Compare multiple values of an array in the same time in javascript ) 
cerrado. Esta pregunta es off-topic . Actualmente no está aceptando respuestas. ¿Quieres ...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos