如何在 Angular2 rc3 路由中处理来自 oauth 重定向 url 的哈希片段
How to handle hash fragments from oauth redirect urls in Angular2 rc3 routing
我正在尝试找到一种方法来处理设置 Angular2 Typescript 路由(使用 3.0.0-alpha.8 路由器),该路由将处理以哈希片段开头的路由。
我正在开发的应用程序通过带有 oauth2 的 rails 后端处理所有外部登录(我无法控制的事情)。将用户重定向到外部登录页面工作正常,但是当重定向 url 时,总是会发回某种形式的 http://localhost:4200#access_token=TOKEN
(其中 TOKEN 是一系列数字和字母),但我不知道如何设置可以处理 #
标志的路由,以便我可以捕获它并重定向到适当的组件。
在以前的 Angular1 应用程序中,ui-router
能够在以下路线中使用:
.state('accessToken', {
url: '/access_token=:token',
controller: 'LoginController',
params: { token: null }
})
并且接受发回的重定向 url 没有问题,然后将所有内容传递给 LoginController 以处理前端其余的 authentication/token 业务。
然而,这个应用程序是 Angular2 和 Typescript,路由器查询参数似乎不太灵活,我在实施类似的解决方案时遇到了麻烦。我一直在基于文档中的 this section,但所有示例都在构建其他内容,例如 /heroes
,然后再进入查询参数的复杂部分,例如 /heroes/:id
。我也搜索了 Whosebug,但没能找到任何适用于 Angular2 和 Typescript 以及当前路由器的东西。
这是我当前(无效)的解决方案:
import { provideRouter, RouterConfig } from '@angular/router';
import { HomeComponent } from './components/home/home.component';
import { TestComponent } from './components/test/test.component';
export const appRoutes: RouterConfig = [
{
path: '',
component: HomeComponent,
terminal: true
},
{
path: 'access_token',
component: TestComponent
}
];
export const APP_ROUTER_PROVIDERS = [
provideRouter(appRoutes)
];
如果我采用发回的重定向 url 并将其修改(纯粹用于测试目的)为 http://localhost:4200/access_token=TOKEN
之类的内容,它就可以正常工作。不幸的是,我实际上无法控制现实生活中重定向 url 的格式,而且我无法想出一个解决方案来处理它以散列片段而不是 /
然后是我的查询参数。我能找到的所有带有复杂符号或字符的路由示例都以 /
开头。
我尝试将上面的解决方案修改为 :access_token
,但没有用,并且将其列为基本路由下的子路由,如下所示:
{
path: '',
component: HomeComponent,
terminal: true,
children: [
{ path: 'access_token', component: TestComponent },
]
}
导致以下控制台错误:
platform-browser.umd.js:2312 EXCEPTION: Error: Uncaught (in promise): Error: Cannot match any routes: ''
我觉得绝对必须有一个干净的解决方案来解决这个问题,尤其是因为有这么多 API 通过像这样的重定向 url 来处理它们的身份验证,但无论我如何深入研究文档,我都可以'好像找不到。非常感谢有关如何实施此建议的任何建议。
我最终找到了一个解决方案,该解决方案使用首选 PathLocationStrategy,但也在散列片段被丢弃后 url 部分之前从 oauth 重定向 uri 中提取令牌(来自最终答案here which is pulled from the QueryParams and Fragment section in the following blog post).
基本上我在使用 doorkeeper/oauth2 注册我的应用程序时将重定向 url 更新为 http://localhost:4200/login/ (这导致包含令牌的重定向 url 看起来像 http://localhost:4200/login/#access_token=TOKEN
) 并添加了以下路由:
{
path: 'login',
component: LoginComponent
}
这会捕获重定向 url 但会丢弃散列片段之后的所有内容,从而删除我需要的令牌。为了防止它在散列片段之后删除所有内容,我将以下代码添加到 LoginComponent
:
的构造函数中
constructor(private activatedRoute: ActivatedRoute,
private router: Router,
private tokenService: TokenService) {
// Pulls token from url before the hash fragment is removed
const routeFragment: Observable<string> = activatedRoute.fragment;
routeFragment.subscribe(fragment => {
let token: string = fragment.match(/^(.*?)&/)[1].replace('access_token=', '');
this.tokenService.setToken(token);
});
}
您选择如何处理令牌完全取决于您(我有一个 TokenService,其中包含从 localStorage 设置、检索和清除它的方法),但这就是您访问 url 部分的方式在散列片段之后。如果有人有更好的解决方案,请在这里 update/post。
更新:
对上述登录组件代码进行小幅更新,以处理 Angular v4.2.0 中的 'fragment is possibly null' typescript 错误,并在 tsconfig.json 中将 strictNullChecks 设置为 true 以备不时之需。功能相同:
let routeFragment = this.activatedRoute.fragment.map(fragment => fragment);
routeFragment.subscribe(fragment => {
let f = fragment.match(/^(.*?)&/);
if(f) {
let token: string = f[1].replace('access_token=', '');
this.tokenService.setToken(token);
}
注意:从 RxJS 6 开始,map
运算符已成为可管道化的,这意味着您必须在 Observable
的 pipe
方法中传递它,如下所示:
import { map } from 'rxjs/operators';
// ...
this.activatedRoute.fragment
.pipe(map(fragment => fragment))
.subscribe(fragment => {
let f = fragment.match(/^(.*?)&/);
if(f) {
let token: string = f[1].replace('access_token=', '');
this.tokenService.setToken(token);
}
无需假设您需要的值的索引,您可以使用以下方法从您想要的片段中获取键值对。
constructor(private route: ActivatedRoute) {}
ngOnInit(): void {
const fragment: string = this.route.snapshot.fragment;
this.processFragment(fragment);
}
processFragment(fragmentString) {
var ar = fragmentString.split('&');
var result = {}
for (var i = 0; i < ar.length; i++) {
var split = ar[i].indexOf("=");
var key = ar[i].slice(0, split);
result[key] = ar[i].slice(split + 1);
}
return result;
}
在“结果”对象中,您可以通过 result['key']
访问所需的值。
我正在尝试找到一种方法来处理设置 Angular2 Typescript 路由(使用 3.0.0-alpha.8 路由器),该路由将处理以哈希片段开头的路由。
我正在开发的应用程序通过带有 oauth2 的 rails 后端处理所有外部登录(我无法控制的事情)。将用户重定向到外部登录页面工作正常,但是当重定向 url 时,总是会发回某种形式的 http://localhost:4200#access_token=TOKEN
(其中 TOKEN 是一系列数字和字母),但我不知道如何设置可以处理 #
标志的路由,以便我可以捕获它并重定向到适当的组件。
在以前的 Angular1 应用程序中,ui-router
能够在以下路线中使用:
.state('accessToken', {
url: '/access_token=:token',
controller: 'LoginController',
params: { token: null }
})
并且接受发回的重定向 url 没有问题,然后将所有内容传递给 LoginController 以处理前端其余的 authentication/token 业务。
然而,这个应用程序是 Angular2 和 Typescript,路由器查询参数似乎不太灵活,我在实施类似的解决方案时遇到了麻烦。我一直在基于文档中的 this section,但所有示例都在构建其他内容,例如 /heroes
,然后再进入查询参数的复杂部分,例如 /heroes/:id
。我也搜索了 Whosebug,但没能找到任何适用于 Angular2 和 Typescript 以及当前路由器的东西。
这是我当前(无效)的解决方案:
import { provideRouter, RouterConfig } from '@angular/router';
import { HomeComponent } from './components/home/home.component';
import { TestComponent } from './components/test/test.component';
export const appRoutes: RouterConfig = [
{
path: '',
component: HomeComponent,
terminal: true
},
{
path: 'access_token',
component: TestComponent
}
];
export const APP_ROUTER_PROVIDERS = [
provideRouter(appRoutes)
];
如果我采用发回的重定向 url 并将其修改(纯粹用于测试目的)为 http://localhost:4200/access_token=TOKEN
之类的内容,它就可以正常工作。不幸的是,我实际上无法控制现实生活中重定向 url 的格式,而且我无法想出一个解决方案来处理它以散列片段而不是 /
然后是我的查询参数。我能找到的所有带有复杂符号或字符的路由示例都以 /
开头。
我尝试将上面的解决方案修改为 :access_token
,但没有用,并且将其列为基本路由下的子路由,如下所示:
{
path: '',
component: HomeComponent,
terminal: true,
children: [
{ path: 'access_token', component: TestComponent },
]
}
导致以下控制台错误:
platform-browser.umd.js:2312 EXCEPTION: Error: Uncaught (in promise): Error: Cannot match any routes: ''
我觉得绝对必须有一个干净的解决方案来解决这个问题,尤其是因为有这么多 API 通过像这样的重定向 url 来处理它们的身份验证,但无论我如何深入研究文档,我都可以'好像找不到。非常感谢有关如何实施此建议的任何建议。
我最终找到了一个解决方案,该解决方案使用首选 PathLocationStrategy,但也在散列片段被丢弃后 url 部分之前从 oauth 重定向 uri 中提取令牌(来自最终答案here which is pulled from the QueryParams and Fragment section in the following blog post).
基本上我在使用 doorkeeper/oauth2 注册我的应用程序时将重定向 url 更新为 http://localhost:4200/login/ (这导致包含令牌的重定向 url 看起来像 http://localhost:4200/login/#access_token=TOKEN
) 并添加了以下路由:
{
path: 'login',
component: LoginComponent
}
这会捕获重定向 url 但会丢弃散列片段之后的所有内容,从而删除我需要的令牌。为了防止它在散列片段之后删除所有内容,我将以下代码添加到 LoginComponent
:
constructor(private activatedRoute: ActivatedRoute,
private router: Router,
private tokenService: TokenService) {
// Pulls token from url before the hash fragment is removed
const routeFragment: Observable<string> = activatedRoute.fragment;
routeFragment.subscribe(fragment => {
let token: string = fragment.match(/^(.*?)&/)[1].replace('access_token=', '');
this.tokenService.setToken(token);
});
}
您选择如何处理令牌完全取决于您(我有一个 TokenService,其中包含从 localStorage 设置、检索和清除它的方法),但这就是您访问 url 部分的方式在散列片段之后。如果有人有更好的解决方案,请在这里 update/post。
更新: 对上述登录组件代码进行小幅更新,以处理 Angular v4.2.0 中的 'fragment is possibly null' typescript 错误,并在 tsconfig.json 中将 strictNullChecks 设置为 true 以备不时之需。功能相同:
let routeFragment = this.activatedRoute.fragment.map(fragment => fragment);
routeFragment.subscribe(fragment => {
let f = fragment.match(/^(.*?)&/);
if(f) {
let token: string = f[1].replace('access_token=', '');
this.tokenService.setToken(token);
}
注意:从 RxJS 6 开始,map
运算符已成为可管道化的,这意味着您必须在 Observable
的 pipe
方法中传递它,如下所示:
import { map } from 'rxjs/operators';
// ...
this.activatedRoute.fragment
.pipe(map(fragment => fragment))
.subscribe(fragment => {
let f = fragment.match(/^(.*?)&/);
if(f) {
let token: string = f[1].replace('access_token=', '');
this.tokenService.setToken(token);
}
无需假设您需要的值的索引,您可以使用以下方法从您想要的片段中获取键值对。
constructor(private route: ActivatedRoute) {}
ngOnInit(): void {
const fragment: string = this.route.snapshot.fragment;
this.processFragment(fragment);
}
processFragment(fragmentString) {
var ar = fragmentString.split('&');
var result = {}
for (var i = 0; i < ar.length; i++) {
var split = ar[i].indexOf("=");
var key = ar[i].slice(0, split);
result[key] = ar[i].slice(split + 1);
}
return result;
}
在“结果”对象中,您可以通过 result['key']
访问所需的值。