Saltar al contenido

Redireccionamiento angular a la página de inicio de sesión

Solución:

Aquí hay un ejemplo actualizado usando Angular 4 (también compatible con Angular 5-8)

Rutas con ruta local protegida por AuthGuard

import { Routes, RouterModule } from '@angular/router';

import { LoginComponent } from './login/index';
import { HomeComponent } from './home/index';
import { AuthGuard } from './_guards/index';

const appRoutes: Routes = [
    { path: 'login', component: LoginComponent },

    // home route protected by auth guard
    { path: '', component: HomeComponent, canActivate: [AuthGuard] },

    // otherwise redirect to home
    { path: '**', redirectTo: '' }
];

export const routing = RouterModule.forRoot(appRoutes);

AuthGuard redirige a la página de inicio de sesión si el usuario no ha iniciado sesión

Actualizado para pasar la URL original en los parámetros de consulta a la página de inicio de sesión

import { Injectable } from '@angular/core';
import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';

@Injectable()
export class AuthGuard implements CanActivate {

    constructor(private router: Router) { }

    canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
        if (localStorage.getItem('currentUser')) {
            // logged in so return true
            return true;
        }

        // not logged in so redirect to login page with the return url
        this.router.navigate(['/login'], { queryParams: { returnUrl: state.url }});
        return false;
    }
}

Para ver el ejemplo completo y la demostración funcional, puede consultar esta publicación.

Actualizar: Publiqué un proyecto completo de Angular 2 esqueleto con integración OAuth2 en Github que muestra la directiva mencionada a continuación en acción.

Una forma de hacerlo sería mediante el uso de un directive. A diferencia de Angular 2 components, que son básicamente etiquetas HTML nuevas (con código asociado) que inserta en su página, una directiva atributiva es un atributo que coloca en una etiqueta que hace que ocurra algún comportamiento. Documentos aquí.

La presencia de su atributo personalizado hace que sucedan cosas en el componente (o elemento HTML) en el que colocó la directiva. Considere esta directiva que uso para mi aplicación Angular2 / OAuth2 actual:

import {Directive, OnDestroy} from 'angular2/core';
import {AuthService} from '../services/auth.service';
import {ROUTER_DIRECTIVES, Router, Location} from "angular2/router";

@Directive({
    selector: '[protected]'
})
export class ProtectedDirective implements OnDestroy {
    private sub:any = null;

    constructor(private authService:AuthService, private router:Router, private location:Location) {
        if (!authService.isAuthenticated()) {
            this.location.replaceState("https://foroayuda.es/"); // clears browser history so they can't navigate with back button
            this.router.navigate(['PublicPage']);
        }

        this.sub = this.authService.subscribe((val) => {
            if (!val.authenticated) {
                this.location.replaceState("https://foroayuda.es/"); // clears browser history so they can't navigate with back button
                this.router.navigate(['LoggedoutPage']); // tells them they've been logged out (somehow)
            }
        });
    }

    ngOnDestroy() {
        if (this.sub != null) {
            this.sub.unsubscribe();
        }
    }
}

Esto hace uso de un servicio de autenticación que escribí para determinar si el usuario ya ha iniciado sesión y también se suscribe al evento de autenticación para que pueda expulsar a un usuario si cierra la sesión o se agota el tiempo de espera.

Podrías hacer lo mismo. Crearía una directiva como la mía que verifica la presencia de una cookie necesaria u otra información de estado que indique que el usuario está autenticado. Si no tienen esas banderas que está buscando, redirija al usuario a su página pública principal (como yo) o su servidor OAuth2 (o lo que sea). Pondría ese atributo de directiva en cualquier componente que necesite protección. En este caso, podría llamarse protected como en la directiva que pegué arriba.

<members-only-info [protected]></members-only-info>

Luego, querrá navegar / redirigir al usuario a una vista de inicio de sesión dentro de su aplicación y manejar la autenticación allí. Tendría que cambiar la ruta actual por la que deseaba hacer. Entonces, en ese caso, usaría la inyección de dependencia para obtener un objeto Router en su directiva constructor() función y luego use la navigate() método para enviar al usuario a su página de inicio de sesión (como en mi ejemplo anterior).

Esto supone que tiene una serie de rutas en algún lugar controlando un <router-outlet> etiqueta que se parece a esto, tal vez:

@RouteConfig([
    {path: '/loggedout', name: 'LoggedoutPage', component: LoggedoutPageComponent, useAsDefault: true},
    {path: '/public', name: 'PublicPage', component: PublicPageComponent},
    {path: '/protected', name: 'ProtectedPage', component: ProtectedPageComponent}
])

Si, en cambio, necesita redirigir al usuario a un externo URL, como su servidor OAuth2, entonces su directiva haría algo como lo siguiente:

window.location.href="https://myserver.com/oauth2/authorize?redirect_uri=http://myAppServer.com/myAngular2App/callback&response_type=code&client_id=clientId&scope=my_scope

Uso con el enrutador final

Con la introducción del nuevo enrutador, se hizo más fácil proteger las rutas. Debe definir un guardia, que actúa como un servicio, y agregarlo a la ruta.

import { Injectable } from '@angular/core';
import { CanActivate } from '@angular/router';
import { UserService } from '../../auth';

@Injectable()
export class LoggedInGuard implements CanActivate {
  constructor(user: UserService) {
    this._user = user;
  }

  canActivate() {
    return this._user.isLoggedIn();
  }
}

Ahora pasa el LoggedInGuard a la ruta y también agregarlo a la providers matriz del módulo.

import { LoginComponent } from './components/login.component';
import { HomeComponent } from './components/home.component';
import { LoggedInGuard } from './guards/loggedin.guard';

const routes = [
    { path: '', component: HomeComponent, canActivate: [LoggedInGuard] },
    { path: 'login', component: LoginComponent },
];

La declaración del módulo:

@NgModule({
  declarations: [AppComponent, HomeComponent, LoginComponent]
  imports: [HttpModule, BrowserModule, RouterModule.forRoot(routes)],
  providers: [UserService, LoggedInGuard],
  bootstrap: [AppComponent]
})
class AppModule {}

Publicación de blog detallada sobre cómo funciona con la versión final: https://medium.com/@blacksonic86/angular-2-authentication-revisited-611bf7373bf9

Uso con el enrutador obsoleto

Una solución más robusta es ampliar la RouterOutlet y al activar una ruta, verifique si el usuario está conectado. De esta manera, no tiene que copiar y pegar su directiva en cada componente. Además, la redirección basada en un subcomponente puede ser engañosa.

@Directive({
  selector: 'router-outlet'
})
export class LoggedInRouterOutlet extends RouterOutlet {
  publicRoutes: Array;
  private parentRouter: Router;
  private userService: UserService;

  constructor(
    _elementRef: ElementRef, _loader: DynamicComponentLoader,
    _parentRouter: Router, @Attribute('name') nameAttr: string,
    userService: UserService
  ) {
    super(_elementRef, _loader, _parentRouter, nameAttr);

    this.parentRouter = _parentRouter;
    this.userService = userService;
    this.publicRoutes = [
      '', 'login', 'signup'
    ];
  }

  activate(instruction: ComponentInstruction) {
    if (this._canActivate(instruction.urlPath)) {
      return super.activate(instruction);
    }

    this.parentRouter.navigate(['Login']);
  }

  _canActivate(url) {
    return this.publicRoutes.indexOf(url) !== -1 || this.userService.isLoggedIn()
  }
}

los UserService representa el lugar donde reside su lógica empresarial, ya sea que el usuario haya iniciado sesión o no. Puede agregarlo fácilmente con DI en el constructor.

Cuando el usuario navega a una nueva URL en su sitio web, se llama al método de activación con la instrucción actual. Desde allí, puede tomar la URL y decidir si está permitida o no. Si no, simplemente redirija a la página de inicio de sesión.

Una última cosa que queda para que funcione es pasarlo a nuestro componente principal en lugar del integrado.

@Component({
  selector: 'app',
  directives: [LoggedInRouterOutlet],
  template: template
})
@RouteConfig(...)
export class AppComponent { }

Esta solución no se puede utilizar con el @CanActive decorador de ciclo de vida, porque si la función que se le pasa se resuelve como falso, el método de activación del RouterOutlet no se llamará.

También escribí una publicación de blog detallada al respecto: https://medium.com/@blacksonic86/authentication-in-angular-2-958052c64492

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *