如何使用 HashLocationStrategy 和 Auth0 Lock 小部件进行用户登录 [英] How to use the HashLocationStrategy with the Auth0 Lock widget for user login

查看:25
本文介绍了如何使用 HashLocationStrategy 和 Auth0 Lock 小部件进行用户登录的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

更新Auth0 登录示例后app.module.ts 中使用 HashLocationStrategy:

import { LocationStrategy, HashLocationStrategy } from '@angular/common';//(...)@NgModule({供应商: [{提供:LocationStrategy,useClass:HashLocationStrategy},appRoutingProviders,AUTH_PROVIDERS],//(...)

Auth0 Lock authenticated 事件不再引发:

import { Injectable } from '@angular/core';从 'angular2-jwt' 导入 { tokenNotExpired };//避免名称未找到警告声明 var Auth0Lock: 任何;@Injectable()导出类 Auth0Service {//配置 Auth0lock = new Auth0Lock('I21EAjbbpf...', '....au.auth0.com', {});构造函数(){//为 lock `authenticated` 事件添加回调this.lock.on("已认证", (authResult) => {//使用authResult中的token到getProfile()并保存到localStoragethis.lock.getProfile(authResult.idToken, function(error, profile) {如果(错误){//处理错误返回;}localStorage.setItem('id_token', authResult.idToken);localStorage.setItem('profile', JSON.stringify(profile));});});}//(...)

解决方案

您遇到此问题的原因是 Angular 2 路由器会在路由导航时自动清理 URL,导致 Auth0 Lock 永远看不到数据需要对用户进行身份验证.从 GitHub 来看,这种行为并不总是这样,但它是当前的行为.请参阅RC2 路由器在匹配路由后从路径中去除额外参数导航不应该为某些背景保留查询参数和片段.

执行登录后,Auth0 将请求您的浏览器导航到类似于此的 URL:

http://example.com/#access_token=RENH3twuqx&id_token=eyJ0.epcOidRwc.Qdx3ac&token_type=Bearer

