我需要在我的Web应用程序中实现Facebook和Google登录。我还需要访问用户的Facebook / Google +朋友列表。
我已经阅读了Facebook和Google的完整OAuth2文档。我了解基本概念。例如,假设对于Facebook登录,步骤如下:


用户将单击“ FB登录”按钮。
将要求用户登录Facebook并允许允许。如果用户允许,它将返回授权码。
现在我们将使用授权码来获取访问令牌。
我们可以将访问令牌存储在会话中以启动用户会话。
现在我们可以使用访问令牌来访问不同的用户资源。

现在,在第3步之后我有些困惑。我们应该在用户每次登录时生成访问令牌还是将访问令牌存储在数据库中?

如果我们将访问令牌存储在数据库中,那么当用户在10天后访问我们的网站(假设他清除了浏览器cookie)并单击“ FB登录”按钮时,我们如何重用它?再次。因为当用户再次单击“ FB登录”按钮时,他将获得新的授权码,并且必须再次启动完整的过程。如何识别该用户在我的数据库中已经有访问令牌?

任何帮助将不胜感激。

评论

作为附带说明,需要牢记的一件事是与访问令牌相关的安全性。我希望它不会以纯文本格式存储(例如未加密)。

我认为您的最后一个问题未得到回答:“如何识别该用户在我的数据库中已经有访问令牌?”

#1 楼

从技术上讲,您可以将访问令牌存储在数据库中,并将其用于API调用,直到过期为止。但是,这可能比它的价值还要麻烦。

一方面,正如乔纳森(Jonathan)在上面的评论中指出的那样,现在您必须担心保护数据库及其中的数据的安全-这些令牌可以访问有关您用户的一些特权信息。当然,仅将令牌存储在会话存储中也可能会将其也放在磁盘上,这取决于您的会话配置。在不使用它时将其保持加密是一个好主意。

您提出的有关用户清除cookie并返回的方案也是一个问题。您可以从数据库中获取访问令牌并将其重新粘贴到他们的cookie中,但是在执行此操作之前,您必须确保他们是他们所说的人-现在,您必须再做一层密码才能给他们访问他们已经给您的令牌。

您最好再重新做一次授权流程,当他们回来时再次单击登录按钮。它不是那么昂贵。但是,如果那确实是您的首选,那么可以选择存储令牌。您在处理所有相关问题时必须非常小心。

评论


我有完全一样的问题。问题是,每次他们登录时,都会建立新的OAuth会话。登录20次后,将打开20个“松散”会话。如果您转到服务提供商站点上列出授权令牌的页面,则看起来很头疼。你怎么处理那件事呢?

– Konrad Garus
15年10月30日在9:28

@Konrad Garus大多数提供者,例如facebook或google,都会将单个应用程序的会话关联到单个条目中,并在登录时使较早的访问令牌无效。

–乔纳斯·柯瑞兹(JonasKöritz)
17年5月8日在11:21

#2 楼

我一直在考虑这个问题,可能会想出一个对我们有用的答案,尽管我不能说它是否对您有用。

在我们的环境中,我们的主要原因在某些自动化或后端过程完成后或按计划进行操作时,可能需要使用访问令牌来代表用户进行操作。在这种情况下,我们不能简单地要求用户再次登录,因为该用户没有直接参与此工作流程(他会要求完成工作,但在完成时并不在那里)。因此,我们必须以某种方式访问​​访问令牌。

当然,如果不引起问题,我也想在可行的情况下跳过重新授权。

但是我也不喜欢在Web服务器上存储使用访问令牌所需的所有内容的想法。因此,即使我对数据库中的访问令牌进行了加密,也无法真正消除我担心加密密钥是否存储在Web服务器上的担忧。哎呀,客户端机密和应用程序ID也在那里,所以就这些了。<​​br />
所以这是我建议的解决方案,它需要四个参与者:

Web服务器存储了appid ,密码和数据库连接字符串(当然)。获取应用程序令牌后,它将生成随机对称加密密钥并加密访问令牌。数据库获取加密的访问令牌,并且加密密钥存储在客户端cookie中。同时,Web服务器将加密密钥和用户ID成对发送到后端系统。

当客户端使用站点时,可以通过使用客户端cookie解密数据库中的访问令牌来避免重新认证。如果Cookie消失了,无论如何都必须进行重新认证。后端系统(其攻击面比Web服务器要小得多)还具有数据库连接字符串,因此它是所有必需信息将驻留与用户信息进行交互的唯一位置。它可以在访问令牌的整个生命周期内随意使用该信息。

