Bootstrap

Yii2.0 RESTful API 认证教程

终于到了 认证介绍了.

废话不多说,直接正文开始

认证介绍

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

认证方式

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

  • 请求参数: 当作API URL请求参数发送,例如 , 由于大多数服务器都会保存请求参数到日志, 这种方式应主要用于 请求,因为它不能使用HTTP头来发送

  • : 使用者从认证服务器上获取基于 协议的 , 然后通过 发送到 服务器。

上方进行简单介绍,内容来自

实现步骤

我们都知道 默认的认证类都是 ,前后台都是共用一个认证类,因此我们要把 认证类 单独分离出来,达到前、后、API都分离,

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

准备条件

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

1.直接在你的数据库中新增 字段。

2.使用数据迁移的方式

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

php yii migrate/create add_access_token_to_user

打开 修改如下内容:

public function safeUp()
{
	$this->addColumn('user', 'access_token', $this->string());
}
public function safeDown()
{
	$this->dropColumn('user', 'access_token');
}

执行迁移命令

php yii migrate

配置

打开

配置 `user` 应用组件:

  • 设置 属性为哪个认证类

  • 设置 属性为

  • 设置 属性为

将 `session` 组件注释掉,或删掉

'user' => [
	'identityClass' => 'api\models\User',
	'enableAutoLogin' => true,
	'enableSession'=>false,
	//'identityCookie' => ['name' => '_identity-backend', 'httpOnly' => true],
],
//'session' => [ // this is the name of the session cookie used for login on the backend
//  'name' => 'advanced-backend',
//],

编写 `api\models\User.php` 实现认证类,继承 `IdentityInterface`

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

将 `common\models\LoginForm.php` 类拷贝到`api\models\`目录下,修改命名空间,并重写login方法:

validate()) {
        $access_token=$this->_user->generateAccessToken();
        $this->_user->save();
        return $access_token;
    } else {
        return false;
    }
}

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

namespace api\models;

use Yii;
use yii\base\NotSupportedException;
use yii\behaviors\TimestampBehavior;
use yii\db\ActiveRecord;
use yii\web\IdentityInterface;
...
...
class User extends ActiveRecord implements IdentityInterface
{
    ...
    ...
    
    /**
     * 生成accessToken字符串
     * @return string
     * @throws \yii\base\Exception
     */
    public function generateAccessToken()
    {
        $this->access_token=Yii::$app->security->generateRandomString();
        return $this->access_token;
    }
}

接下来打开 之前的`User` 控制器编写登录方法

use api\models\LoginForm;
...
... //省略一些代码


/**
 * 登陆
 * @return array
 * @throws \yii\base\Exception
 * @throws \yii\base\InvalidConfigException
 */
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规则

打开 修改 属性,添加下列代码:

'urlManager' => [
    'enablePrettyUrl' => true,
    'enableStrictParsing' => true,
    'showScriptName' => false,
    'rules' => [
        ['class' => 'yii\rest\UrlRule', 
            '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控制器

因我这里暂未设计其他数据表 所以我们暂且还使用 数据表吧

在新加一个控制器 命名为 并继承 ,配置认证方式代码:代码如下:

 CompositeAuth::className(),
            'authMethods' => [
                HttpBasicAuth::className(),
                HttpBearerAuth::className(),
                QueryParamAuth::className(),
            ],
        ];
        return $behaviors;
    }
}

#### 注意:这个控制器并非真正的Article,实则还是User

实现 方法:

打开 重写 方法

...
...
class User extends ActiveRecord implements IdentityInterface
{
    ...
    ...
    
    public static function findIdentityByAccessToken($token, $type = null)
    {
        return static::findOne(['access_token' => $token]);
    }
    ...
}

为刚才新加的控制器添加路由规则(ps:好像多了一步......)

修改

'urlManager' => [
    'enablePrettyUrl' => true,
    'enableStrictParsing' => true,
    'showScriptName' => false,
    'rules' => [
        ['class' => 'yii\rest\UrlRule',
            'controller' => 'user',
            'extraPatterns'=>[
                'GET send-email'=>'send-email'
                'POST login'=>'login',
            ],
        ],
        ['class' => 'yii\rest\UrlRule',
            'controller' => 'article',
            'extraPatterns'=>[

            ],
        ],
    ],
]

接下来访问一下你的域名 ,不携带任何参数是不是返回 401了?

上面的格式本章并不存在,你只要返回 401 即可

ok,这里介绍两种访问方式,一种是URL访问,另一种是通过 来进行携带

Authorization:Bearer y3XWtwWaxqCEBDoE-qzZk0bCp3UKO920

注意 Bearer 和你的token中间是有 一个空格的,很多同学在这个上面碰了很多次

好啦,基于YII2.0 RESTful 认证就此结束了,

更过完整的功能 请移步官方文档

另外还有,就自行发觉吧

另外,如果看不懂,或者写的不好,请移步 魏曦 老师的视频教程,本人所有内容都是跟随 魏曦老师 学的

写完认证发现我们的接口返回的数据不是很直观,现实生活中通常也不是这样子的,我们可能会返回一些特定的格式

自定义响应内容

打开 在 数组里面添加如下内容分


'response' => [
    'class' => 'yii\web\Response',
    'on beforeSend' => function ($event) {
        $response = $event->sender;
        $response->data = [
            'success' => $response->isSuccessful,
            'code' => $response->getStatusCode(),
            'message' => $response->statusText,
            'data' => $response->data,
        ];
        $response->statusCode = 200;
    },
],

这里的状态码统一设为 200 ,具体的可另行配置,假如登陆操作 密码错误或者其他,我们可以在控制器中这样使用:

$response = Yii::$app->response;
$response->setStatusCode(422);
return [
	'errmsg' => '用户名或密码错误!'
];

水平有限,难免有纰漏,请不吝赐教,在下会感激不尽