• 技术文章 >后端开发 >php教程

    原生 PHP 实现支付宝 App 第三方登录获取用户信息

    藏色散人藏色散人2019-09-12 17:56:40转载1596
    背景

    App 项目要求实现第三方 微信 和 支付宝 登录,微信可以直接在 App 端完成认证拿到用户信息,支付宝则需要后端获取。

    流程

    1、服务端先拿到 App 端 调用 支付宝 SDK 所需要的 infoStr

    2、App 端 通过 infoStr 获得用户 授权 code

    3、服务端通过 授权 code 拿到请求 token

    4、服务端通过 token 获得用户信息

    代码

    在这之前,支付宝接口对接流程你应该有所了解。

    1、创建 RSA2 方法:获得 sign:

    /**
     * enRSA2 RSA加密
     * 
     * @param String $data
     * @return String
     */
    private function enRSA2($data)
    {
        $str = chunk_split(trim($this->private_key), 64, "\n");
        $key = "-----BEGIN RSA PRIVATE KEY-----\n$str-----END RSA PRIVATE KEY-----\n";
        // $key = file_get_contents(storage_path('rsa_private_key.pem')); 为文件时这样引入
        $signature = '';
        $signature = openssl_sign($data, $signature, $key, OPENSSL_ALGO_SHA256)?base64_encode($signature):NULL;
        return $signature;
    }

    2、创建一个 Get 参数拼接方法,保证符合支付宝加签字符串要求:

    /**
     * myHttpBuildQuery
     * 之所以不用 自带函数 `http_build_query` 
     * 是因为格式化的时间带有  ‘:’  会被转换成十六进制 utf-8 码
     * 
     * @param Array
     * @return String
     */
    private function myHttpBuildQuery($dataArr)
    {
        ksort($dataArr);
        $signStr = '';
        foreach ($dataArr as $key => $val) {
            if (empty($signStr)) {
                $signStr = $key.'='.$val;
            } else {
                $signStr .= '&'.$key.'='.$val;
            }
        }
        return $signStr;  
    }

    3、给到 APP 端需要的 infoStr:

    /**
     * InfoStr APP登录需要的的infostr
     * 
     * @return String
     */
    public function infoStr()
    {
        $infoStr = http_build_query([
            'apiname' => 'com.alipay.account.auth',
            'method' => 'alipay.open.auth.sdk.code.get',
            'app_id' => $this->app_id,
            'app_name' => 'mc',
            'biz_type' => 'openservice',
            'pid' => $this->pid,
            'product_id' => 'APP_FAST_LOGIN',
            'scope' => 'kuaijie',
            'target_id' => mt_rand(999, 99999), //商户标识该次用户授权请求的ID,该值在商户端应保持唯一
            'auth_type' => 'AUTHACCOUNT', // AUTHACCOUNT代表授权;LOGIN代表登录
            'sign_type' => 'RSA2',
        ]);
        $infoStr .= '&sign='.$this->enRSA2($infoStr);
        return $infoStr;
    }

    4、拿到用户信息:

     /**
         * AlipayToken 获得用户 请求token, 通过它获得 用户信息
         * 
         * 需要按照支付宝加签流程来。
         */
        public function userInfo($app_auth_token)
        {
            $infoArr = [
                'method' => 'alipay.system.oauth.token',
                'app_id' => $this->app_id,
                'charset' => 'utf-8',
                'sign_type' => 'RSA2',
                'timestamp' => date('Y-m-d H:i:s'),
                'version' => '1.0',
                'code' => $app_auth_token,
                'grant_type' => 'authorization_code',
            ];
            $signStr = $this->myHttpBuildQuery($infoArr);
            $sign = urlencode($this->enRSA2($signStr));
            $qureStr = $signStr.'&sign='.$sign;
            $res = new Client();
            $body = $res->get('https://openapi.alipay.com/gateway.do?'.$qureStr)->getBody()->getContents();
            $body = json_decode($body);
            if (!isset($body->alipay_system_oauth_token_response->access_token)) {
                return '接口异常';
            } else {
                $autho_token = $body->alipay_system_oauth_token_response->access_token;
                $userinfo = $this->aliPayUserInfo($autho_token);
                return $userinfo; // 或则 返回 json_encode($userinfo) 根据实际需求来 
            }
        }
        /**
         * AliPayUserInfo 通过 token 获取用户信息
         */
        private function aliPayUserInfo($autho_token)
        {
            $infoArr = [
                'method' => 'alipay.user.info.share',
                'app_id' => $this->app_id,
                'charset' => 'utf-8',
                'sign_type' => 'RSA2',
                'timestamp' => date('Y-m-d H:i:s'),
                'version' => '1.0',
                'auth_token' => $autho_token,
            ];
            $signStr = $this->myHttpBuildQuery($infoArr);
            $sign = urlencode($this->enRSA2($signStr));
            $qureStr = $signStr.'&sign='.$sign;
            $res = new Client();
            $body = $res->get('https://openapi.alipay.com/gateway.do?'.$qureStr)->getBody()->getContents();
            $body = json_decode($body);
            if (!isset($body->alipay_user_info_share_response)) {
                return '接口异常';
            }
            $body = $body->alipay_user_info_share_response;
            return $body;
        }

    代码总览

    <?php 
    // 使用 Guzzle 做请求操作
    use GuzzleHttp\Client;
    // 支付宝APP 第三方登录
    // 特点:相比微信,支付宝所有敏感信息都在服务端完成, 保证了安全
    //
    // 流程:
    // 1.服务端到APP infoStr 
    // 2.APP端 通过infoStr 获得 auth_code 
    // 3.服务端通过 auth_code 拿到请求 token
    // 4.服务端通过 token 获得用户信息
    class AliPayUser{
        protected $app_id = '支付宝app_id';
        protected $pid = '支付宝pid';
        protected $private_key = '你的私钥';
        /**
         * InfoStr APP登录需要的的infostr
         * 
         * @return String
         */
        public function infoStr()
        {
            $infoStr = http_build_query([
                'apiname' => 'com.alipay.account.auth',
                'method' => 'alipay.open.auth.sdk.code.get',
                'app_id' => $this->app_id,
                'app_name' => 'mc',
                'biz_type' => 'openservice',
                'pid' => $this->pid,
                'product_id' => 'APP_FAST_LOGIN',
                'scope' => 'kuaijie',
                'target_id' => mt_rand(999, 99999), //商户标识该次用户授权请求的ID,该值在商户端应保持唯一
                'auth_type' => 'AUTHACCOUNT', // AUTHACCOUNT代表授权;LOGIN代表登录
                'sign_type' => 'RSA2',
            ]);
            $infoStr .= '&sign='.$this->enRSA2($infoStr);
            return $infoStr;
        }
         /**
         * AlipayToken 获得用户 请求token, 通过它获得 用户信息
         * 
         * 需要按照支付宝加签流程来。
         */
        public function userInfo($app_auth_token)
        {
            $infoArr = [
                'method' => 'alipay.system.oauth.token',
                'app_id' => $this->app_id,
                'charset' => 'utf-8',
                'sign_type' => 'RSA2',
                'timestamp' => date('Y-m-d H:i:s'),
                'version' => '1.0',
                'code' => $app_auth_token,
                'grant_type' => 'authorization_code',
            ];
            $signStr = $this->myHttpBuildQuery($infoArr);
            $sign = urlencode($this->enRSA2($signStr));
            $qureStr = $signStr.'&sign='.$sign;
            $res = new Client();
            $body = $res->get('https://openapi.alipay.com/gateway.do?'.$qureStr)->getBody()->getContents();
            $body = json_decode($body);
            if (!isset($body->alipay_system_oauth_token_response->access_token)) {
                return '接口异常';
            } else {
                $autho_token = $body->alipay_system_oauth_token_response->access_token;
                $userinfo = $this->aliPayUserInfo($autho_token);
                return $userinfo; // 或则 返回 json_encode($userinfo) 根据实际需求来 
            }
        }
        /**
         * AliPayUserInfo 通过 token 获取用户信息
         */
        private function aliPayUserInfo($autho_token)
        {
            $infoArr = [
                'method' => 'alipay.user.info.share',
                'app_id' => $this->app_id,
                'charset' => 'utf-8',
                'sign_type' => 'RSA2',
                'timestamp' => date('Y-m-d H:i:s'),
                'version' => '1.0',
                'auth_token' => $autho_token,
            ];
            $signStr = $this->myHttpBuildQuery($infoArr);
            $sign = urlencode($this->enRSA2($signStr));
            $qureStr = $signStr.'&sign='.$sign;
            $res = new Client();
            $body = $res->get('https://openapi.alipay.com/gateway.do?'.$qureStr)->getBody()->getContents();
            $body = json_decode($body);
            if (!isset($body->alipay_user_info_share_response)) {
                return '接口异常';
            }
            $body = $body->alipay_user_info_share_response;
            return $body;
        }
        /**
         * enRSA2 RSA加密
         * 
         * @param String $data
         * @return String
         */
        private function enRSA2($data)
        {
            $str = chunk_split(trim($this->private_key), 64, "\n");
            $key = "-----BEGIN RSA PRIVATE KEY-----\n$str-----END RSA PRIVATE KEY-----\n";
            // $key = file_get_contents(storage_path('rsa_private_key.pem')); 为文件时这样引入
            $signature = '';
            $signature = openssl_sign($data, $signature, $key, OPENSSL_ALGO_SHA256)?base64_encode($signature):NULL;
            return $signature;
        }
        /**
         * myHttpBuildQuery 返回一个 http Get 传参数组
         * 之所以不用 自带函数 http_build_query 时间带 ‘:’ 会被转换
         * 
         * @param Array
         * @return String
         */
        private function myHttpBuildQuery($dataArr)
        {
            ksort($dataArr);
            $signStr = '';
            foreach ($dataArr as $key => $val) {
                if (empty($signStr)) {
                    $signStr = $key.'='.$val;
                } else {
                    $signStr .= '&'.$key.'='.$val;
                }
            }
            return $signStr;  
        }
    }

    其它

    1.注意:这份代码是从原有项目扒出来,主要是为有此需求的开发人员提供参考,并未测试是否能直接使用,请自行测试。

    2.之所以不用支付宝 php_SDK,是因为需求有限:只获取用户的信息,没必要。

    3.代码有不合理的地方还请提出来,大家互相学习。

    以上就是原生 PHP 实现支付宝 App 第三方登录获取用户信息的详细内容,更多请关注php中文网其它相关文章!

    声明:本文转载于:learnku,如有侵犯,请联系admin@php.cn删除
    专题推荐:PHP
    上一篇:php八大数据类型有哪些 下一篇:php类和对象的关系
    大前端线上培训班

    相关文章推荐

    • php文件上传步骤是什么• php 字符串替换方法• php中定义常量的两种方法• php依赖注入的三种方式

    全部评论我要评论

  • 手机用户1564211880

    您好,支付宝那边一直提示验签失败:"error_response":{"code":"40002","msg":"Invalid Arguments","sub_code":"isv.invalid-signature","sub_msg"

    2020-03-23

  • 取消发布评论发送
  • 1/1

    PHP中文网