我正在Yii 1.x中构建一个API,它将与移动应用程序一起使用。部分过程涉及使用以下JSON请求登录(使用用户名和密码): -
//使用用户名&发送的请求密码
{
"request" : {
"model" : {
"username" : "bobbysmith",
"password" : "mystrongpassword"
}
}
}
//如果成功登录,则返回以下回复
{
"response": {
"code": 200,
"message": "OK",
"model": {
"timestamp": 1408109484,
"token": "633uq4t0qdtd1mdllnv2h1vs32"
}
}
}
此令牌非常重要 - 一旦用户登录应用程序,我希望他们可以访问要求他们登录的其他页面。我希望移动应用程序存储此令牌&如果在任何后续请求中找到相同的 633uq4t0qdtd1mdllnv2h1vs32 令牌,它将接受此作为经过身份验证的请求(对于此用户'bobbysmith')。
我有点不确定如何最好地做到这一点,我做了一些研究,oAuth已被提及几次,以及通过HTTPS的基本身份验证。
所以简而言之......
任何人都可以解释实现这一目标的最佳方法吗?如果我所说的内容不是100%明确的,请告诉我,我会提供更多信息。
当我使用PHP时,Yii 1.x解决方案是理想的,因为这是使用当前API构建的。
简而言之,应用程序确保每个服务器请求都包含有效负载或标头中的令牌,因此可以在每个后续帖子中检索此令牌,一旦注销,只需删除此令牌或设置为null / empty
答案 0 :(得分:55)
集中一个解决方案,一次性提供所有好的(RESTful)auth内容,这可能是:
提示:个人用户数据应该是永久加密的!
上面您可以看到有关安全接口的标准信息。为了确保持久的安全性,您可以像下一部分一样尝试。我不确定你的AppSidePersitence。也许它的sqlLite或类似的东西。这就是为什么我没有指出基于代码的DB-Schema,就像我对Yii做的那样。您需要在Yii应用程序(后端)内部以及应用程序(客户端)内部存储/持久存储以存储时间和令牌。
您的YiiDBModel
-- -----------------------------------------------------
-- Table `mydb`.`user`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`user` (
`id` INT NOT NULL,
`username` VARCHAR(255) NOT NULL,
`password` VARCHAR(255) NOT NULL,
`lastLogin` DATETIME NULL,
`modified` DATETIME NULL,
`created` DATETIME NULL,
PRIMARY KEY (`id`))
ENGINE = InnoDB;
----------------------------------------------------
-- Table `mydb`.`authToken`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`authToken` (
`id` INT NOT NULL,
`userId` INT NOT NULL,
`token` VARCHAR(255) NOT NULL,
`created` DATETIME NOT NULL,
PRIMARY KEY (`id`, `userId`),
INDEX `fk_authToken_user_idx` (`userId` ASC),
UNIQUE INDEX `token_UNIQUE` (`token` ASC),
CONSTRAINT `fk_authToken_user`
FOREIGN KEY (`userId`)
REFERENCES `mydb`.`user` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
您的AppPersitenceModel
正确处理您的令牌并确保登录安全
一旦用户登录被Yii验证为“成功”,您就会生成一个带有当前时间戳的新用户令牌,该用户令牌将存储在您的YiiApp-DB中。在您的YiiApp中,您需要配置一个“过期时间”,该时间将添加到当前时间戳中,例如,如果您想使用“时间戳”:当前时间戳为:1408109484
且您的过期时间设置为3600
(3600秒= 1小时)。所以...您将通过API发送的过期日期时间为(1408109484+3600)
。顺便说一句。提示:您不需要发送"code": 200
等属性。响应代码包含在您的请求/响应标头数据中。
** 200 OK响应 - 例如,在用户登录成功后,保持计算的“过期”日期:**
{
"error": null,
"content": {
"expires": 1408109484,
"token": "633uq4t0qdtd1mdllnv2h1vs32"
}
}
重要提示:您希望保护的每个请求都需要与您生成的用户“令牌”一起发送。哪个可能会存储在您的deviceStorage中。您可以处理“登录状态” - 如果您使用HTTP-Response-Codes权限,则确实是RESTful,例如,200 OK(如果一切正常)或401(未授权,用户未进入或会话已过期)。您需要在Yii方面验证您的用户请求。从传入请求中读出令牌,由于数据库中给定的令牌验证它,并将“created”-DB与当前传入的Request-Time(HTTP-Requests)进行比较。
**请求 - 示例,任何安全请求的默认架构:**
{
"token": "633uq4t0qdtd1mdllnv2h1vs32"
"content": {
"someDataYouNeed" : null
}
}
** 401 Unauthorized Response-Example,令牌已过期:**
{
"error": 1, // errorCode 1: token is expired
"content": {
"someDataYouNeed" : null
}
}
** 401 Unauthorized Response-Example,用户未登录(YiiDB中不存在令牌):**
{
"error": 2, // errorCode 2: user is not logged in
"content": {
"someDataYouNeed" : null
}
}
保持用户会话活着?这很简单。只需将authToken
- 表中的“已创建”日期更新为当前请求时间。每次都这样做,用户发送了有效请求。这样,如果用户仍处于活动状态,会话将不会过期。在更新expires
- DB中的日期字段之前,请确保您的DB-Token未过期。如果在会话到期时没有发送请求,则不再可能保持活动状态。
很抱歉,但添加PHP代码太多了。
答案 1 :(得分:0)
如果您正在构建本机移动应用程序,那么明智的做法是依赖本机内存(例如iOS钥匙串)的安全性而不是基于cookie的解决方案。否则你所描述的似乎很好。只要你的有效载荷是通过SSL发送的,如果令牌在PUT或POST中并不重要。您的令牌管理(即到期时间)是您必须做出的业务决策。后端我会按照您描述并保留数据库中的令牌并在出于任何原因失去它时将其删除,并将消息返回到客户端应用程序以将其重新置于注销模式/重新请求凭据。
编辑:从多产的Phil Sturgeon看看这个令人敬畏的啧啧。他还有一个很棒的CI库,用于在CI中构建RESTful API,这可能值得一看。http://philsturgeon.uk/blog/2013/07/building-a-decent-api
http://code.tutsplus.com/tutorials/working-with-restful-services-in-codeigniter--net-8814
答案 2 :(得分:0)
到目前为止,您可能已切换到Yii2,并且为了将来参考,最干净的解决方案是使用RESTful API的包含类,或者可以在任何框架中实现它们。
HttpBearerAuth.php充分说明了这些优势,但总而言之,将解决方案与请求标头一起使用会更好,因为GET参数可能会保存在日志和Basic中如果您不使用SSL,您可以轻松拦截验证密码(您应该!)