How do I set up Auth0 with Angular 2 useHash: true?

前提是你 提交于 2020-08-27 22:34:28

问题


The documentation and samples around using auth0 with angular 2 using hash routing (e.g. http://somdomain.com/#/someroute ) is pretty sparse and out of date.

There are multiple problems to address:

  1. auth0 librarylistens for a change in URL fragment. Unfortunately, angular swallows the URL fragment change because it thinks it is dealing with a route.

  2. the url fragment begins with #access_token=... and angular throws an error because access_token is not registered as a route.

  3. even if you register a route access_token you don't want to display it as a route any way, so you need to cancel the navigation.

What are all the things one has to do to actually set it up?


回答1:


First you'll need auth0-lock

 npm install --save auth0-lock

Next, you'll need an authentication service. The following Authentication Service implements login() and logout().

Before calling these methods, make sure you configure the service with registerAuthenticationWithHashHandler. This can be done in App.Component.ts

// AuthService.ts
import { environment } from './../environments/environment';
import { Injectable } from '@angular/core';
import { Router, RouterEvent } from '@angular/router';
import 'rxjs/add/operator/filter';
import 'rxjs/add/operator/take';
import { AuthCallbackComponent } from './../app/auth-callback/auth-callback.component';
import { AuthenticationCallbackActivateGuard } from '../app/auth-callback/auth-callback-activate-guard';
import Auth0Lock from 'auth0-lock';

@Injectable()
export class AuthService {

  private lock: Auth0Lock;

  constructor(public router: Router) {

    this.lock = new Auth0Lock(
      environment.auth0.clientID,
      environment.auth0.domain,
      {
        oidcConformant: true,
        autoclose: true,
        auth: {
          autoParseHash: false,
          redirectUrl: environment.auth0.redirectUri,
          responseType: 'token id_token',
          audience: environment.auth0.audience,
          params: {
            scope: 'openid'
          }
        }
      }
    );

  }

  public login(): void {
    this.lock.show();
  }

  // Call this method in app.component.ts
  // if using path-based routing
  public registerAuthenticationHandler(): void {
    this.lock.on('authenticated', (authResult) => {
      if (authResult && authResult.accessToken && authResult.idToken) {
        this.setSession(authResult);
        this.router.navigate(['/']);
      }
    });
    this.lock.on('authorization_error', (err) => {
      this.router.navigate(['/']);
      console.log(err);
      alert(`Error: ${err.error}. Check the console for further details.`);
    });
  }

  // Call this method in app.component.ts
  // if using hash-based routing
  public registerAuthenticationWithHashHandler(): void {

    this.registerAuthenticationHandler();
    this.workaroundHashAccessTokenRoute();

    this.router.events.take(1).subscribe(event => {

      if (!(event instanceof RouterEvent)) {
        return;
      }

      this.lock.resumeAuth(window.location.hash, (err, authResult) => {
        if (authResult && authResult.idToken) {
          this.lock.emit('authenticated', authResult);
        }

        if (authResult && authResult.error) {
          this.lock.emit('authorization_error', authResult);
        }
      });

    });
  }

  private workaroundHashAccessTokenRoute() {

    /* workaround useHash:true with angular2 router
    ** Angular mistakenly thinks "#access_token" is a route
    ** and we oblige by creating a fake route that can never be activated
    */
    const routes = this.router.config;
    routes.splice(0, 0, {
      path: 'access_token',
      component: AuthCallbackComponent,
      canActivate: [AuthenticationCallbackActivateGuard]
    });
    this.router.resetConfig(routes);
  }

  private setSession(authResult): void {
    // Set the time that the access token will expire at
    const expiresAt = JSON.stringify((authResult.expiresIn * 1000) + new Date().getTime());
    localStorage.setItem('access_token', authResult.accessToken);
    localStorage.setItem('id_token', authResult.idToken);
    localStorage.setItem('expires_at', expiresAt);
  }

  public logout(): void {
    // Remove tokens and expiry time from localStorage
    localStorage.removeItem('access_token');
    localStorage.removeItem('id_token');
    localStorage.removeItem('expires_at');
    // Go back to the home route
    this.router.navigate(['/']);
  }

  public isAuthenticated(): boolean {
    // Check whether the current time is past the
    // access token's expiry time
    const expiresAt = JSON.parse(localStorage.getItem('expires_at'));
    return new Date().getTime() < expiresAt;
  }
}

The registerAuthenticationWithHashHandler creates a dummy route called "access_token" and it is protected by a rule called AuthenticationCallbackActivateGuard that always returns false.

// auth-callback-activate-guard.ts
import { Injectable } from '@angular/core';
import { CanActivate } from '@angular/router';
import { Location } from '@angular/common';
import { Router } from '@angular/router';

@Injectable()
export class AuthenticationCallbackActivateGuard implements CanActivate {

  constructor(private router: Router, private location: Location) { }

  canActivate() {
    return false;
  }
}

Here are the parts you'll need for the dummy routes:

// auth-callback/auth-callback.components.ts
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-auth-callback',
  templateUrl: './auth-callback.component.html',
  styleUrls: ['./auth-callback.component.scss']
})
export class AuthCallbackComponent implements OnInit {

  constructor() { }

  ngOnInit() {
  }

}

Registering Authentication Service in App.Component.ts

// app/app.component.ts
import { Component } from '@angular/core';
import { AuthService } from '../services/auth.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'app';

  constructor(private auth: AuthService) {
    auth.registerAuthenticationWithHashHandler();
  }
}


来源:https://stackoverflow.com/questions/47764509/how-do-i-set-up-auth0-with-angular-2-usehash-true

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!