此 URL 包含 Lock 识别用户已通过身份验证的所有必要信息,但是,前面提到的 Angular 路由器行为意味着在 Lock 有机会处理此信息之前,身份验证数据包含在 URL 片段中的内容被删除,将 URL 保留为 (http://example.com/#/).发生这种情况是因为您很可能已经配置了一个匹配任何 URL 的全能路由.

假设您配置了以下路由:

const appRoutes: Routes = [{ 路径:'',组件:HomeComponent },{ 路径:'**',重定向到:'' }];

<小时><块引用>

免责声明:下面显示的第一个解决方案是作为一种变通方法提供的,经证明适用于 Angular 2.0.0、Angular 路由器 3.0.0 与 Lock 10.2 一起使用.从那时起,路由器和/或锁似乎发生了变化,导致最初的解决方法失败.我提供了第二种解决方法,它似乎适用于 Angular 2.4.1、Angular 路由器 3.4.1 和 Lock 10.7.>

<小时>

解决方法 #1 - (angular/core@2.0.0, angular/router@3.0.0, lock@10.2)

尝试规避此默认行为的一种可能方法是执行以下步骤:

  1. 向正在处理身份验证回调请求的路由添加激活保护,如果当前 URL 看起来像是登录的结果(例如,包含 access_token),则不允许路由激活 其片段中的关键字.
  2. 在触发身份验证事件后,强制导航到您想要的路线,以便应用程序识别登录.

您可以创建以下类:

import { Injectable } from '@angular/core';从'@angular/router'导入{CanActivate};从@angular/common"导入{位置};@Injectable()导出类 AuthenticationCallbackActivateGuard 实现 CanActivate {构造函数(私有位置:位置){}可以激活(){//你可能想在这里做一个更健壮的检查返回 this.location.path(true).indexOf("access_token") === -1;}}

将其注册为回家路线的守卫:

const appRoutes: Routes = [{ path: '', 组件: HomeComponent, canActivate: [AuthenticationCallbackActivateGuard] },{ 路径:'**',重定向到:''}];导出 const appRoutingProviders: any[] = [AuthenticationCallbackActivateGuard];

最后,在身份验证后导航到您的路线:

this.lock.on('authenticated', (authResult) => {localStorage.setItem('id_token', authResult.idToken);this.router.navigate([''], {});});

解决方法 #2 - (angular/core@2.4.1, angular/router@3.4.1, lock@10.7)

与之前所做的类似,但命令式导航是在警卫本身上完成的,并使用作为片段提供的身份验证回调数据,以便 Lock 在处理事件时能够看到此信息.由于导航移到了守卫,您不再需要对锁定认证事件进行导航.

创建以下类:

import { Injectable } from '@angular/core';从'@angular/router'导入{CanActivate};从@angular/common"导入{位置};从@angular/router"导入{路由器};@Injectable()导出类 AuthenticationCallbackActivateGuard 实现 CanActivate {构造函数(私有路由器:路由器,私有位置:位置){}可以激活(){var path = this.location.path(true);//你可能想在这里做一个更健壮的检查var isAuthenticationCallback = path.indexOf("access_token") !== -1;如果(isAuthenticationCallback){this.router.navigate([''], { fragment: path });返回假;}返回真;}}

将其注册为回家路线的守卫:

const appRoutes: Routes = [{ path: '', 组件: HomeComponent, canActivate: [AuthenticationCallbackActivateGuard] },{ 路径:'**',重定向到:'' }];导出 const appRoutingProviders: any[] = [AuthenticationCallbackActivateGuard];

最后,处理身份验证事件:

this.lock.on('authenticated', (authResult) => {localStorage.setItem('id_token', authResult.idToken);});

After updating the Auth0 login sample to use HashLocationStrategy in app.module.ts:

import { LocationStrategy, HashLocationStrategy } from '@angular/common';
// (...)
@NgModule({
  providers: [
    {provide: LocationStrategy, useClass: HashLocationStrategy},
    appRoutingProviders,
    AUTH_PROVIDERS
  ],  
//(...)

The Auth0 Lock authenticated event is not raised anymore:

import { Injectable } from '@angular/core';
import { tokenNotExpired } from 'angular2-jwt';

// Avoid name not found warnings
declare var Auth0Lock: any;

@Injectable()
export class Auth0Service {

  // Configure Auth0
  lock = new Auth0Lock('I21EAjbbpf...', '....au.auth0.com', {});

  constructor() {
    // Add callback for lock `authenticated` event
    this.lock.on("authenticated", (authResult) => {
      // Use the token in authResult to getProfile() and save it to localStorage
      this.lock.getProfile(authResult.idToken, function(error, profile) {
        if (error) {
          // Handle error
          return;
        }

        localStorage.setItem('id_token', authResult.idToken);
        localStorage.setItem('profile', JSON.stringify(profile));
      });
    });    
  }
// (...)

解决方案

The reason you're experiencing this issue is because the Angular 2 router will automatically cleanup the URL upon route navigation causing Auth0 Lock to never see the data required to authenticate the user. Judging from GitHub, this behavior was not always like this, but it's the current one. See RC2 Router strips extra arguments from the path after matching a route and navigation should not preserve query params and fragment for some background.

Upon performing the login Auth0 will request your browser to navigate into an URL similar to this:

http://example.com/#access_token=RENH3twuqx&id_token=eyJ0.epcOidRwc.Qdx3ac&token_type=Bearer

This URL contains all the necessary information for Lock to recognize that the user is authenticated, however, the previously mentioned Angular router behavior means that before Lock having a chance to process this information, the authentication data contained in the URL fragment is stripped, leaving the URL as (http://example.com/#/). This happens because you most likely have configured a catch-all route that matches any URL.

Assuming you have the following routes configured:

const appRoutes: Routes = [
  { path: '', component: HomeComponent },
  { path: '**', redirectTo: '' }
];


DISCLAIMER: The first solution that will be shown below was provided as a workaround that proved functional for Angular 2.0.0, Angular router 3.0.0 used with Lock 10.2. Since then, it seems the router and/or Lock suffered changes that made the initial workaround fail. I'm providing a second workaround that seems to be functional with Angular 2.4.1, Angular router 3.4.1 and Lock 10.7.


Workaround #1 - (angular/core@2.0.0, angular/router@3.0.0, lock@10.2)

One possible way to try to circumvent this default behavior is to perform the following steps:

  1. Add an activation guard to the route that is handling the authentication callback request in such way as to not allow the route to activate if the current URL seems like to be the result of login (for example, contains the access_token keyword in its fragment.
  2. Upon the authenticated event being triggered force the navigation to your desired route so that the application recognizes the login.

You could create the following class:

import { Injectable } from '@angular/core';
import { CanActivate } from '@angular/router';
import { Location } from '@angular/common';

@Injectable()
export class AuthenticationCallbackActivateGuard implements CanActivate {

  constructor(private location: Location) { }

  canActivate() {
    // You may want to make a more robust check here
    return this.location.path(true).indexOf("access_token") === -1;
  }
}

Register it as a guard for your home route:

const appRoutes: Routes = [
  { path: '', component: HomeComponent, canActivate: [AuthenticationCallbackActivateGuard] },
  { path: '**', redirectTo: '' }
];

export const appRoutingProviders: any[] = [
  AuthenticationCallbackActivateGuard
];

And finally, navigate to your route after authentication:

this.lock.on('authenticated', (authResult) => {
  localStorage.setItem('id_token', authResult.idToken);
  this.router.navigate([''], {});
});

Workaround #2 - (angular/core@2.4.1, angular/router@3.4.1, lock@10.7)

Similar to what was done before, but the imperative navigation is done on the guard itself with the authentication callback data provided as fragment so that Lock is able to see this information when processing events. Since navigation moved to the guard, you no longer need to do the navigation on the lock authenticated event.

Create the following class:

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() {
    var path = this.location.path(true);

    // You may want to make a more robust check here
    var isAuthenticationCallback = path.indexOf("access_token") !== -1;

    if (isAuthenticationCallback) {
      this.router.navigate([''], { fragment: path });

      return false;
    }

    return true;
  }
}

Register it as a guard for your home route:

const appRoutes: Routes = [
  { path: '', component: HomeComponent, canActivate: [AuthenticationCallbackActivateGuard] },
  { path: '**', redirectTo: '' }
];

export const appRoutingProviders: any[] = [
  AuthenticationCallbackActivateGuard
];

And finally, handle the authentication event:

this.lock.on('authenticated', (authResult) => {
  localStorage.setItem('id_token', authResult.idToken);
});

这篇关于如何使用 HashLocationStrategy 和 Auth0 Lock 小部件进行用户登录的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