资讯专栏INFORMATION COLUMN

Yii2.0 RESTful API 认证教程【令牌验证】

X1nFLY / 1438人阅读

摘要:最近在做认证功能,记录整个过程,方便以后查看。请求参数当作请求参数发送,例如,由于大多数服务器都会保存请求参数到日志,这种方式应主要用于请求,因为它不能使用头来发送使用者从认证服务器上获取基于协议的,然后通过发送到服务器。

最近在做RESTful API认证功能,记录整个过程,方便以后查看。本文参照了 https://segmentfault.com/a/1190000016368603部分内容,感谢该作者的分享,以下内容根据我的项目实际情况进行了调整。

认证介绍

和Web应用不同,RESTful APIs 通常是无状态的, 也就意味着不应使用 sessionscookies, 因此每个请求应附带某种授权凭证,因为用户授权状态可能没通过 sessionscookies 维护, 常用的做法是每个请求都发送一个秘密的 access token 来认证用户, 由于 access token 可以唯一识别和认证用户,API 请求应通过 HTTPS 来防止man-in-the-middle (MitM) 中间人攻击.

认证方式

HTTP 基本认证 :access token 当作用户名发送,应用在access token可安全存在API使用端的场景, 例如,API使用端是运行在一台服务器上的程序。

请求参数: access token 当作API URL请求参数发送,例如 https://example.com/users?acc..., 由于大多数服务器都会保存请求参数到日志, 这种方式应主要用于JSONP 请求,因为它不能使用HTTP头来发送 access token

OAuth 2 : 使用者从认证服务器上获取基于 OAuth2 协议的 access token, 然后通过 HTTP Bearer Tokens 发送到 API 服务器。

上方进行简单介绍,内容来自 Yii Framework 2.0 权威指南

实现步骤

继续上一篇 的内容(这里暂时使用默认User数据表,正式环境请分离不同的数据表来进行认证)

需要添加的数据内容

继上篇的 User 数据表,我们还需要增加一 个 access_tokenexpire_at 的字段,

进入项目根目录打开控制台输入以下命令:

./yii migrate/create add_column_access_token_to_user
./yii migrate/create add_column_expire_at_to_user

打开 你的项目目录 /console/migrations/m181224_075747_add_column_access_token_user.php 修改如下内容:

    public function up()
    {
        $ret = $this->db->createCommand("SELECT * FROM information_schema.columns WHERE table_schema = DATABASE()  AND table_name = "user" AND column_name = "access_token"")->queryOne();//判断user表是否有"access_token"这个字段
        if (empty($ret)) {
            $this->addColumn("user", "access_token", $this->string(255)->defaultValue(NULL)->comment("令牌"));
        }
    }

    public function down()
    {
        $this->dropColumn("user", "access_token");
        return true;
    }

打开 你的项目目录 /console/migrations/m181224_092333_add_column_expire_at_user.php 修改如下内容:

    public function up()
    {
        $ret = $this->db->createCommand("SELECT * FROM information_schema.columns WHERE table_schema = DATABASE()  AND table_name = "user" AND column_name = "expire_at"")->queryOne();
        if (empty($ret)) {
            $this->addColumn("user", "expire_at", $this->integer(11)->defaultValue(NULL)->comment("令牌过期时间"));
        }
    }

    public function down()
    {
        $this->dropColumn("user", "expire_at");
        return true;
    }

执行迁移命令

./yii migrate
配置

打开 apiconfigmain.php

配置 user 应用组件:

"user" => [
            "identityClass" => "apimodelsUser",
            "enableAutoLogin" => true,
            "enableSession"=>false,
            //"identityCookie" => ["name" => "_identity-api", "httpOnly" => true],
        ],

将 session 组件注释掉,或删掉

//        "session" => [
//            // this is the name of the session cookie used for login on the backend
//            "name" => "advanced-api",
//        ],

编写 apimodelsUser.php 实现认证类,继承 IdentityInterface

commonmodelsUser 类拷贝到 apimodels 目录下,修改命名空间为 apimodels


commonmodelsLoginForm.php 类拷贝到 apimodels* 目录下,修改命名空间,并重写 login* 方法:

validate()) {
            //return Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600 * 24 * 30 : 0);
            if ($this->getUser()) {
                $access_token = $this->_user->generateAccessToken();
                $this->_user->expire_at = time() + static::EXPIRE_TIME;
                $this->_user->save();
                Yii::$app->user->login($this->_user, static::EXPIRE_TIME);
                return $access_token;
            }
        }
        return false;
}

上方代码给 User 模型添加了一个 generateAccessToken() 方法,因此我们到 apimodelsUser.php 中添加此方法

namespace apimodels;

use Yii;
use yiiaseNotSupportedException;
use yiiehaviorsTimestampBehavior;
use yiidbActiveRecord;
use yiiwebIdentityInterface;
use yiiwebUnauthorizedHttpException;
...
...
class User extends ActiveRecord implements IdentityInterface
{
    ...
    ...
    
   /**
     * 生成accessToken字符串
     * @return string
     * @throws yiiaseException
     */
    public function generateAccessToken()
    {
        $this->access_token=Yii::$app->security->generateRandomString();
        return $this->access_token;
    }
}

接下来在apicontrollers新加一个控制器 命名为 UserController 并继承 yii estActiveController,编写登录 Login 方法,具体代码如下:

namespace apicontrollers;
use apimodelsLoginForm;
use yii
estActiveController;
use yii;


class UserController extends ActiveController
{
    public $modelClass = "apimodelsUser";

    public function actions()
    {
        $action= parent::actions(); // TODO: Change the autogenerated stub
        unset($action["index"]);
        unset($action["create"]);
        unset($action["update"]);
        unset($action["delete"]);
    }

    public function actionIndex()
    {
        //你的代码
    }

    /**
     * 登陆
     * @return array
     * @throws yiiaseException
     * @throws yiiaseInvalidConfigException
     */
    public function actionLogin()
    {
        $model = new LoginForm();
        if ($model->load(Yii::$app->getRequest()->getBodyParams(), "") && $model->login()) {
            return [
                "access_token" => $model->login(),
            ];
        } else {
            return $model->getFirstErrors();
        }
    }
}

最后新增一条 URL 规则

打开 apiconfigmain.php 修改 components 属性,添加下列代码:

"urlManager" => [
    "enablePrettyUrl" => true,
    "enableStrictParsing" => true,
    "showScriptName" => false,
    "rules" => [
        ["class" => "yii
estUrlRule", 
            "controller" => "user",
            "extraPatterns"=>[
                "POST login"=>"login",
            ],
        ],
    ],
]

使用一个调试工具来进行测试 http://youdomain/users/login 记住是POST 请求发送,假如用POSTMAN有问题的话指定一下 Content-Type:application/x-www-form-urlencoded
ok,不出意外的话,相信你已经可以收到一个access_token 了,接下来就是如何使用这个token,如何维持认证状态,达到不携带这个token将无法访问,返回 401

维持认证状态

实现认证步骤:

在你的 REST 控制器类中配置 authenticator 行为来指定使用哪种认证方式

在你的 user identity class 类中实现 yiiwebIdentityInterface::findIdentityByAccessToken() 方法.

具体实现方式如下:

打开之前的 User 控制器( apicontrollersUserController.php ),增加以下内容:

use yiihelpersArrayHelper;
use yiifiltersauthQueryParamAuth;

...//此处省略一些代码了

    public function behaviors()
    {
        return ArrayHelper::merge(parent::behaviors(), [
            "authenticatior" => [
                "class" => QueryParamAuth::className(), //实现access token认证
                "except" => ["login"], //无需验证access token的方法,注意区分$noAclLogin
            ]
        ]);
    }
...    

实现 findIdentityByAccessToken() 方法:

打开 apimodelsUser.php 重写 findIdentityByAccessToken() 方法

...
use yiiwebUnauthorizedHttpException;
...

class User extends ActiveRecord implements IdentityInterface
{
    ...
    ...
    
    /**
     * {@inheritdoc}
     */
    public static function findIdentityByAccessToken($token, $type = null)
    {
//        throw new NotSupportedException(""findIdentityByAccessToken" is not implemented.");
        $user = static::find()->where(["access_token" => $token, "status" => self::STATUS_ACTIVE])->one();
        if (!$user) {
            return false;
        }
        if ($user->expire_at < time()) {
            throw new UnauthorizedHttpException("the access - token expired ", -1);
        } else {
            return $user;
        }
    }
    ...
}

