【学无止境】 基于ThinkPHP的OAuth2.0实现 ----OAuth2.0 个人学习笔记 Two

来源:互联网 发布:mmd动作数据导入maya 编辑:程序博客网 时间:2024/05/21 23:32

ThinkPHP 结合 OAuth2.0

准备工作

  1. 第一我们得准备好OAuth2.0的源码包,下载地址点这里。

  2. 我们将下载好的源码包放在thinkphp的vendor文件夹下面。这里注意只要src文件夹下的OAuth2放入vendor即可。如下图:
    这里写图片描述

  3. 新建模块oauth2.0 然后将其路由等信息配置完毕。

开始工作


  • 首先还是在配置文件中把OAuth的PDO数据库配置完成
 //OAuth数据库配置    'OAUTH_DB_HOST'=>'xxxxx.com',    'OAUTH_DB_NAME'=>'xxx',    'OAUTH_DB_USER'=>'xxx',    'OAUTH_DB_PWD'=>'xxxxxxxx',
  • 新建 IndexController 作为本次学习的主控制器,注意本控制器请继承 RestController(thinkphp封装)
class IndexController extends RestController 
  • 新建 authorize 公共方法来处理用户的授权请求和换取code的工作
public function authorize(){        //默认response_type为code        $_GET['response_type'] =  isset($_GET['response_type'])?$_GET['response_type']:'code';        //数据表字段为client_id指的是appid        isset($_GET['appid'])  && $_GET['client_id'] = $_GET['appid'];        $oauth = new OAuthModel();        $request = \OAuth2\Request::createFromGlobals();        $response = new \OAuth2\Response();        if (!$oauth->server()->validateAuthorizeRequest($request, $response)) {            $response->send();            exit();        }        //用户同意授权后        $is_authorized = ($_POST['authorized'] == 'yes');        //生成code(绑定你的业务user_id)        $oauth->server()->handleAuthorizeRequest($request, $response, $is_authorized,$user_id);        if ($is_authorized) {            $code = substr($response->getHttpHeader('Location'), strpos($response->getHttpHeader('Location'), 'code=')+5, 40);            //返回第三方服务            //所带参数state,code,            $parses = $_REQUEST;            $back_parses = array(                'state'=>$parses['state'],                'code'=>$code,            );            //跳转回第三方服务器            if(!$parses['redirect_url']) $this->err("redirect_url丢失!");            redirect( base64_decode($parses['redirect_url']) . '?' . http_build_query($back_parses));        }else{            $parses = $_GET;            $back_parses = array(                'state'=>$parses['state'],            );            //跳转回第三方服务器            redirect( urldecode($parses['redirect_url']) . '?' . http_build_query($back_parses) );        }    }
  • 获取到了code之后我们需要拿着这个code去换token,新建公共方法token 完成以下工作
public function token(){  //默认grant_type为authorization_code(授权码模式)        $_POST['grant_type'] = isset($_POST['grant_type'])?$_POST['grant_type']:'authorization_code';        $oauth = new OAuthModel();        $oauth->server()->handleTokenRequest(\OAuth2\Request::createFromGlobals())->send();}        
  • 拿到了这个token后我们就要校验这个token是否是正确的token,这个时候回到我们自己的项目目录下新建 CheckTokenController 控制器。
class CheckTokenController extends BaseController{    protected function _initialize(){        parent::_initialize();        $oauth = new OAuthModel();        if(!$_REQUEST['access_token']){            $this->err("未找到access_token,请确认已传入access_token");        }        //验证access_token        if (!$oauth->server()->verifyResourceRequest(\OAuth2\Request::createFromGlobals())) {            $oauth->server()->getResponse()->send();            exit();        }        //删除不必要的GET参数        unset($_GET['m']);        unset($_GET['c']);        unset($_GET['a']);        unset($_GET['access_token']);    }}    

所有的项目资源控制器必须继承该控制器!!!

  • 最后一步,回到自己的资源控制器里面编写自己的逻辑代码
class UserController extends CheckAccessTokenController{        public function user_info(){            switch ($this->_method){                case 'get':                    $model = new UserModel();                    $this->suc("用户信息获取成功",$model->user_info($this->user_id));                    break;                case 'post':                    //数据更新:使用动态验证,验证数据合法性同时验证数据是更新还是插入                    //TODO:当数据为更新时一定注意须包含主键id,否则将自动判断为插入数据                    //动态验证,逻辑代码            }        }}

测试方法举例

当我们完成整个编写流程后我们需要如何去测试呢? 在这里我也提供一个测试的方法与大家共享

  • 将用户导向授权层获取code
public function user(){        $url = "http://xxxxxx/resource/user/access_token/".  $this->get_oauth_token() ;        $this->test($url);    }
  • 检查是否有token
public function get_oauth_token(){        if($code = $_GET['code']){            //TODO::验证返回的state 防止CSRF攻击            $code = $_GET['code'];            $res = $this->code2oauthtoken($code);            if($res->access_token){                return $res->access_token;            }else{                echo "无效的code";exit();            }        }else{            $this->redirect_oauth();        }    }
    protected function redirect_oauth($url){        $url = $url?:get_url();            //TODO::使用state参数防止CSRF攻击 当用户跳转到授权服务器前,使用session储存state,当用户跳转回来时,比对state,以此判断用户身份是否改变                redirect('http://xxxxxxx/oauth2.0/authorize/appid/testclient/state/xyz/redirect_url/'.base64_encode($url));    }
  • 成功拿回codecode 换取 token
 public function code2oauthtoken($code){            $url = 'xxxxxx/oauth2.0/token';            //$url =ROOT_URL . U('Home/Index/token');            $method = 'post';            $param = array(                'grant_type'=>'authorization_code',                'code'=>$code,            );            $header = array(                'Authorization: Basic ' .base64_encode(self::APPID . ':' . self::APPSECRET),            );            $res = http_request($url,$method,$param,$header);            $res = json_decode($res);            return $res;    }
  • 最终获取资源层资源
{"error": 0,"message": "数据拿出成功","data": "RE_zjw"}
0 0