RESTful 认证

技巧库 · forecho · 于 4年前 发布 · 5860 次阅读

认证

为什么需要认证?

和 Web 应用程序不同,RESTful API 无状态的,这意味着不能使用 sessions 或 cookies。因此,每个请求应该要携带某种认证证书来实现访问的安全性控制。一个通用的方法是在每个请求中发送一个秘密访问令牌(secret access token)来进行用户认证。由于一个访问令牌可以被用来唯一的识别和认证一个用户,所以 API 请求应该总是通过 HTTPS 发送以防止中间人(man-in-the-middle (MitM))攻击。

如何实现?

  • 首先你要有一个 user 表和 access_token 表
  • 在控制器中添加一个行为

Coding

快速验证

快速跑通程序,再慢慢优化功能是一种很好的编程习惯。如何在没有 user 表和 access_token 表的情况实现下验证功能呢?

首先确保 common/models/User.php 文件有如下代码:

public $authKey;
public $accessToken;

private static $users = [
    '100' => [
        'id' => '100',
        'username' => 'admin',
        'password' => 'admin',
        'authKey' => 'test100key',
        'accessToken' => '100-token',
    ],
    '101' => [
        'id' => '101',
        'username' => 'demo',
        'password' => 'demo',
        'authKey' => 'test101key',
        'accessToken' => '101-token',
    ],
];

确保 findIdentityfindIdentityByAccessToken 两个方法的代码如下:

public static function findIdentity($id)
{
    return isset(self::$users[$id]) ? new static(self::$users[$id]) : null;
}

public static function findIdentityByAccessToken($token, $type = null)
{
    foreach (self::$users as $user) {
        if ($user['accessToken'] === $token) {
            return new static($user);
        }
    }
    return null;
}

由于上节课我们转移了 User.php 文件的位置,命名空间也修改了,所以我们需要去修改 config/web.php 配置文件的 User 组建配置信息:

'user' => [
    'identityClass' => 'app\common\models\User',
    'enableAutoLogin' => true,
],

然后找到 modules/v1/controllers/TopicController.php 文件,添加认证行为:

use yii\helpers\ArrayHelper;
use yii\filters\auth\CompositeAuth;
use yii\filters\auth\HttpBasicAuth;
use yii\filters\auth\HttpBearerAuth;
use yii\filters\auth\QueryParamAuth;

public function behaviors()
{
    return ArrayHelper::merge(parent::behaviors(), [
        'authenticator' => [
            'class' => CompositeAuth::className(),
            'authMethods' => [
                // HttpBasicAuth::className(),
                // HttpBearerAuth::className(),
                QueryParamAuth::className(),
            ],
        ],
    ]);
}

上面是三种验证方式,其中任何一种方式都可以:

  • HttpBasicAuth::className() 是通过弹窗填用户名密码,默认只需要在用户名栏填入 Access-Token 返回接口数据。
  • HttpBearerAuth::className() 是通过请求 Headers 带上 Authorization: Bearer Access-Token 参数返回接口数据。
  • QueryParamAuth::className() 是通过 URL 带上 ?access-token=Access-Token 参数返回接口数据。

API 用得最多的应该是 QueryParamAuth::className() 认证方式,所以上面的代码我们也可以改成:

use yii\filters\auth\QueryParamAuth;

public function behaviors()
{
    $behaviors = parent::behaviors();
    $behaviors['authenticator'] = [
        'class' => QueryParamAuth::className(),
        'tokenParam' => 'access_token', // 可选参数 修改默认的 `access-token`
    ];

    return $behaviors;
}

验收结果

我们先按照以前的 URL 请求数据,查看返回结果,如果提示401错误,则说明我们添加认证成功。

接着我们使用认证的方式访问 URL,查看返回结果是否正常,如果正常说明我们认证成功。

最后

快速验证认证功能成功之后,接下来我们就要修改代码,让 access_token 从数据库中读取,我想这步就非常简单了,你只需要修改 common/models/User.php 文件的 findIdentityfindIdentityByAccessToken 两个方法。根据具体需求你可以:

  • 如果简单应用场景,每个用户只拥有一个访问令牌,你可以把访问令牌保存在 user 表的一个 access_token 字段中。
  • 如果 access_token 有有效期,而且需要更新的话,新需要新建一个 access_token 表,保存每个用户最新生成的 access_token。

如果这篇文章对您有帮助,不妨微信小额赞助我一下,让我有动力继续写出高质量的教程。

本帖已被设为精华帖!
共收到 3 条回复 Yii 2.0 最佳实践 RESTful
Alvin952#14年前 0 个赞

这个是怎么实现 。 我按照你的方式来,为什么没有任何反应呢。

forecho#24年前 0 个赞

@Alvin952 #1楼 有什么提示吗?你这样问,我没办法回答你,要学会提问。

Alvin952#34年前 0 个赞

没有任何提示。url 上面带不带access_token 都可以访问

这个行为好像没有起作用。 use yii\filters\auth\QueryParamAuth;

public function behaviors() {

$behaviors = parent::behaviors();
$behaviors['authenticator'] = [
    'class' => QueryParamAuth::className(),
    'tokenParam' => 'access_token', // 可选参数 修改默认的 `access-token`
];

return $behaviors;

}

添加回复 (需要登录)
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册