这将使Web服务器只能短暂访问任何访问令牌,并且该令牌永远不会存储在客户端上。对我来说,这似乎很安全,尽管也许有人会说它是过度设计的。有想法吗?

评论


您的Web服务器角色和*“后端系统”角色之间有什么区别?如果它们都是在远程系统中运行的程序,除了系统管理员之外,其他任何人都无法访问它们,那么它们将被视为“机密客户端”定义,因此您不必真的将它们分开,或者您只是认为Web服务器可以打开端口并侦听流量,而后端系统则不能,因此从理论上讲更安全?

– RayLuo
17年2月8日,1:13

基本上你做对了。在我的环境中,Web应用程序收集有关计算密集型作业的信息,并将后端处理的请求(在没有客户端请求的情况下唯一需要使用的访问令牌)放置在消息队列中。后端系统是一个没有入站访问权限的完整孤岛,它从队列中拉出请求,因此它应该是高度安全的。甚至对Web服务器的完全破坏也无法提供攻击后端的方法。 (当用户再次登录时,攻击者当然可以随着时间的流逝获取访问令牌。)

– Dominic P
17年2月13日在17:59

我也不太了解“ Web服务器”和“后端系统”之间的区别。不过,我喜欢您的建议,将加密密钥保留为cookie。对于我们来说,唯一的问题是,有时您将无法使用您提出的解决方案在用户不活跃的情况下访问用户数据。

–迪尔西娜
20-05-23在12:31

我非常喜欢这个解决方案,但是非常聪明,如果一个客户端通过多个客户端(移动应用,Web应用,...)访问服务器,那么该解决方案将不起作用,因为只能在以下位置读取一个“客户端”的access_token时间(因为密钥存储在客户端cookie中)。

– Rochadsouza
20-05-31在15:30

@dearsina我们的方案依赖于一个自动化的工作节点来处理队列消息,这可能是在用户与站点进行交互之后的几天或几周,以实现用户请求。该工作程序节点几乎没有攻击面,因此可以通过访问令牌对其进行持久性访问用户数据的访问是可以接受的,而我们不想在Web服务器上允许这样做。 (编辑:在此处删除对错误评论的响应)您仍然可以在用户不活动时访问用户信息,您只需要从“后端节点”(与Web服务器隔离的另一个过程)中进行操作即可。

– Dominic P
20 Jun 22'4:30



#3 楼

我认为访问令牌及其使用方式会引起一些混淆,这可能会导致安全问题。

令牌可能会带来安全风险是正确的,但这取决于您所使用的信息要求服务。朋友列表不仅仅提供诸如姓和名的信息,而且还不如个人信息那么重要。无论哪种情况,您都不希望公开实际的访问令牌,因为这就像向您的应用程序公开密码一样。

如果愿意,我选择创建一个辅助“令牌”,该令牌包含一个会话值(例如cookie中的加密会话值),用于标识用户直到其过期。因此,我在数据库中有一个访问令牌(可能是加密的,为了安全起见,它可以访问用户信息)。

您还可以通过令牌检索此人的ID。如果至少将其存储在数据库中,则可以通过人员的ID匹配检索到的令牌。这样,当您为访问令牌交换代码时,可以比较ID并找到正确的记录。

#4 楼

在广泛采用JSON Web令牌(JWT)之前,许多答案已经过时了。

您应该将access_token当作拥有电子邮件/密码对一样好,因此它需要安全地存储和传输。 access_token不应包含太多信息,仅JWT的sub范围内的用户ID就足够了。由于JWT可以防止有效载荷的恶意修改,因此您可以安全地使用存储在其中的授权和ID。

对于大多数应用程序来说,在服务器上存储一个access_token可能会有些繁重,因为您可以在access_tokens上使用一个短期限,而存储一个refresh_token(而不是频繁的数据库调用)。如果需要用户信息,请将其存储在ID令牌中,仅用于显示有关已认证用户的信息。

每当您要刷新ID信息时都重新请求ID令牌,并且永远不要将id_token提交给API。

如今,聪明的开发人员在OAuth 2.0的基础上实现了OpenID Connect来标准化其用户信息和访问授权,并且随着大多数Identify Provider(IdP)实施此规范(例如Google,Facebook,Auth0),我将从这里开始,YourServiceHere)。

#5 楼

如果您可能在使用的应用程序中达到令牌的最大租用期限,则建议存储令牌。但是,我建议使用Redis,而不是数据库。如果令牌丢失,则应将应用程序设置为继续运行,因此它不需要长期保存,并且Redis比使用数据库快得多,并且那里有一些非常简单的Redis实现也不需要花费很长时间起床并运行。