使用 Angular 2+ 的社交登录时,组件之间的信息以何种方式传递?

Posted

技术标签:

【中文标题】使用 Angular 2+ 的社交登录时,组件之间的信息以何种方式传递?【英文标题】:In what way is the information passed between components when using social signin with angular 2+? 【发布时间】:2018-07-04 08:10:12 【问题描述】:

我计划通过以下方式为我的应用程序支持多种登录选项(包括使用 google 和 facebook 进行社交登录)。 当用户单击使用 google/facebook 登录时,会打开一个新窗口,用户身份验证完成,服务器返回 JWT,我存储在本地存储中并使用 hostlistener,前一个窗口(或父窗口)知道成功的身份验证。

此流程运行良好(使用正常的服务器端身份验证),但我正在考虑将 JWT 存储在本地存储中可能引起的安全问题。使用社交登录时共享身份验证信息的标准方式是什么?

有没有更好的方法将 JWT/身份验证详细信息从子窗口(身份验证发生的地方)传递到父窗口? 另一种选择是使用 Eventemitters 在两个组件之间传递信息,但是使用社交登录和 jwt 的网站使用的标准方式是什么?

编辑:我想复制大多数网站的行为,即在用户通过身份验证之前,父窗口保持静止,一旦身份验证完成并传递到父窗口,它重定向到让我们说主页或重定向网址。

【问题讨论】:

为什么要打开一个新窗口进行身份验证?它使用户体验更差,并且在移动设备上可能会出现问题。如果有其他方法并且 OAuth2 身份验证不需要它,我不会这样做。 因为在新窗口中,可以有多个登录选项,其中一些可能会重定向到外部域(例如 google.com)。我看到的所有网站也都在新窗口中实现了社交登录。另外,我计划为我的 2-3 个应用程序提供相同的身份验证机制。 【参考方案1】:

如果您确实想使用弹出窗口进行身份验证,您可以使用弹出窗口访问应用程序的父窗口

window.opener

从弹出窗口向父级发送令牌的最简单方法是发布消息(请参阅Mozilla docs)

window.opener.postMessage(messageContainingToken, window.location.origin);

父窗口需要有监听器

window.addEventListener("message", receiveTokenMessage, false);

function receiveTokenMessage(event) 
   if (event.origin !== window.location.origin) 
       return;
   
   let messageContainingToken = event.data;

messageContainingToken 可以是令牌本身,也可以是一些更复杂的 JSON。然后就可以将token存储在SessionStorage中,比LocalStorage更安全。

更新(建议):

我建议你不要使用弹出窗口。相反,在登录页面上,我会为“使用 SomeOauth2Provider 登录”创建按钮。当用户单击按钮时,他会被重定向到 SomeOauth2Provider 网站,并且在身份验证后,他会被重定向回您的 Angular SPA(您提供一个 redirectUri)。处理包含令牌的 redirectUri 的 Angular 组件将验证令牌,将其保存到 SessionStorage 并将路由更改为应用程序的某些初始视图。

我认为在重定向后再次加载 Angular 应用程序比打开新窗口(也可以禁用)更加用户友好。

【讨论】:

谢谢。您还可以分享网站最常用的方式吗?我的意思是几乎每三个网站我们都会看到社交登录选项。在使用 Angular 构建的那些中,他们是如何进行这种通信的。有标准的方法吗? 我用我将如何做的信息更新了答案。 当我使用 window.opener.postMessage(messageContainingToken, window.location.origin, false);,我收到错误:TypeError: Failed to execute 'postMessage' on 'Window': The provided值不能转换为序列。 postMessage 使用The structured clone algorithm 进行消息值序列化。它有其局限性,因此您可能发送的东西不兼容。您可以尝试使用一个简单的字符串作为应该始终被接受的值。 你是对的,postMessage方法的最后一个boolean transfer参数应该省略,这样你就不会报错。我更新了答案。【参考方案2】:

我建议使用 firebase。他们有角度的、生产就绪的社交登录实现包。看看:https://firebase.google.com/products/auth/

有一篇关于使用 Firebase 为 Angular 应用程序验证用户的好文章:https://medium.com/@hellotunmbi/step-by-step-complete-firebase-authentication-in-angular-2-97ca73b8eb32

【讨论】:

【参考方案3】:

我的建议是使用 Centralized State Management@ngrx/store,这样您就可以将 JWT 和用户声明存储在应用程序的状态中从应用程序的每个部分使用它。

以下链接可能有助于启动:

https://auth0.com/blog/managing-state-in-angular-with-ngrx-store/

https://github.com/ngrx/platform/blob/master/docs/store/README.md

https://blog.angular-university.io/angular-ngrx-store-and-effects-crash-course/

然后您可以使用 HTTPInterceptor 将令牌添加到标头中。如果您使用像 angular-oauth2-oidc 这样的 OAuth 库,则不必担心这一点,因为它带有自己的拦截器,但您应该取消提供自己的拦截器以防万一。

localStoragesessionStorage 都扩展了存储。除了sessionStorage的预期“非持久性”之外,它们之间没有区别。

也就是说,存储在localStorage 中的数据会一直存在,直到被明确删除。所做的更改会保存下来,可供所有当前和将来访问该网站的用户使用。

对于sessionStorage,更改仅适用于每个窗口(或 Chrome 和 Firefox 等浏览器中的选项卡)。所做的更改被保存并可用于当前页面,以及将来在同一窗口中访问该站点。窗口关闭后,存储被删除。

Web 存储 (localStorage/sessionStorage) 可通过同一域上的 JavaScript 访问。这意味着在您的网站上运行的任何 JavaScript 都可以访问网络存储,因此很容易受到跨站脚本 (XSS) 攻击。简而言之,XSS 是一种漏洞,攻击者可以在其中注入将在您的页面上运行的 JavaScript

使用饼干代替!!! CookiesHttpOnly cookie 标志一起使用时,无法通过 JavaScript 访问,并且不受 XSS 的影响。您还可以设置 Secure cookie 标志以保证 cookie 仅通过 HTTPS 发送。

【讨论】:

以上是关于使用 Angular 2+ 的社交登录时,组件之间的信息以何种方式传递?的主要内容,如果未能解决你的问题,请参考以下文章

start_url / index页面上的Angular 9 PWA社交登录重定向问题

如何使用 Angular 和 Spring Boot 添加社交登录功能

使用服务不起作用的 2 个组件之间的交互 ​​Angular 6/7

使用服务 Angular 在组件之间传递数据

使用 Angular CLI 在组件之间处理数据时遇到问题

如何在角度2的组件之间传递用户输入数据?