支付宝赞助帐号:service@kuitao8.com 

thinkphp5.0 oauth2.0实现跨域登录的方法

Created2018-01-30   Views 1965    Author 懒人程序

Client.php

<?php
namespace app\index\controller;

use think\Controller;

class Client extends Controller
{
    const GET_AUTH_CODE_URL = "http://www.c.com/public/index.php/Index/Server/authorize";
    const GET_ACCESS_TOKEN_URL = "http://www.c.com/public/index.php/Index/Server/token";
    const GET_RESOURCE_URL = "http://www.c.com/public/index.php/Index/Server/resource";
    const APP_ID = "testclient";    //应用的APPKEY
    const APP_SECRET = "testpass";//应用密钥
    const REDIRECT_URI = 'http://www.c.com/public/index.php/Index/Client/login';//成功授权后的回调地址
    public static function getAuthorizeUrl($app_param=array()){
        $params = array(
            'response_type'=>'code',
            'client_id'=>isset($app_param['appid'])?$app_param['appid']:SELF::APP_ID,
            'redirect_uri'=>isset($app_param['redirect_uri'])?$app_param['redirect_uri']:SELF::REDIRECT_URI,
            'state'=>$app_param['state'],
        );
        $authorze_url = SELF::GET_AUTH_CODE_URL.'?'.http_build_query($params);
        return $authorze_url;
    }
    public static function getToken($app_param=array()){
        $params = array(
            'grant_type'=>'authorization_code',
            'client_id'=>isset($app_param['appid'])?$app_param['appid']:SELF::APP_ID,
            'redirect_uri'=>isset($app_param['redirect_uri'])?$app_param['redirect_uri']:SELF::REDIRECT_URI,
            'client_secret'=>isset($app_param['app_secret'])?$app_param['app_secret']:SELF::APP_SECRET,
            'code'=>$app_param['code'],
        );
        $response = self::post(SELF::GET_ACCESS_TOKEN_URL,$params);
        return $response;

    }
    public static function getApiData($app_param=array()){

        $params = array(
            'access_token'=>$app_param['access_token'],
        );
        $openid_url = SELF::GET_RESOURCE_URL.'?'.http_build_query($params);
        //   echo $openid_url;
        $str  = file_get_contents($openid_url);
        $data = json_decode($str,true);
        return $data;

    }
    public function login(){
        $code = isset($_REQUEST["code"])?$_REQUEST["code"]:'';
        if(empty($code))
        {
            //state参数用于防止CSRF攻击,成功授权后回调时会原样带回
            session('state', md5(uniqid(rand(), TRUE)));
            $data['state'] =  session('state');
            $authorze_url = $this->getAuthorizeUrl($data);
            header('Location:'.$authorze_url);
        }
        if(isset($_REQUEST['state']) && ($_REQUEST['state'] == session('state')))
        {
            //Step2:通过Authorization Code获取Access Token
            $data = array(
                'code'=>$code,
            );

            if(!empty($_SESSION['token']) && $_SESSION['token_expire_at']>time()){
                $token =  $_SESSION['token'];

            }else{
                $token =  $this->getToken($data);

            }
            //Step3:使用Access Token来获取用户的OpenID
            if(!empty($token['access_token']))
            {
                $_SESSION['token'] = $token;
                $_SESSION['token_expire_at'] = time()+$token['expires_in'];
                $user_info =  $this->getApiData($token);
                var_dump($user_info);
            }else{
                exit('token error...');
            }
        }else{
            exit("csrf...");
        }
    }
    /***
     * @param $url
     * @param array $header_options
     * @return mixed
     */
    static function get($url,array $header_options = array())
    {
        $ch = curl_init();
        $curl_options = array(
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => 1, //返回原生的(Raw)输出
            //            CURLOPT_HEADER => 0,
            //            CURLOPT_TIMEOUT => 120, //超时时间
            //            CURLOPT_FOLLOWLOCATION => 1, //是否允许被抓取的链接跳转
            CURLOPT_ENCODING=>'gzip,deflate',
            CURLOPT_HTTPHEADER => $header_options,
        );
        if (strpos($url,"https")!=false) {
            $curl_options[CURLOPT_SSL_VERIFYPEER] = false; // 对认证证书来源的检查
        }
        curl_setopt_array($ch, $curl_options);
        $res = curl_exec($ch);
        $data = json_decode($res,true);
        if(json_last_error() != JSON_ERROR_NONE){
            $data = $res;
        }
        curl_close($ch);
        return $data;
    }
    /**
     * post 请求
     * @param $url 请求url
     * @param array $param  post参数
     * @param array $header 头部信息
     * @param bool $login   是否登陆
     * @param int $ssl      启用ssl
     * @param int $log      是否记录日志
     * @param string $format返回数据格式
     * @return mixed
     */
    static function post($url, array $param = array(), array $header = array())
    {
        $ch = curl_init();
        $post_param = array();
        if (is_array($param)) {
            $post_param = http_build_query($param);
        } else if (is_string($param)) { //json字符串
            $post_param = $param;
        }
        $header_options =  $header;
        $curl_options = array(
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => 1, //返回原生的(Raw)输出
            CURLOPT_HEADER => 0,
            CURLOPT_TIMEOUT => 120, //超时时间
            CURLOPT_FOLLOWLOCATION => 1, //是否允许被抓取的链接跳转
            CURLOPT_HTTPHEADER => $header_options,
            CURLOPT_POST => 1, //POST
            CURLOPT_POSTFIELDS => $post_param, //post数据
            CURLOPT_ENCODING=>'gzip,deflate'
        );
        //debug 1
        //        curl_setopt($ch,CURLINFO_HEADER_OUT,1);
        //        curl_setopt($ch,CURLOPT_HEADER,1);
        //debug 2 详细的请求过程
        //        curl_setopt($ch,CURLOPT_VERBOSE,true);
        //        curl_setopt($ch,CURLINFO_HEADER_OUT,0);
        //        curl_setopt($ch,CURLOPT_HEADER,0);
        //        curl_setopt($ch,CURLOPT_VERBOSE,true);
        //        $fp = fopen('php://temp', 'rw+');
        //        curl_setopt($ch,CURLOPT_STDERR,$fp);
        if (strpos($url,"https")!==false) {
            $curl_options[CURLOPT_SSL_VERIFYPEER] = false; // 对认证证书来源的检查
        }
        curl_setopt_array($ch, $curl_options);
        $res = curl_exec($ch);
        // $debug_info = rewind($fp) ? stream_get_contents($fp):"";
        //$debug_info = curl_getinfo($ch);
        //  print_r($debug_info);
        $data = json_decode($res, true);
        if(json_last_error() != JSON_ERROR_NONE){
            $data = $res;
        }
        curl_close($ch);
        return $data;
    }

}

