架构设计 - 支持Facebook登录的REST API由移动应用程序

时间:2015-05-14 06:11:46

标签: api rest facebook-graph-api oauth oauth-2.0

我正在尝试设计REST API以支持各种移动客户端(iOS和Android应用)。这些应用程序将允许用户使用Facebook登录以及我们自己的电子邮件身份验您可以参考下图来了解我的设计

Design flow

有两种授权级别:

第一个是使用OAuth2的“客户端(或应用程序)授权”。因此,当用户在移动设备上安装我们的应用程序并启动应用程序时,首先,应用程序进行“客户端(应用程序)授权”,如上图所示(第1张图像)。服务器将长期存在的access_token发送回客户端以用于所有后续调用。我的问题是:

Q1)您可以看到客户端正在发送client_keyclient_secret,我将它们存储在client_info表中。这个秘密应该是纯文本还是应该是可解密的格式?如果我加密它,我仍然需要在我的系统中的某处保留加密密钥。那它将如何使其安全?同样在每次通话中,解密都是一种开销。

Q2)是否可以在redis中以纯文本格式缓存客户端access_token并首先使用该缓存?

Q3)为了更加安全,我要求客户发送appsecret_proof以确保他们发送的access_token仅属于此客户端。它使用与Facebook https://developers.facebook.com/docs/graph-api/securing-requests#appsecret_proof相同的概念。它是hash_hmac('sha256', access_token, client_secret)

问题4)我们将只拥有自己的2个移动应用程序(分别用于iOS和Android),并且不提供第三方使用我们的API来开发其他应用程序。这意味着,对于每种类型的应用,我们的client_info表只有两行一个。那么可以,在应用代码中,我们保持client_keyclient_secret硬编码吗?如果是,那么将来当我们必须使新秘密失效并使用新秘密时,我们将如何取代这些信息?

Q5)由于这是几年来我们自己的应用,因此会针对相同的client_keyclient_secret创建多个access_token。为了保存所有这些内容,最好将client_key作为键存储,将array of all access_tokens作为值存储在redis中。将来,当我们向第三方开放API时,这个redis存储设计仍然可以扩展吗?

=================

稍后,用户决定对我的应用执行某些操作,因为我们需要用户登录他的帐户。对于该用户,请单击“facebook login”。我的应用从facebook获取facebook access_token和fb用户的ID,并将这些信息传递给API服务器(如第二张图所示)。 API服务器获取该令牌并调用facebook API以验证其access_token。验证令牌后,服务器会使用与该用户相关的一些元数据以及FB访问令牌来生成我们自己的user_access_token,例如utoken。并将utoken传递回客户端,以便在每个后续用户特定的API调用中传回。我的问题是:

Q1)将utoken保存在数据库user_token表中是否可以。这个utoken应该是纯文本还是应该是可解密的格式?如果我加密它,我仍然需要在我的系统中的某处保留加密密钥。那它将如何使其安全?同样在每次通话中,解密都是一种开销。

Q2)在每个用户特定的API调用中,我应该每次调用facebook来检查facebook access_token是否仍然有效?我相信我不应该,因为这对我没有任何意义。请注意,Facebook仅用于“facebook登录”。

Q3)我应该加密哪些信息来生成utoken?我想要有一个用户emailuser idrolefacebook token的哈希或关联数组,然后序列化该数据结构并最终加密它。你觉得那样会好吗?我理解它符合我的要求,但作为标准或普通应用程序,它们是否足够好?或者有最好的做法吗?

Q4)客户端应该在其cookie /缓存中存储utoken吗?这不可怕吗?

Q5)请注意用户可能有多个设备,使用相同的用户凭据登录。这意味着,在user_token表中,我们必须为登录的会话存储多个utokens,而所有这些都属于同一个用户。听起来不错吗?

我的设计方案有些熟悉REST API for website which uses Facebook for authentication

1 个答案:

答案 0 :(得分:1)

Q1.1:不!客户端凭据不应以这种方式使用。如果您的客户端是单页面应用程序或移动应用程序,您将被迫将客户端凭据存储在用户机器不安全的环境中。您应该使用OAuth的隐式流程

Q1.2:假设令牌是短暂的,没有问题缓存它。除了确保您可以依赖其他应用程序对用户进行身份验证之外,OAuth的关键在于您使用短期令牌有效地替换长期存在的用户或应用程序凭据。因此,如果有人获得对令牌的访问权限,至少他们对系统的访问权限将受到限制。

Q1.3:查看facebook文档:

  

图表API调用可以代表客户端从客户端或从您的服务器进行。通过添加名为appsecret_proof的参数,可以更好地保护来自服务器的呼叫

它声明appsecret_proof将代表用户用于来自服务器的调用。这里的要点与Q1.1有关。如果您将client_secret存储在用户的设备中,则可以生成appsecret_proof

Q1.4:再次,不!您应该对OAuth规范有一个很好的解读,并了解不同的流类型以及何时使用它们。另外请注意,如果您为自己的应用提供API,那么任何人都可以滥用API。唯一的区别是它没有记录。 Web App也会发生同样的情况。一旦它进入互联网,我就可以编写一个刮刀并滥用Web App。这是完全正常的,请记住,互联网上的任何内容都不是私密的,它只是没有记录。

问题5:再次,代币应该是短暂的。如果他们的生命周期与在用户更改之前一直存在的凭证相同,则令牌将失去其目的。

Q2.1:您应该保存该令牌ReST架构使用客户端缓存约束。

Q2.2:我不这么认为。 Facebook只是告诉您获得该令牌的用户具有一些您可以与系统中的用户关联的身份(例如,电子邮件)。一旦你知道了这种关联,你就应该关注Facebook令牌,而不是打电话给Facebook API。但是你说,你只是为了登录而使用它。

Q2.3:看起来不错但是再次检查Oauth规范,因为您似乎正在构建一个隐式流并使用JWT令牌。根据您想要存储在令牌中的内容,似乎没问题。

Q2.4:JWT令牌必须由客户端缓存。没有什么可怕的,因为它们对客户端是不透明的,因为它们是加密的。客户端发送带有每个请求的JWT令牌,API服务器使用私钥(从未暴露在服务器外部)对令牌进行解密,并可以检查用户的身份。

Q2.5:记住短命代币。代币必须到期!。