第三方登陆的使用在当今很是广泛,无论是PC端仍是手机端都很常见。由于它有着一号多用的特色,无论是在什么网站什么软件上只要有了这个第三方登陆的功能就无需再次走注册步骤,直接用第三方的帐号登陆就能够了,方便吧?开发程序看重的是用户体验,为用户打造一款“麻雀虽小,五脏俱全”,使用便利的产品是咱们的职责。那么话又说回来,在Restfual api 上如何实现第三方登陆呢?我在Segmentfault上找不到我想要的答案,不过最终我也实现了,我把个人实现思路写出来,固然这只是个人一种实现方式,要是你们有更好的方法呢,乐意交流。php
一、用Restfual api的架构实现第三方登陆,如QQ,微信登陆等。api
一、建两个表,user表和user_login表。user表我就不详说了,这是基本表,我重点说一下user_login表。
user_login表字段:微信
id id user_id 用户id type 登陆类型(如:QQ,weixin) qq_access_token QQ受权access_token qq_openid QQ openid wx_access_token 微信受权access_token wx_openid 微信openid
要是还有微博或者淘宝之类的其余第三方登陆就如以上的规律加上对应的字段就好了。架构
二、gii生成UserLogin.php model以下:app
<?php class UserLogin extends \yii\db\ActiveRecord { /** * @inheritdoc */ public static function tableName() { return 'user_login'; } /** * @inheritdoc */ public function rules() { return [ [['user_id'], 'integer'], [['type'], 'string', 'max' => 30], [['qq_access_token', 'wx_access_token'], 'string', 'max' => 220], [['qq_openid', 'wx_openid'], 'string', 'max' => 100] ]; } /** * @inheritdoc */ public function attributeLabels() { return [ 'id' => Yii::t('yii', 'ID'), 'user_id' => Yii::t('yii', 'User ID'), 'type' => Yii::t('yii', 'Type'), 'qq_access_token' => Yii::t('yii', 'Qq Access Token'), 'qq_openid' => Yii::t('yii', 'Qq Openid'), 'wx_access_token' => Yii::t('yii', 'Wx Access Token'), 'wx_openid' => Yii::t('yii', 'Wx Openid'), ]; } }
三、控制器里的方法以下:
QQ登陆yii
public function actionQqLogin() { $_model = new UserLogin(); $model = new TUser(); $post = Yii::$app->request->post(); if(!empty($post)) { $t_nickname = !empty($post['t_nickname']) ? trim($post['t_nickname']) : ''; $access_token = !empty($post['access_token']) ? trim($post['access_token']) : ''; $openid = !empty($post['openid']) ? trim($post['openid']) : ''; $t_photo = !empty($post['t_photo']) ? trim($post['t_photo']) : '';//头像 $res = UserLogin::find() ->where(['type'=>'qq','qq_openid'=>$openid]) ->one(); //判断是否已存在用户信息,存在则返回该条用户信息 if(!empty($res)) { $res->qq_access_token = $access_token; $res->save(); //获取一条用户信息 $user = $model->getUserrow($res->user_id); if(!empty($user)){ return $user; }else{ ErrorMsg::Info(Yii::t('yii','Login fail')); } }else{ //保存新用户 $user = $this->saveUser($t_nickname,$t_nickname,$openid,'','',$t_photo); if(empty($return['error_code'])){ $_model->user_id = $user->t_id; $_model->type = 'qq'; $_model->qq_access_token = $access_token; $_model->qq_openid = $openid; $_model->save(); $user = $model->getUserrow($user->t_id); //保证返回数据字段一致 } return $user; } }else{ ErrorMsg::Info(Yii::t('yii','Login fail')); } }
微信登陆post
public function actionWxLogin() { $_model = new UserLogin(); $model = new TUser(); $post = Yii::$app->request->post(); if(!empty($post)) { $t_nickname = !empty($post['t_nickname']) ? trim($post['t_nickname']) : ''; $access_token = !empty($post['access_token']) ? trim($post['access_token']) : ''; $openid = !empty($post['openid']) ? trim($post['openid']) : ''; $t_photo = !empty($post['t_photo']) ? trim($post['t_photo']) : '';//头像 $res = UserLogin::find() ->where(['type'=>'weixin','wx_openid'=>$openid]) ->one(); //判断是否已存在用户信息,存在则返回该条用户信息 if(!empty($res)) { $res->wx_access_token = $access_token; $res->save(); //获取一条用户信息 $user = $model->getUserrow($res->user_id); if(!empty($user)){ return $user; }else{ ErrorMsg::Info(Yii::t('yii','Login fail')); } }else{ //保存新用户 $user = $this->saveUser($t_nickname,$t_nickname,$openid,'','',$t_photo); if(empty($return['error_code'])){ $_model->user_id = $user->t_id; $_model->type = 'weixin'; $_model->wx_access_token = $access_token; $_model->wx_openid = $openid; $_model->save(); $user = $model->getUserrow($user->t_id);//保证返回数据字段一致 } return $user; } }else{ ErrorMsg::Info(Yii::t('yii','Login fail')); } }
保存用户信息方法:网站
public function saveUser($t_username,$t_nickname,$openid,$email,$phone,$t_photo) { $access_token = sha1(time().$openid); $data = array( "t_nickname"=> $t_nickname, "t_password"=> base64_encode($openid), "t_state" => 0, "t_photo" => $t_photo?$t_photo:"/images/upload/100x100/no_photo.jpg", "t_timezone"=> "PRC", "t_language"=> "zh_cn", "access_token"=> $access_token, "rent_user_type"=>"3", 't_add_time'=>time(), ); $model = new $this->modelUser; $model->attributes = $data; if(!empty($t_nickname) && !empty($openid)){ if(!$model->save()){ ErrorMsg::Info(Yii::t('yii','Reg fail')); } return $model; }else{ ErrorMsg::Info(Yii::t('yii','m-log-2')); } }
第三方登陆获取用户基本信息方法,TUser model里:ui
public function getUserrow($uid) { $user = $this->find() ->select(['access_token','t_password']) ->where(['t_id'=>$uid]) ->one(); if(!empty($user)){ $result['access_token']= !empty($access_token=$user->access_token)?$access_token:""; $result['appsercert'] = !empty($t_password=$user->t_password)?$t_password:""; return $result; //返回给手机端用,只返回access_token和appsercert。 } }
好了,到这里Restfual api 架构的第三方登陆已经实现了,微博,淘宝等第三方登陆实现的思路也如此,就是要对传入的参数进行改进一下就OK了。这是我实现Restfual api架构的第三方登陆的思路,不足的提议,好的点赞哈,咱们一块儿交流。this
一、直接在user表里加上QQ、weixin的type,openid和access_token字段,这种作法拓展性很差,之后要是再增长如:微博,淘宝等第三方登陆的话,又要操做user表,对user表操做过于频繁容易出问题,并且也不是每个用户都会使用第三方登陆,会形成大量空缺字段,浪费。我之因此独立建立user_login表也正是基于这些考虑的。二、返回给手机端全部的用户信息。其实手机端不须要那些,你只要返回给手机端access_token和appsercert这两个字段就能够了,手机端会本身获取用户信息。