【发布时间】:2017-04-14 02:01:53
【问题描述】:
Auth0 要求您在身份验证后将回调 URL 列入白名单,因此您不能只使用 /thing/1、/thing/1001 等 URL 登录应用程序中的任何页面,因为无法通配事物 ID。
这个Github conversation 指向我在Angular 2 中解释为的简洁解决方案:
在我的 auth.service.ts 中:
lock = new Auth0Lock('Client_ID', 'Domain', {
auth: {
redirectUrl: window.location.origin + '/login',
responseType: 'token',
params: {
scope: 'openid name email',
state: JSON.stringify({pathname: window.location.pathname})
}
}
});
然后我可以在 Angular 2 中将我的 /login 路由列入白名单。我尝试让我的 login.component.ts 读取,然后导航到 Auth0 在回调中返回的路径名,如下所示:
this.route
.queryParams
.subscribe(params => {
this.state = params['state'];
this.router.navigate(this.state, {preserveQueryParams: true});
});
...但是 params 似乎总是为空。据我所知,这是因为回调 URL 采用这种形式:
...并且 Angular 2 路由会在 # 参数到达 LoginComponent 之前自动剥离它们。
然后我发现 lock.authenticated 上的 authResult 仍然包含我在 auth.service.ts 中的状态参数,因此尝试按如下方式导航到它:
this.lock.on("authenticated", (authResult:any) => {
localStorage.setItem('id_token', authResult.idToken);
let state: string = JSON.parse(authResult.state);
this.router.navigate([state.pathname], {});
这似乎最初有效,但事实证明,并不可靠......它似乎将我从任何地方重定向到不可预测的任何地方
/thing/1001 to
/things or even
/
...我不知道为什么。非常感谢任何帮助。
编辑回应@shusson 的回答:
基于@shusson 答案的工作代码在 auth.service.ts 中:
export class Auth {
// Configure Auth0
lock = new Auth0Lock('Client_ID', 'Domain',{
auth: {
redirectUrl: location.origin + '/login',
responseType: 'token',
}
});
constructor(private router: Router, route: ActivatedRoute) {
// Add callback for lock `authenticated` event
this.lock.on("authenticated", (authResult:any) => {
localStorage.setItem('id_token', authResult.idToken);
let state: any = JSON.parse(authResult.state);
this.router.navigate([state.pathname], {});
...
}
public login() {
// Call the show method to display the widget.
this.lock.show({
auth: {
params: {
scope: 'openid name email',
state: JSON.stringify({pathname: this.router.url})
}
}
});
};
编辑:基于this comment re:在回调中传递路径是一个 CSRF 漏洞:
我的 auth.service.ts 中的最终工作代码是:
import { Injectable } from '@angular/core';
import { tokenNotExpired } from 'angular2-jwt/angular2-jwt';
import { Router, ActivatedRoute } from '@angular/router';
import { UUID } from 'angular2-uuid/index';
// Avoid name not found warnings
declare var Auth0Lock: any;
@Injectable()
export class Auth {
// Configure Auth0
lock = new Auth0Lock('Client_ID', 'Domain',{
auth: {
redirectUrl: location.origin + '/login',
responseType: 'token',
}
});
//Store profile object in auth class
userProfile: Object;
constructor(private router: Router, route: ActivatedRoute) {
// Set userProfile attribute of already saved profile
this.userProfile = JSON.parse(localStorage.getItem('profile'));
// Add callback for lock `authenticated` event
this.lock.on("authenticated", (authResult:any) => {
localStorage.setItem('id_token', authResult.idToken);
let pathname_object: any = JSON.parse(authResult.state);
let pathname: any = localStorage.getItem(pathname_object.pathname_key);
//get rid of localStorage of url
localStorage.removeItem(pathname_object.pathname_key);
//navigate to original url
this.router.navigate([pathname], {});
// Fetch profile information
this.lock.getProfile(authResult.idToken, (error:any, profile:any) => {
if (error) {
// Handle error
alert(error);
return;
}
localStorage.setItem('profile', JSON.stringify(profile));
this.userProfile = profile;
});
});
}
public login() {
//generate UUID against which to store path
let uuid = UUID.UUID();
localStorage.setItem(uuid, this.router.url);
// Call the show method to display the widget.
this.lock.show({
auth: {
params: {
scope: 'openid name email',
state: JSON.stringify({pathname_key: uuid})
}
}
});
};
...
}
【问题讨论】: