从零开始搭建完整的电影全栈系统(四)——restfulApi用户的认证授权及用户注册

在配置文件main.php中设置用户认证类,并注释掉cookies和session配置,因为Api客户端和WEB网站不同,通常不能使用cookies和session维持登录状态。

'user' => [
            'identityClass' => 'common\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用户认证(登录功能)

复制一份common/models/UserLoginForm到common/models中并改名为ApiLoginForm,同时将remember me 和vitifyCode等相关功能取消,并重写login方法。代码如下:

<?php
namespace api\models;

use common\models\User;
use Yii;
use yii\base\Model;

/**
 * Login form
 */
class ApiLoginForm extends Model
{
    public $username;
    public $password;
    //public $rememberMe = true;
    public $vitifyCode;

    private $_user;

    public function attributeLabels() //属性labels
    {
        return [
            'username' => '用户名',
            'password' => '密码',
            //'rememberMe' => '记住我',
            //'vitifyCode' => '验证码',
        ];
    }
    /**
     * {@inheritdoc}
     */
    public function rules()
    {
        return [
            // username and password are both required
            [['username', 'password'], 'required'],
            // rememberMe must be a boolean value
            //['rememberMe', 'boolean'],
            // password is validated by validatePassword()
            ['password', 'validatePassword'],
            //['vitifyCode', 'captcha'], //验证码验证
        ];
    }

    /**
     * Validates the password.
     * This method serves as the inline validation for password.
     *
     * @param string $attribute the attribute currently being validated
     * @param array $params the additional name-value pairs given in the rule
     */
    public function validatePassword($attribute, $params)
    {
        if (!$this->hasErrors()) {
            $user = $this->getUser();
            if (!$user || !$user->validatePassword($this->password)) {
                $this->addError($attribute, 'Incorrect username or password.');
            }
        }
    }

    /**
     * Logs in a user using the provided username and password.
     *
     * @return bool whether the user is logged in successfully
     */
    public function login()
    {
        if ($this->validate()) {
//            return Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600 * 24 * 30 : 0);
            $access_token = $this->_user->generateAccessToken();
            $this->_user->expire_at=time()+3600*7*24;//设定access_token过期时间
            $this->_user->save();
            Yii::$app->user->login($this->_user,3600*7*24);
            return $access_token;
        } else {
            return false;
        }
    }

    /**
     * Finds user by [[username]]
     *
     * @return User|null
     */
    protected function getUser()
    {
        if ($this->_user === null) {
            $this->_user = User::findByUsername($this->username);
        }

        return $this->_user;
    }
}

在common/models User中实现generateAccessToken,代码如下:

/**
     * 生成access_token
     * @return string
     * @throws \yii\base\Exception
     */

    public function generateAccessToken()
    {
        $this->access_token = Yii::$app->security->generateRandomString();
        return $this->access_token;
    }

实现UserController控制器,实现login方法:

<?php

namespace api\controllers;

use api\models\ApiLoginForm;
use common\models\Article;
use yii\rest\ActiveController;

/**
 * VodDetailController implements the CRUD actions for VodDetail model.
 */
class UserController extends ActiveController
{

    public $modelClass = 'common\models\User';
    public function actionLogin()
    {
        $model = new ApiLoginForm();
        /* $model->username = $_POST['username'];
         $model->password = $_POST['password'];*/
        //使用getBodyParams处理POST请求
        $model->load(\Yii::$app->getRequest()->getBodyParams(),'');
        if ($model->login()) {
            return ['access_token' => $model->login()];
        } else {
            $model->validate();
            return $model;
        }
    }
}

配置好url美化:

 [
                    'class' => 'yii\rest\UrlRule',
                    'controller' => 'user',
                    'pluralize' => false,//访问资源不需要加s
                    'extraPatterns' => [
                        'POST login' => 'login',
                        'POST signup' => 'signup',
                    ],
                ]

测试登录api顺利获得accessToken:


测试登录api顺利获得accessToken:

认证状态的维持


维持认证状态,就是客户端如何⽤accesstoken这个令
牌,去访问服务端所提供的服务。
1,添加QueryParamAuth过滤器,在VideoDetailController:

public function behaviors()
{
 return ArrayHelper::merge(parent::behaviors(), [
 'authenticatior' => [
 'class' => QueryParamAuth::className()
 ]
 ]);
}
在这里插入图片描述

可以看出认证已经生效。

我们带上有效的access-token去测试:


在这里插入图片描述

提示我们,要想顺利通过验证必须在\common\models\User.php 实现个findIdentityByAccessToken方法。实现该方法:

public static function findIdentityByAccessToken($token, $type = null)
    {
        return static::find()
            ->where(['access_token'=>$token,'status'=>self::STATUS_ACTIVE])
            ->andWhere(['>','expire_at',time()])
            ->one();
    }

再次带上access-token去测试,可以看出顺利得到想要的数据了:


在这里插入图片描述

我们还可以指定需要认证才能访问的动作。比如列表页不需要认证,详情需要:

public function behaviors()
    {
        return ArrayHelper::merge(parent::behaviors(), [
            'authenticatior' => [
                'class' => QueryParamAuth::className(),
                'only' => ['view'],
            ],

        ]);
    }

Yii RestfulApi认证可以参考:Yii RestfulApi认证

过滤器可以参考:过滤器

用户注册实现

复制一份frontend/models/SignupForm到common/models中并改名为ApiSignupForm,并修改 代码如下:

<?php
namespace api\models;

use common\models\User;
use yii\base\Model;

/**
 * Signup form
 */
class ApiSignupForm extends Model
{
    public $username;
    public $email;
    public $password;
    public $password_repeat;


    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
            ['username', 'trim'],
            ['username', 'required'],
            ['username', 'unique', 'targetClass' => '\common\models\User', 'message' => '用户名已被占用.'],
            ['username', 'string', 'min' => 2, 'max' => 255],

            ['email', 'trim'],
            ['email', 'required'],
            ['email', 'email'],
            ['email', 'string', 'max' => 255],
            ['email', 'unique', 'targetClass' => '\common\models\User', 'message' => 'Email已被占用.'],

            ['password', 'required'],
            ['password_repeat', 'required'],
            ['password', 'string', 'min' => 6],
            ['password_repeat','compare','compareAttribute'=>'password','message'=>'两次输入的密码不一致!'],
            /*['realname','required'],
            ['realname','string','max'=>128],*/
        ];
    }

    public function attributeLabels()
    {
        return [
            'username' => '用户名',
            //'realname' => '姓名',
            'password' => '密码',
            'password_repeat'=>'重复密码',
            'email' => '电子邮箱',
        ];
    }

    /**
     * Signs user up.
     *
     * @return User|null the saved model or null if saving fails
     * @throws \yii\base\Exception
     */
    public function signup()
    {
        if (!$this->validate()) {
            return null;
        }
        
        $user = new User();
        $user->username = $this->username;
        $user->email = $this->email;
        //$user->realname=$this->realname;
        $user->setPassword($this->password);
        $user->generateAuthKey();
        
        return $user->save() ? $user : null;
    }
}

在UserController中实现 signup方法:

public function actionSignup()
    {
        $model = new ApiSignupForm();
        $model->load(\Yii::$app->getRequest()->getBodyParams(),'');
        if ($model->signup()) {
            return ['result' =>'注册成功'];
        } else {
            $model->validate();
            return $model;
        }
    }

配置Url美化:

 [
                    'class' => 'yii\rest\UrlRule',
                    'controller' => 'user',
                    'pluralize' => false,//访问资源不需要加s
                    'extraPatterns' => [
                        'POST login' => 'login',
                        'POST signup' => 'signup',
                    ],
                ]

测试:


Api注册用户
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,012评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,628评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,653评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,485评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,574评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,590评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,596评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,340评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,794评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,102评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,276评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,940评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,583评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,201评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,441评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,173评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,136评论 2 352