如何在Angular2 rc3路由中处理来自oauth重定向url的哈希片段
Posted
技术标签:
【中文标题】如何在Angular2 rc3路由中处理来自oauth重定向url的哈希片段【英文标题】:How to handle hash fragments from oauth redirect urls in Angular2 rc3 routing 【发布时间】:2016-11-10 09:21:37 【问题描述】:我正在尝试找到一种方法来处理设置 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 以在前端处理其余的身份验证/令牌业务。
然而,这个应用程序是 Angular2 和 Typescript,并且路由器查询参数似乎不太灵活,我在实施类似的解决方案时遇到了麻烦。我一直基于文档中的this section,但所有示例都在构建其他东西,例如/heroes
,然后再进入查询参数的复杂部分,例如/heroes/:id
。我也搜索了 ***,但找不到任何适用于 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 处理它们的身份验证,但无论我如何挖掘文档,我似乎都找不到它。任何有关如何实现这一点的建议将不胜感激。
【问题讨论】:
【参考方案1】:不只是假设您需要的值的索引,您可以使用以下方法从您想要的片段中获取键值对。
`
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'] 访问所需的值
【讨论】:
【参考方案2】:我最终能够找到一个使用首选 PathLocationStrategy 的解决方案,但也可以在删除哈希片段之后的部分 url 之前将令牌从 oauth 重定向 uri 中拉出(来自最终答案 here 被拉来自blog post 中的 QueryParams 和 Fragment 部分)。
基本上,我在使用 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 部分的方式。如果有人有更好的解决方案,请随时在此处更新/发布。
更新: 对上述登录组件代码的小更新,以处理 Angular v4.2.0 中的“片段可能为空”打字稿错误,并且在 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);
【讨论】:
你需要从window.location.hash中拉出accessToken
吗?我使用了一个基于ActivatedRoute
的稍微不同的示例,但它也有一个可观察的片段,片段的结果是 # 之后的数据。
@J.FritzBarnes 嗨,我在上面发布的原始答案截至 2016 年 7 月有效,但现在 Angular 2.0 最终版已经发布(我使用的是 2.4.0 版) )。我刚刚更新了我目前检索令牌的方式的答案,我怀疑这可能与您拉取它的方式相似,并且是我建议从 window.location.hash 拉取它的方式(当我第一次遇到这个问题时解决方案是有限的,一旦我切换到从路由片段中提取它,我就没有回去更新)。感谢您指出这一点!
@NColey 你在 IE 中测试过你的解决方案吗?当用户代理被重定向回 Angular 站点到 IE 中的 /login?token=blah 之类的 url 时,我收到 404 错误,这非常奇怪,适用于 chrome 和 firefox。此外,如果我只是在浏览器的 url 地址中点击相同的 url,它就可以工作。任何想法如何解决?
嗨@EvgenyFedorenko,这个代码所在的应用程序已经运行了大约一年,据我所知,在那段时间里我们在IE上没有任何登录问题。也许 404 错误来自一个不相关的问题?我还会检查您的 oauth 设置是什么,以确保重定向 url 最后有 /login
可能它正在重定向到其他地方。
@NColey 如果有帮助,我已经更新了您的答案,以包含 RxJS 6 的更新代码 sn-p。无论如何,感谢您的回答!非常感谢。以上是关于如何在Angular2 rc3路由中处理来自oauth重定向url的哈希片段的主要内容,如果未能解决你的问题,请参考以下文章
出于测试目的,如何在 angular2 中模拟已激活的父路由?