我知道这不是第一次在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(无需身份验证),它在数据库中创建一个用户并返回新用户。这符合一个请求一个资源规则。但是,这给我带来了一些疑问:
现在,我的流程如下所示:
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的。我将为此提供两种解决方案:
假设您要使用OAuth2(这不是一个坏主意!)。由于多种原因,OAuth2 API并不是真正的RESTful。我想最好还是使用定义良好的身份验证API,而不是为了获得RESTful而滚动自己的身份验证API。
这仍然给您带来了在API上创建用户的问题,并响应此(
POST
)调用,返回了可用作访问/刷新 token 的 secret 。我的替代方法如下:
您不需要用户即可启动 session 。
相反,您可以做的是在创建用户之前启动 session 。这样可以保证在以后的通话中,您都知道自己正在与同一个客户通话。
如果您开始OAuth2进程并收到访问/刷新 token ,则只需在
/users
上执行经过身份验证的POST请求即可。这意味着您的系统需要知道两种经过身份验证的用户:grant_type = client_credentials
)。 创建用户后,您可以为新创建的用户实体分配以前的匿名 session ,因此创建后无需进行任何访问/刷新 token 交换。
电子邮件验证
您对以下两个方面的建议:
由应用程序完成。哪一个更合适,实际上取决于您的应用程序以及最适合您的应用程序。用户开始使用他们不拥有的电子邮件帐户是否有与之相关的风险?如果否,那么允许用户立即进入就可以了。
这是您不希望执行此操作的示例:如果系统的其他成员使用该电子邮件地址将用户添加为 friend ,则该电子邮件地址是一种身份。如果您不强制用户验证其电子邮件,则意味着我可以代表具有不同电子邮件地址的某人行事。这类似于能够接收邀请等。这是攻击媒介吗?然后,您可能需要考虑在验证电子邮件之前阻止用户使用该应用程序。
您可能还考虑只阻止应用程序中电子邮件地址可能敏感的某些功能。在上一个示例中,您可以阻止用户在验证电子邮件之前看到其他用户的邀请。
这里没有正确的答案,这仅取决于您打算如何使用电子邮件地址。
登录
请只使用OAuth2。您描述的流程已经非常接近OAuth2的工作方式。进一步实际使用OAuth2。这非常棒,一旦您克服了理解协议(protocol)的最初障碍,就会发现它比您想象的要容易得多,并且只需实现您的API特别需要的位就相当简单。
大多数PHP OAuth2服务器实现都不是很好。他们做得太多,很难整合。自己动手并不难,而且您已经接近建立类似的东西了。
注销
您可能需要注销端点的两个原因是:
记住我
是的,用本地存储实现“记住我”听起来是个好主意。
关于api - REST API上的用户注册/身份验证流程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27876306/