打开 apicontrollersUserController.php ,增加 Test方法,用于测试令牌验证

    public function actionTest()
    {
        return ["status"=>"success"];
    }

修改 apiconfigmain.php

        "urlManager" => [
            "enablePrettyUrl" => true,
            "enableStrictParsing" => true,
            "showScriptName" => false,
            "rules" => [
                ["class" => "yii
estUrlRule",
                    "controller" => "user",
                    //"pluralize" => false,    //设置为false 就可以去掉复数形式了
                    "extraPatterns"=>[
                        "GET test"=>"test",
                        "POST login"=>"login",
                    ],
                ],
            ],
        ]

接下来访问一下你的域名 http://youdomain/users/test,不携带任何参数是不是返回 401了?
ok,这里介绍两种访问方式,一种是URL访问,另一种是通过header 来进行携带

http://youdomain/users/test?a...

传递 header 头信息

Authorization:Bearer YYdpiZna0hJGhjsfqwxUeHEgLDfHEjB-

注意 Bearer 和你的token中间是有 一个空格的,很多同学在这个上面碰了很多次
以上就是基于YII2.0 RESTful 认证的内容。

本文参照了 https://segmentfault.com/a/1190000016368603部分内容,感谢该作者的分享,以上内容根据我的项目实际情况进行了调整。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/29855.html

相关文章

  • Yii2.0 RESTful API 之速率限制

    摘要:之速率限制什么是速率限制权威指南翻译过来为限流,为防止滥用,你应该考虑对您的限流。如果在规定的时间内接收了一个用户大量的请求,将返回响应状态代码这意味着过多的请求。 Yii2.0 RESTful API 之速率限制 什么是速率限制? 权威指南翻译过来为限流,为防止滥用,你应该考虑对您的 API 限流。 例如,您可以限制每个用户 10 分钟内最多调用 API 100 次。 如果在规定的时...

    LeviDing 评论0 收藏0
  • Yii2.0 RESTful API 认证教程

    摘要:请求参数当作请求参数发送,例如,由于大多数服务器都会保存请求参数到日志,这种方式应主要用于请求,因为它不能使用头来发送使用者从认证服务器上获取基于协议的,然后通过发送到服务器。 认证介绍 和Web应用不同,RESTful APIs 通常是无状态的, 也就意味着不应使用 sessions 或 cookies, 因此每个请求应附带某种授权凭证,因为用户授权状态可能没通过 sessions ...

    JohnLui 评论0 收藏0
  • 使用 Laravel Passport 为你的 REST API 增加用户认证功能

    摘要:在本教程中,我们将了解如何在应用中使用认证。当用户通过登录时,会生成令牌并将其发送给用户,该用户可用于身份验证。提供,可以毫无困难地使用认证。服务提供者我们使用的最新版本,它可以使用包发现并自动注册服务。 showImg(https://segmentfault.com/img/remote/1460000019095408?w=1000&h=526); 在本教程中,我们将了解如何在 ...

    mudiyouyou 评论0 收藏0
  • Yii2.0 RESTful API 之版本控制

    摘要:之版本控制之前我写过两篇关于如何搭建,以及认证等处理,但是没有涉及到版本管理,今天就来谈谈版本管理如何实现。如果你还没有安装,你可以按照这里的说明进行安装。 Yii2.0 RESTful API 之版本控制 之前我写过两篇关于 Yii2.0 RESTful API 如何搭建,以及 认证 等处理,但是没有涉及到版本管理,今天就来谈谈版本管理如何实现。 索性就从头开始一步一步搭建吧,但是关...

    _ang 评论0 收藏0
  • PHP / Laravel API 开发推荐阅读清单

    showImg(https://segmentfault.com/img/bV6aHV?w=1280&h=800); 社区优秀文章 Laravel 5.5+passport 放弃 dingo 开发 API 实战,让 API 开发更省心 - 自造车轮。 API 文档神器 Swagger 介绍及在 PHP 项目中使用 - API 文档撰写方案 推荐 Laravel API 项目必须使用的 8 个...

    shmily 评论0 收藏0

发表评论

0条评论

X1nFLY

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<