Lumen/Laravel 中支付宝 / 微信第三方 App 登陆

介绍

    现在几乎所有APP都集成了微信/支付宝登录,简化用户操作.这里介绍下在lumen/laravel中如何进行微信/支付宝APP登陆。

配置文件

config.woann.php 这里是我自己创建的配置文件,可以自行调整

<?php
// +----------------------------------------------------------------------
// | Created by PhpStorm
// +----------------------------------------------------------------------
// | Date: 2019-03-29
// +----------------------------------------------------------------------
// | Blog: ( http://www.woann.cn )
// +----------------------------------------------------------------------
// | Author: woann <www.woann.cn>
// +----------------------------------------------------------------------
return [
    //微信
    'wechat'    =>  [
        'app'   =>  [
            'appid'    =>  env('WECHAT_APPID', ''),
            'secret'    =>  env('WECHAT_APP_SECRET', '')
        ]
    ],
    //支付宝
    'alipay'    =>  [
        'app_id'        =>  env('ALI_APP_ID'),
        'pid'           =>  env('ALI_PID'),
        'private_key'   =>  env('ALI_PRIVATE_KEY')
    ]
];

支付宝登录基类

app/utility/AliPayLogin.php 这个文件随便你放哪里,能调用到即可

<?php
// +----------------------------------------------------------------------
// | Created by PhpStorm
// +----------------------------------------------------------------------
// | Date: 2019-05-24
// +----------------------------------------------------------------------
// | Blog: ( http://www.woann.cn )
// +----------------------------------------------------------------------
// | Author: woann <www.woann.cn>
// +----------------------------------------------------------------------
namespace App\Utility;
use GuzzleHttp\Client;
class AliPayLogin
{
    protected $app_id;
    protected $pid;
    protected $private_key;

    public function __construct()
    {
        $config = config('woann.alipay');
        $this->app_id = $config['app_id'];
        $this->pid = $config['pid'];
        $this->private_key = $config['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' => getOrderNo(), //商户标识该次用户授权请求的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 false;
        } 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.获取code字符串(客户端通过这个字符串获取code)

 public function aliLoginInfoStr()
    {
        $ali = new AliPayLogin();//实例化支付
        $res = $ali->infoStr();
        return returnApi(200,'SUCCESS',['str' => $res]);
    }
    /*
    数据示例
        {
        "code":200,
        "msg":"SUCCESS",
        "data":{    "str":"apiname=com.alipay.account.auth&method=alipay.open.auth.sdk.code.get&app_id=2021001100636235&app_name=mc&biz_type=openservice&pid=2088631756058087&product_id=APP_FAST_LOGIN&scope=kuaijie&target_id=44039&auth_type=AUTHACCOUNT&sign_type=RSA2&sign=EXMs+NtovsZEKxcwjprKYwIJIbdeESLYxI/cjyqQ1Re8st0ejTktkX06V+gnyTiwfi9KtdSXbM1HMuC8hGyCEeMZb0IDSyOmOXp+f2dDJDXdlzoqyVowOxn7enTejXnngmu2WDuKQo2KcWfRVBKFlnYyA42QOUYw0PEKiXsgJYdjNPyVqKH9oTJJWIASJgZOgXbY4LSDh8gP+P/5QsuM41fTggeeRLJYHNlvbFuigSF+KpdcPiXXi6huI+4NQpN/7PLzXbVHzdeipkHeYTV6tMZY4njv5RvE4UH9ESd3urpoCgRJxriR/mUdGdQZCDHIBKMXTHmagRXH8mx70SFdpA=="
        }
    }
    */

2.通过code获取用户信息进行登录

public function loginByAli(Request $request)
    {
        $code = $request->post('code');
        $ali = new AliPayLogin();//实例化支付宝登录基类
        $res = $ali->userInfo($code);//获取用户信息
        //....根据业务自行处理
    }

微信登录

1.微信通过code获取用户信息(供微信登录接口调用)

private function getUserInfoByWx($code)
    {
        $app = config('woann.wechat.app');//获取app_id,secret
        $auth_url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=".$app['appid']."&secret=".$app['secret']."&code=".$code."&grant_type=authorization_code";
        $auth_res = httpRequest($auth_url);
        if(isset($auth_res['errcode'])){
            return ['code' => $auth_res['errcode'], 'msg' => $auth_res['errmsg']];
        }
        $info_url = "https://api.weixin.qq.com/sns/userinfo?access_token=".$auth_res['access_token']."&openid=".$auth_res['openid']."&lang=zh_CN";
        $userinfo = httpRequest($info_url);
        if(isset($userinfo['errcode'])){
            return ['code' => $userinfo['errcode'], 'msg' => $userinfo['errmsg']];
        }
        return ['code' => 200, 'msg' => $userinfo];
    }

2.登陆接口

public function loginByWechat(Request $reques)
{
    $code = $request->post('code');
  $userInfo = $this->getUserInfoByWx($code);
    if ($userInfo['code'] != 200) {
        return returnApi($userInfo['code'], $userInfo['msg']);
    }
    //以下根据自己业务进行调整
    DB::beginTransaction();
    //根据openid查询用户是否存在
  $user = $this->where('wechat_openid', $userInfo['msg']['openid'])->first();
  if (!$user) {
        $user = new User();
        $user->avatar = $userInfo['msg']['headimgurl'];
        $user->nickname = $userInfo['msg']['nickname'];
        $user->sex = $userInfo['msg']['sex'];
        $user->wechat_openid = $userInfo['msg']['openid'];
    }
    $res = $user->save();
    if($res){
        if (!$token = Auth::login($user)) {
            DB::rollBack();
            return returnApi(500, '未知错误');
        } else {
            DB::commit();
            return returnApi(200, '登录成功', [
                'access_token' => 'Bearer '.$token
                ]);
        }
    }else{
        DB::rollBack();
        return returnApi(500,'未知错误');
    }
}
本作品采用《CC 协议》,转载必须注明作者和本文链接
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!