Passed
Push — master ( 4ee940...caedb6 )
by ma
01:46
created

Douyin::applets()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 4
dl 0
loc 9
rs 10
c 1
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
/**
3
 * 网站应用抖音登录开发 https://developer.open-douyin.com/docs/resource/zh-CN/dop/develop/openapi/account-permission/douyin-get-permission-code
4
 * 抖音小程序开发 https://developer.open-douyin.com/docs/resource/zh-CN/mini-game/develop/server/log-in/code-2-session/
5
 * 注: scope值
6
 *      1、以 trial.whitelist 放平台里申请了白名单用户一直显示待绑定,请查看https://developer.open-douyin.com/docs/resource/zh-CN/dop/common-question/faq/
7
 *      2、以 user_info为scope发起的网页授权,是用来获取用户的基本信息的。
8
 *      3、以 login_id为scope静默授权。
9
 * 如想打通unionid的话需要将小程序绑定到同一个抖音开放平台
10
 */
11
namespace tinymeng\OAuth2\Gateways;
12
13
use tinymeng\OAuth2\Connector\Gateway;
14
use tinymeng\OAuth2\Helper\ConstCode;
15
16
/**
17
 * Class Douyin
18
 * @package tinymeng\OAuth2\Gateways
19
 * @Author: TinyMeng <[email protected]>
20
 * @Created: 2018/11/9
21
 */
