api - REST API上的用户注册/身份验证流程

标签 api rest authentication web-applications asp.net-web-api

我知道这不是第一次在StackOverflow中处理该主题,但是,我有一些我找不到答案的问题,或者其他问题有相反的答案。
我正在做一个相当简单的REST API(Silex-PHP),最初仅由一个SPA(主干应用程序)使用。我不想评论此问题中的所有几种身份验证方法,因为该主题已经在SO上完全介绍了。我将基本上为每个用户创建一个 token ,并且该 token 将附加到需要SPA进行身份验证的每个请求中。所有SPA服务器事务将在HTTPS下运行。目前,我的决定是 token 不会过期。每个 session 的过期 token / token 不符合REST的无状态性,对吗?我知道安全性还有很大的改进空间,但这是我目前的范围。
我有一个 token 模型,因此在数据库中有一个表,其中包含FK到user_id的 token 。我的意思是 token 不是我的用户模型的一部分。
寄存器
我有一个POST / users(无需身份验证),它在数据库中创建一个用户并返回新用户。这符合一个请求一个资源规则。但是,这给我带来了一些疑问:

  • 我的想法是,在创建一个新用户,为该用户创建一个新 token ,立即将其与Response一起返回时,从而改善了UX。用户将立即能够开始使用Web应用程序。但是,为此类响应返回 token 将破坏仅返回资源的规则。我应该一起提出两个请求吗?一个是创建用户,另一个是检索 token ,而无需用户重新输入凭据?
  • 如果我决定将 token 与用户一起返回,那么我认为POST / users对于API使用者会造成困惑,然后出现类似POST / auth / register的信息。再一次,我不喜欢这个想法,因为它涉及一个动词。我真的很喜欢this answer中提供的简单性。但是再一次,我需要一起执行两个请求,一个POST / users和一个POST / tokens。同时执行两个请求是多么的错误,而且,如果两个请求一起发送,我将如何准确发送要附加到特定用户的 token 的相关信息?

  • 现在,我的流程如下所示:
    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
    
    token 永不过期,从而保持REST无状态。
    电子邮件验证
    当前的大多数Web应用程序都需要电子邮件验证,而不会破坏用户的UX,即用户可以在注册后立即使用Web应用程序。另一方面,如果我按照上述建议将 token 与注册请求一起返回,则用户无需验证电子邮件即可立即访问每个资源。
    通常,我会执行以下工作流程:
    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.
    
    login是一个动词,因此违反了REST规则,尽管每个人似乎都同意这样做。
    登出
    为什么每个人似乎都需要/ auth / logout端点?从我的 Angular 来看,在Web应用程序中单击“注销”基本上应该从应用程序中删除 token ,而不是在其他请求中发送 token 。服务器对此不起作用。
    由于可能会将 token 保留在localStorage中,以防止在可能的页面刷新时丢失 token ,因此注销也将意味着从localStorage中删除 token 。但这仍然不会影响服务器。我了解需要POST / logout的人基本上都在使用 session token ,这再次打破了REST的无状态性。
    记得我
    我了解记住我基本上是指在我的情况下是否将返回的 token 保存到localStorage。这是正确的吗?
    如果您建议进一步阅读该主题,我将非常感激。谢谢!

    最佳答案

    注册

    Tokens that expire/tokens per session are not complying with the statelessness of REST, right?



    不,这没有错。许多HTTP身份验证方案确实具有过期 token 。 OREST2在REST服务中非常流行,许多OAuth2实现强制客户端不时刷新访问 token 。

    My idea is that at the time to create a new user, create a new token for the user, to immediately return it with the Response, and thus, improving the UX. The user will immediately be able to start using the web app. However, returning the token for such response would break the rule of returning just the resource. Should I instead make two requests together? One to create the user and one to retrieve the token without the user needing to reenter credentials?



    通常,如果您遵循REST最佳实践创建新资源,则不会返回任何信息来响应这样的POST。这样做会使调用更像RPC,因此在这里我同意您的观点……它不是完全RESTful的。我将为此提供两种解决方案:
  • 忽略这一点,打破最佳实践。在这种情况下,这可能是最好的选择,最好是做一些事(经过仔细考虑),以使它们更加有意义。
  • 如果您想要更加RESTful,我将提供另一种选择。

  • 假设您要使用OAuth2(这不是一个坏主意!)。由于多种原因,OAuth2 API并不是真正的RESTful。我想最好还是使用定义良好的身份验证API,而不是为了获得RESTful而滚动自己的身份验证API。

    这仍然给您带来了在API上创建用户的问题,并响应此(POST)调用,返回了可用作访问/刷新 token 的 secret 。

    我的替代方法如下:

    您不需要用户即可启动 session

    相反,您可以做的是在创建用户之前启动 session 。这样可以保证在以后的通话中,您都知道自己正在与同一个客户通话。

    如果您开始OAuth2进程并收到访问/刷新 token ,则只需在/users上执行经过身份验证的POST请求即可。这意味着您的系统需要知道两种经过身份验证的用户:
  • 使用用户名/密码(`grant_type = passsword1)登录的用户。
  • 以“匿名”身份登录并打算在事实之后创建用户的用户。 (grant_type = client_credentials)。

  • 创建用户后,您可以为新创建的用户实体分配以前的匿名 session ,因此创建后无需进行任何访问/刷新 token 交换。

    电子邮件验证

    您对以下两个方面的建议:
  • 在电子邮件验证完成之前,阻止用户使用该应用程序。
  • 允许用户立即使用应用程序

  • 由应用程序完成。哪一个更合适,实际上取决于您的应用程序以及最适合您的应用程序。用户开始使用他们不拥有的电子邮件帐户是否有与之相关的风险?如果否,那么允许用户立即进入就可以了。

    这是您不希望执行此操作的示例:如果系统的其他成员使用该电子邮件地址将用户添加为 friend ,则该电子邮件地址是一种身份。如果您不强制用户验证其电子邮件,则意味着我可以代表具有不同电子邮件地址的某人行事。这类似于能够接收邀请等。这是攻击媒介吗?然后,您可能需要考虑在验证电子邮件之前阻止用户使用该应用程序。

    您可能还考虑只阻止应用程序中电子邮件地址可能敏感的某些功能。在上一个示例中,您可以阻止用户在验证电子邮件之前看到其他用户的邀请。

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

    登录

    请只使用OAuth2。您描述的流程已经非常接近OAuth2的工作方式。进一步实际使用OAuth2。这非常棒,一旦您克服了理解协议(protocol)的最初障碍,就会发现它比您想象的要容易得多,并且只需实现您的API特别需要的位就相当简单。

    大多数PHP OAuth2服务器实现都不是很好。他们做得太多,很难整合。自己动手并不难,而且您已经接近建立类似的东西了。

    注销

    您可能需要注销端点的两个原因是:
  • 如果您使用基于cookie / session 的身份验证,并且想告诉服务器忘记 session 。听起来这对您来说不是问题。
  • 如果您想告诉服务器使访问/刷新 token 更早过期。是的,您可以将它们从本地存储中删除,这可能就足够了。强制它们在服务器端过期可能会给您一点额外的信心。如果有人能够MITM您的浏览器并且现在可以访问您的 token 怎么办?我可能想快速注销并使所有现有 token 到期。这是一个极端的案例,我个人从未做过,但这可能就是您想要它的原因。

  • 记住我

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

    关于api - REST API上的用户注册/身份验证流程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27876306/

    相关文章:

    javascript - 来自 MongoDB 的错误消息 "Operation ` disneys.insertOne( )` buffering timed out after 10000ms""

    Xcode 天气应用

    rest - 通过提交 SHA1 获取构建状态

    c# - JSON 到 C# 对象(将复杂的 API 响应映射到 C# 对象)

    java - 使用 Java 列出 wsdl url 中的所有操作(请求)

    api - 关于 RESTful API 的几个问题以及为什么很少实现一些最佳实践

    php - 对特定 Controller 功能的授权 Laravel 5.1

    php - 登录后显示客户信息

    Facebook 登录按钮自定义文本还原

    python - 如何在 Python 中使用 Flask 执行周期性任务