Server.php

<?php
namespace app\index\controller;

use think\Controller;

class Server extends Controller
{

    public function __construct()
    {
        parent::__construct ();
        $config = config('database');
        \OAuth2\Autoloader::register();
        $this->storage = new \OAuth2\Storage\Pdo(array('dsn' =>$config['api_dns'], 'username' => $config['username'], 'password' => $config['password']));
        $this->server = new \OAuth2\Server($this->storage);
        $this->server->addGrantType(new \OAuth2\GrantType\ClientCredentials($this->storage));
        $this->server->addGrantType(new \OAuth2\GrantType\AuthorizationCode($this->storage));
        $this->request = \OAuth2\Request::createFromGlobals();
        $this->response = new \OAuth2\Response();
    }
    public function resource() {
        if (!$this->request) {//验证token
            $this->server->getResponse()->send();
            echo json_encode(array('status' => -1, 'msg' => 'token error','data'=>array()));
        }else{//验证成功
               $token = $this->server->getAccessTokenData(\OAuth2\Request::createFromGlobals());
                $model = M ( "users" );
                $user_info = $model->where ( "user_id='{$token['user_id']}'" )->field('user_id,username,last_name')->find ();
                $data = array(
                    'status' => 1,
                    'msg' => 'msg',
                    'data'=>array(
                        'token_info'=>$token,
                        'user_info'=>$user_info
                    )
                );
                echo json_encode($data);
            }

        /*
        if ($rs = $this->require_scope ( "userinfo" )) {//授权成功
            $model = M ( 'access_tokens' );
            $data = $model->field ( "user_id" )->where ( "access_token='{$_GET['access_token']}'" )->find ();
            $model = M ( "users" );
            $data = $model->where ( "user_id='{$data['user_id']}'" )->find ();
            $this->arrayRecursive ( $data, 'urlencode', true );
            $json = json_encode ( $data );
            echo urldecode ( $json );exit;
        }*/
    }
    public function authorize(){
        if (!$this->server->validateAuthorizeRequest($this->request, $this->response)) {
            $this->response->send();
            die;
        }
        if (empty($_POST)) {
            exit('
<form method="post">
  <label>第三方登录?</label><br />
  <p><span>账号:</span><input type="text" name="username" value=""></p>
  <p><span>密码:</span><input type="password" name="password" value="" /></p>
  <input type="submit" name="authorized" value="登录">
</form>');
        }
        $name = $_POST ['username'];
        $pass = $_POST ['password'];
        $model = M ( "users" );
        $rs = $model->where ( "username='{$name}' and password='{$pass}'" )->find ();
        if (empty ( $rs )) {
            echo "用户名 密码错误";
            die ();
        }
        $is_authorized = ($_POST['authorized'] === '登录');
        $this->server->handleAuthorizeRequest($this->request, $this->response, $is_authorized,$rs['user_id']);
        if ($is_authorized) {
            // this is only here so that you get to see your code in the cURL request. Otherwise, we'd redirect back to the client
            $code = substr($this->response->getHttpHeader('Location'), strpos($this->response->getHttpHeader('Location'), 'code=')+5, 40);
            $result = $this->response->setRedirect2(302,$_GET['redirect_uri'].'?code='.$code."&state=".$_GET['state']);
            /*
             * $code = substr ( $this->response->getHttpHeader ( 'Location' ), strpos ( $this->response->getHttpHeader ( 'Location' ), 'code=' ) + 5, 40 );
            header ( "Location: " . $this->response->getHttpHeader ( 'Location' ) );
             */
            header("Location:$result");exit;
        }
        $this->response->send();
    }
    public function token(){
        $this->server->handleTokenRequest(\OAuth2\Request::createFromGlobals())->send();
    }
    /**
     * token校验
     * 正确返回 true
     * 错误返回错误信息
     * @param string $scope
     */
    public function require_scope($scope = "") {
        if (! $this->server->verifyResourceRequest ( $this->request, $this->response, $scope )) {
            return $this->server->getResponse ()->send ();
        } else {
            return true;
        }
    }
    /**
     * token 过期后 刷新token
     */
    public function refresh_token(){
        $this->server->addGrantType(new \OAuth2\GrantType\RefreshToken($this->storage, array(
            "always_issue_new_refresh_token" => true,
            "unset_refresh_token_after_use" => true,
            "refresh_token_lifetime" => 2419200,
        )));
        $this->server->handleTokenRequest($this->request)->send();
    }
    /**
     * 客户端认证模式
     */
    public function client_credentials(){
        $this->server->addGrantType(new \OAuth2\GrantType\ClientCredentials($this->storage, array(
            "allow_credentials_in_request_body" => true
        )));
        $this->server->handleTokenRequest($this->request)->send();
    }
    //json乱码
    function arrayRecursive(&$array, $function, $apply_to_keys_also = false) {
        foreach ( $array as $key => $value ) {
            if (is_array ( $value )) {
                $this->arrayRecursive ( $array [$key], $function, $apply_to_keys_also );
            } else {
                $array [$key] = $function ( $value );
            }

            if ($apply_to_keys_also && is_string ( $key )) {
                $new_key = $function ( $key );
                if ($new_key != $key) {
                    $array [$new_key] = $array [$key];
                    unset ( $array [$key] );
                }
            }
        }
    }
}

https://github.com/shophome/tp_oauth2.0_server_client

上一篇: 收集整理一些常用的PHP类库
下一篇: php composer openssl 证书问题
支持键盘 ← →

邮件订阅

订阅我们的精彩内容