22
class Douyin extends Gateway
23
{
24
    protected $ApiBase            = 'https://open.douyin.com';
25
    protected $AuthorizeURL   = 'https://open.douyin.com/platform/oauth/connect/';
26
    protected $AuthorizeSilenceURL   = 'https://open.douyin.com/oauth/authorize/v2/';//抖音静默授权
27
    protected $AccessTokenURL = 'oauth/access_token/';
28
    protected $UserInfoURL = 'oauth/userinfo/';
29
30
    protected $jsCode2Session = 'https://minigame.zijieapi.com/mgplatform/api/apps/jscode2session';
31
32
    protected $API_BASE_ARRAY = [
33
        'douyin'=>'https://open.douyin.com/',//抖音
34
        'toutiao'=>'https://open.snssdk.com/',//头条
35
        'xigua'=>'https://open-api.ixigua.com/',//西瓜
36
    ];
37
38
    public $oauth_type = ConstCode::TYPE_DOUYIN;//抖音
39
40
    /**
41
     * @param $config
42
     * @throws \Exception
43
     */
44
    public function __construct($config)
45
    {
46
        parent::__construct($config);
47
        //切换方式
48
        $this->switchAccessTokenURL();
49
    }
50
51
    /**
52
     * Description:  得到跳转地址
53
     * @author: JiaMeng <[email protected]>
54
     * Updater:
55
     * @return string
56
     */
57
    public function getRedirectUrl()
58
    {
59
        //存储state
60
        $this->saveState();
61
62
        //登录参数
63
        $params = [
64
            'client_key'    => $this->config['app_id'],
65
            'redirect_uri'  => $this->config['callback'],
66
            'response_type' => $this->config['response_type'],
67
            'scope'         => $this->config['scope'],
68
            'optionalScope' => $this->config['optionalScope']??'',
69
            'state'         => $this->config['state'],
70
        ];
71
        if($params['state'] == 'login_id'){
72
            /**
73
             * 抖音静默获取授权码
74
             * https://developer.open-douyin.com/docs/resource/zh-CN/dop/develop/openapi/account-permission/douyin-default-get-permission-code
75
             */
76
            return $this->AuthorizeSilenceURL . '?' . http_build_query($params);
77
        }else{
78
            return $this->AuthorizeURL . '?' . http_build_query($params);
79
        }
80
    }
81
82
    /**
83
     * Description:  获取当前授权用户的openid标识
84
     * @author: JiaMeng <[email protected]>
85
     * Updater:
86
     * @return mixed
87
     * @throws \Exception
88
     */
89
    public function openid()
90
    {
91
        $this->getToken();
92
93
        if (isset($this->token['open_id'])) {
94
            return $this->token['open_id'];
95
        } else {
96
            throw new \Exception('没有获取到抖音用户ID!');
97
        }
98
    }
99
100
    /**
101
     * Description:  获取格式化后的用户信息
102
     * @return array
103
     * @throws \Exception
104
     * @author: JiaMeng <[email protected]>
105
     * Updater:
106
     */
107
    public function userInfo()
108
    {
109
        //登录参数
110
        $result = $this->getUserInfo();
111
112
        $userInfo = [
113
            'open_id' => $this->openid(),
114
            'access_token'=> $this->token['access_token'] ?? '',
115
            'union_id'=> $this->token['unionid'] ?? '',
116
            'channel' => $this->oauth_type,
117
            'nickname'=> $result['nickname']??'',
118
            'gender'  => $result['gender'] ?? ConstCode::GENDER,
119
            'avatar'  => $result['avatar']??'',
120
        ];
121
        $userInfo['type'] = ConstCode::getTypeConst($userInfo['channel'],$this->type);
122
        return $userInfo;
123
    }
124
125
    /**
126
     * Description:  获取原始接口返回的用户信息
127
     * @return array
128
     * @throws \Exception
129
     * @author: JiaMeng <[email protected]>
130
     * Updater:
131
     */
132
    public function getUserInfo()
133
    {
134
        if($this->type == 'app'){//App登录
135
            if(!isset($_REQUEST['access_token']) ){
136
                throw new \Exception("Douyin APP登录 需要传输access_token参数! ");
137
            }
138
            $this->token['access_token'] = $_REQUEST['access_token'];
139
        }elseif ($this->type == 'applets'){
140
            //小程序
141
            return $this->applets();
142
        }else {
143
            /** 获取token信息 */
144
            $this->getToken();
145
        }
146
147
        /** 获取用户信息 */
148
        $params = [
149
            'access_token'=>$this->token['access_token'],
150
            'open_id'=>$this->openid(),
151
        ];
152
        $data = $this->get($this->UserInfoURL, $params);
153
154
        return $this->parseUserInfo($data);
155
    }
156
157
    /**
158
     * @return array|mixed|null
159
     * @throws \Exception
160
     */
161
    public function applets(){
162
        /** 获取参数 */
163
        $params = $this->jscode2sessionParams();
164
165
        /** 获取access_token */
166
        $token =  $this->get($this->jsCode2Session, $params);
167
        /** 解析token值(子类实现此方法) */
168
        $this->token = $this->parseToken($token);
169
        return $this->token;
170
    }
171
172
    /**
173
     * Description:  根据第三方授权页面样式切换跳转地址
174
     * @author: JiaMeng <[email protected]>
175
     * Updater:
176
     */
177
    private function switchAccessTokenURL()
178
    {
179
        switch ($this->oauth_type){
180
            case ConstCode::TYPE_DOUYIN:$this->ApiBase = $this->API_BASE_ARRAY['douyin'];break;
181
            case ConstCode::TYPE_TOUTIAO:$this->ApiBase = $this->API_BASE_ARRAY['toutiao'];break;
182
            case ConstCode::TYPE_XIGUA:$this->ApiBase = $this->API_BASE_ARRAY['xigua'];break;
183
            default:throw new \Exception("获取抖音 OAUTH_TYPE 参数出错:{$this->oauth_type}");
184
        }
185
        $this->AccessTokenURL = $this->ApiBase.$this->AccessTokenURL;
186
        $this->UserInfoURL = $this->ApiBase.$this->UserInfoURL;
187
    }
188
189
    /**
190
     * Description:  重写 获取的AccessToken请求参数
191
     * @author: JiaMeng <[email protected]>
192
     * Updater:
193
     * @return array
194
     */
195
    protected function accessTokenParams()
196
    {
197
        $params = [
198
            'client_key'      => $this->config['app_id'],
199
            'client_secret'     => $this->config['app_secret'],
200
            'grant_type' => $this->config['grant_type'],
201
            'code'       => $this->getCode(),
202
        ];
203
204
        return $params;
205
    }
206
207
    /**
208
     * Description:  重写 获取的jscode2sessionParams请求参数
209
     * @author: JiaMeng <[email protected]>
210
     * Updater:
211
     * @return array
212
     */
213
    protected function jscode2sessionParams()
214
    {
215
        $params = [
216
            'appid'      => $this->config['app_id'],
217
            'secret'     => $this->config['app_secret'],
218
        ];
219
        if(isset($_REQUEST['code'])) $params['code'] = $_REQUEST['code'];
220
        if(isset($_REQUEST['anonymous_code'])) $params['anonymous_code'] = $_REQUEST['anonymous_code'];
221
222
        return $params;
223
    }
224
225
    /**
226
     * Description:  解析access_token方法请求后的返回值
227
     * @author: JiaMeng <[email protected]>
228
     * Updater:
229
     * @param string $token 获取access_token的方法的返回值
230
     * @return mixed
231
     * @throws \Exception
232
     */
233
    protected function parseToken($token)
234
    {
235
        $data = json_decode($token, true);
236
        if (isset($data['data']['access_token'])) {
237
            return $data['data'];
238
        }elseif (isset($data['session_key'])){
239
            //小程序登录
240
            return $data;
241
        } else {
242
            throw new \Exception("获取抖音 ACCESS_TOKEN 出错:{$token}");
243
        }
244
    }
245
246
    /**
247
     * Description:  解析access_token方法请求后的返回值
248
     * @author: JiaMeng <[email protected]>
249
     * Updater:
250
     * @param string $token 获取access_token的方法的返回值
251
     * @return mixed
252
     * @throws \Exception
253
     */
254
    protected function parseUserInfo($data)
255
    {
256
        $data = json_decode($data, true);
257
        if (isset($data['message']) && $data['message'] == 'success') {
258
            return $data['data'];
259
        } else {
260
            throw new \Exception("获取抖音 UserInfo 出错:{$data['data']['description']}");
261
        }
262
    }
263
264
}
265