REST API上的用户注册/认证流程

我知道这不是第一次在StackOverflow中处理该主题,但是,我有一些问题,我无法找到答案或其他问题反对答案。

我正在做一个相当简单的REST API(Silex-PHP),最初只需要一个SPA(骨干应用程序)就可以使用它。 我不想评论这个问题中的所有认证方法,因为这个主题已经完全覆盖了SO。 我基本上会为每个用户创建一个令牌,并且此令牌将附加到需要SPA进行身份验证的每个请求中。 所有SPA服务器事务将在HTTPS下运行。 目前,我的决定是令牌不会过期。 每个会话过期/令牌的令牌不符合REST的无状态,对吧? 我知道有很多安全改进的空间,但这是我现在的工作范围。

我有一个Tokens模型,因此在数据库中有一个表格,用于将FK标记为user_id。 我的意思是,令牌不是我用户模型的一部分。

寄存器

我有一个POST /用户(不需要身份验证),它在数据库中创建一个用户并返回新用户。 这符合一个请求一个资源规则。 但是,这给我带来了一些疑问:

  • 我的想法是,在创建新用户时,为用户创建一个新的令牌,立即使用Response返回它,从而改进用户体验。 用户将立即能够开始使用网络应用程序。 但是,返回此类响应的令牌会破坏仅返回资源的规则。 我是否应该一起提出两个请求? 一个用于创建用户,另一个用于检索令牌而用户不需要重新输入凭据?

  • 如果我决定将令牌与用户一起返回,那么我相信POST /用户会对API消费者感到困惑,然后会出现像POST / auth / register之类的内容。 再一次,我不喜欢这个想法,因为涉及动词。 我真的很喜欢这个答案中提供的简单。 但是再次,我需要一起做两个请求,POST /用户和POST /令牌。 如何一起完成两个请求,以及如果两个请求一起发送,我会如何精确地将令牌的相关信息发送给某个用户?

  • 现在我的流程如下所示:

    1. Register form makes a POST /users request
    2. Server creates a new user and a new token, returns both in the response (break REST rule)
    3. Client now attaches token to every Request that needs Authorization
    

    令牌永不过期,保留REST无状态。

    电子邮件验证

    大多数当前的web应用程序需要电子邮件验证,而不会破坏用户的用户体验,即用户可以在注册后立即使用该webapp。 另一方面,如果我按照上面的建议返回了带有注册请求的令牌,用户将立即访问每个资源而不验证电子邮件。

    通常我会采用以下工作流程:

    1. Register form sends POST /users request.
    2. Server creates a new user with validated_email set to false and stores an email_validation_token. Additionally, the server sends an email generating an URL that contains the email_validation_token. 
    3. The user clicks on the URL that makes a request: For example POST /users/email_validation/{email_validation_token}
    4. Server validates email, sets validated_email to true, generates a token and returns it in the response, redirecting the user to his home page at the same time.
    

    这看起来过于复杂,完全毁了UX。 你怎么去了?

    登录

    这很简单,现在我正在这样做,所以请纠正我的错误:

    1. User fills a log in form which makes a request to POST /login sending Basic Auth credentials.
    2. Server checks Basic Auth credentials and returns token for the given user.
    3. Web app attached the given token to every future request.
    

    登录是一个动词,因此违反了REST规则,但似乎每个人都同意这样做。

    登出

    为什么每个人似乎都需要一个/ auth / logout端点? 从我的角度来看,在web应用程序中单击“注销”应该基本上从应用程序中删除令牌,而不是在进一步的请求中发送令牌。 服务器在此不起作用。

    由于令牌可能保存在localStorage中以防止在可能的页面刷新时丢失令牌,所以注销也意味着将令牌从localStorage中删除。 但是,这仍然不会影响服务器。 我了解需要POST /注销的人基本上使用会话令牌,这又会打破REST的无状态。

    记住我

    我明白记住我基本上是指将返回的标记保存到localStorage或不在我的情况。 这是正确的吗?

    如果你想推荐关于这个话题的更多信息,我会非常感激。 谢谢!


    寄存器

    每个会话过期/令牌的令牌不符合REST的无状态,对吧?

    不,这没有错。 许多HTTP认证方案确实有过期令牌。 OAuth2对于REST服务非常流行,许多OAuth2实现强制客户端不时刷新访问令牌。

    我的想法是,在创建新用户时,为用户创建一个新的令牌,立即使用Response返回它,从而改进用户体验。 用户将立即能够开始使用网络应用程序。 但是,返回此类响应的令牌会破坏仅返回资源的规则。 我是否应该一起提出两个请求? 一个用于创建用户,另一个用于检索令牌而用户不需要重新输入凭据?

    通常,如果您按照REST最佳实践创建新资源,则不会像这样返回响应POST的内容。 这样做会使呼叫更像RPC,所以我在这里同意你的意见......这不是完美的RESTful。 我将提供两个解决方案:

  • 忽略这一点,打破最佳实践。 也许在这种情况下它是最好的,如果它们更有意义,那么做例外有时是最好的事情(经过仔细考虑)。
  • 如果你想更加RESTful,我会提供一个替代方案。
  • 让我们假设你想使用OAuth2(不是一个坏主意!)。 出于多种原因,OAuth2 API并不是真正的RESTful。 我的意思是,使用定义良好的身份验证API更好,但为了实现RESTful,您还需要滚动自己的身份验证API。

    这仍然会导致您在API上创建用户的问题,并响应此( POST )调用,返回可用作访问/刷新令牌的秘密。

    我的选择如下:

    您不需要有用户来开始会话

    你可以做的是在创建用户之前启动会话。 这保证了对于未来的任何呼叫,您都知道您正在与同一客户进行交谈。

    如果您启动OAuth2进程并接收您的访问/刷新令牌,则只需在/users上执行经过验证的POST请求即可。 这意味着您的系统需要了解两种经过身份验证的用户:

  • 使用用户名/密码登录的用户(`grant_type = passsword1)。
  • 以匿名方式登录并打算在事实之后创建用户的用户。 ( grant_type = client_credentials )。
  • 一旦用户被创建,您可以将您以前的匿名会话与新创建的用户实体分配,因此您不需要在创建后进行任何访问/刷新令牌交换。

    电子邮件验证

    你的建议都是:

  • 防止用户在完成电子邮件验证之前使用该应用程序。
  • 允许用户立即使用该应用程序
  • 由应用程序完成。 哪一个更合适取决于您的应用程序和最适合您的应用程序。 用户是否开始在他们不拥有的电子邮件中使用帐户有任何风险? 如果不是,那么允许用户马上就可以。

    下面是一个你不想这样做的例子:假设你的系统的其他成员使用电子邮件地址来将用户添加为朋友,那么电子邮件地址就是一种身份。 如果您不强制用户验证其电子邮件,这意味着我可以代表具有不同电子邮件地址的人员采取行动。 这类似于能够接收邀请等。这是一个攻击媒介吗? 然后,您可能需要考虑阻止用户使用该应用程序,直到电子邮件通过验证。

    您也可以考虑只阻止应用程序中的电子邮件地址可能敏感的某些功能。 在前面的示例中,您可以防止人们在验证电子邮件之前看到来自其他用户的邀请。

    这里没有正确的答案,这取决于你打算如何使用电子邮件地址。

    登录

    请只使用OAuth2。 您描述的流程已经非常接近OAuth2的工作方式。 实际使用OAuth2可以再进一步。 这非常好,一旦你了解了协议的最初障碍,你会发现它比你想象的更容易,并且相当简单地实现你特别需要的API。

    大多数PHP OAuth2服务器实现并不好。 他们做得太多,并且有点难以整合。 滚动你自己并不困难,你已经非常接近构建类似的东西。

    登出

    您可能需要注销端点的两个原因是:

  • 如果您使用基于cookie /会话的身份验证,并且想要通知服务器忘记会话。 听起来这对你来说不是问题。
  • 如果您想要告诉服务器提前过期访问/刷新令牌。 是的,你可以将它们从本地存储中删除,这可能会足够好。 强制服务器端过期可能会给你一点额外的信心。 如果某人能够使用MITM浏览器并且现在可以访问您的令牌,该怎么办? 我可能想要快速注销并过期所有现有的令牌。 这是一个边缘案例,我个人从来没有这样做过,但这可能是你需要它的原因。
  • 记住我

    是的,用本地存储实现“记住我”听起来像是个好主意。


    你是对的,SESSION在REST中是不允许的,因此不需要登录或注销REST服务和/登录,/注销不是名词。

    您可以使用身份验证

  • 基于SSL的基本认证
  • 摘要式认证
  • OAuth 2
  • HMAC等
  • 我更喜欢使用PUBLIC KEY和PRIVATE KEY [HMAC]

    私钥永远不会通过网络传输,我不关心公钥。 公钥将用于制定用户特定的操作[谁持有api密钥]

    私钥将由客户端应用程序和服务器知道。 私钥将用于创建签名。 您使用私钥生成签名令牌并将该密钥添加到头中。 服务器还将生成签名并验证握手请求。

    Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b
    

    现在你将如何获得私钥? 你必须手动完成,就像你在你的应用上放置了facebook,twitter或google api键一样。

    但是,在某些情况下,您也可以像Amazon S3那样仅返回[不推荐]密钥一次。 他们在注册响应中提供“AWS秘密访问密钥”。

    链接地址: http://www.djcxy.com/p/33789.html

    上一篇: User registration/authentication flow on a REST API

    下一篇: How can I use Django OAuth Toolkit with Python Social Auth?