Passed
Push — master ( 65f1dc...1ff528 )
by ma
02:06
created

Gateway::checkState()   A

Complexity

Conditions 6
Paths 5

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 5
c 0
b 0
f 0
dl 0
loc 7
rs 9.2222
cc 6
nc 5
nop 0
1
<?php
2
namespace tinymeng\OAuth2\Connector;
3
4
use tinymeng\OAuth2\Helper\ConstCode;
5
use tinymeng\OAuth2\Helper\Str;
6
7
/**
8
 * 所有第三方登录必须继承的抽象类
9
 */
10
abstract class Gateway implements GatewayInterface
11
{
12
    /**
13
     * 配置参数
14
     * @var array
15
     */
16
    protected $config;
17
18
    /**
19
     * AppId
20
     * @var array
21
     */
22
    protected $app_id;
23
24
    /**
25
     * AppSecret
26
     * @var string
27
     */
28
    protected $app_secret;
29
30
    /**
31
     * 回调地址
32
     * @var string
33
     */
34
    protected $callback;
35
36
    /**
37
     * 当前时间戳
38
     * @var int
39
     */
40
    protected $timestamp;
41
42
    /**
43
     * 默认第三方授权页面样式
44
     * @var string
45
     */
46
    protected $display = 'default';
47
48
    /**
49
     * 登录类型:app applets
50
     * @var bool
51
     */
52
    protected $type;
53
54
    /**
55
     * 第三方Token信息
56
     * @var array
57
     */
58
    protected $token = null;
59
60
    /**
61
     * 是否验证回跳地址中的state参数
62
     * @var boolean
63
     */
64
    protected $checkState = false;
65
66
    /**
67
     * 第三方返回的userInfo
68
     * @var array
69
     */
70
    protected $userInfo = [];
71
72
    /**
73
     * 格式化的userInfo
74
     * @var array
75
     */
76
    protected $formatUserInfo = [];
77
78
    /**
79
     * Gateway constructor.
80
     * @param $config
81
     * @throws \Exception
82
     */
83
    public function __construct($config)
84
    {
85
        if (!$config) {
86
            throw new \Exception('传入的配置不能为空');
87
        }
88
        if(isset($_GET['referer']) && $config['callback']){
89
            $config['callback'] .= ((strpos($config['callback'], '?') !== false) ? '&' : '?').'referer='.$_GET['referer'];
90
        }
91
        //默认参数
92
        $_config = [
93
            'app_id'        => '',
94
            'app_secret'    => '',
95
            'callback'      => '',
96
            'response_type' => 'code',
97
            'grant_type'    => 'authorization_code',
98
            'proxy'         => '',
99
            'state'         => '',
100
            'type'          => '',
101
            'is_sandbox'    => false,//是否是沙箱环境
102
        ];
103
        $this->config    = array_merge($_config, $config);
104
        foreach($this->config as $key=>$val){
105
            if(property_exists($this,$key)) $this->$key=$val;
106
        }
107
        $this->timestamp = time();
108
    }
109
110
    /**
111
     * Description:  设置授权页面样式
112
     * @author: JiaMeng <[email protected]>
113
     * Updater:
114
     * @param $display
115
     * @return $this
116
     */
117
    public function setDisplay($display)
118
    {
119
        $this->display = $display;
120
        return $this;
121
    }
122
123
    /**
124
     * Description:  设置是否是App
125
     * @author: JiaMeng <[email protected]>
126
     * Updater:
127
     * @return $this
128
     */
129
    public function setType($type)
130
    {
131
        $this->type = $type;
132
        return $this;
133
    }
134
135
    /**
136
     * Description:  强制验证回跳地址中的state参数
137
     * @author: JiaMeng <[email protected]>
138
     * Updater:
139
     * @return $this
140
     */
141
    public function mustCheckState(){
142
        $this->checkState = true;
143
        return $this;
144
    }
145
146
    /**
147
     * 获取配置信息
148
     * @Author: TinyMeng <[email protected]>
149
     * @return array
150
     */
151
    public function getConfig(){
152
        return $this->config;
153
    }
154
155
    /**
156
     * 设置token(App登录时)
157
     * @param $token
158
     * @return $this
159
     */
160
    public function setToken($token){
161
        $this->token = $token;
162
        return $this;
163
    }
164
165
    /**
166
     * 存储state
167
     * @Author: TinyMeng <[email protected]>
168
     */
169
    public function saveState(){
170
        if ($this->checkState === true) {
171
            //是否开启session
172
            if (session_status() !== PHP_SESSION_ACTIVE) {
173
                session_start();
174
            }
175
            if(empty($this->config['state'])){
176
                $this->config['state'] = Str::random();//生成随机state
177
            }
178
            //存储到session
179
            $_SESSION['tinymeng_oauth_state'] = $this->config['state'];
180
        }
181
    }
182
183
    /**
184
     * 验证state
185
     * @Author: TinyMeng <[email protected]>
186
     * @throws \Exception
187
     */
188
    public function checkState(){
189
        if ($this->checkState === true) {
190
            if (session_status() !== PHP_SESSION_ACTIVE) {
191
                session_start();
192
            }
193
            if (!isset($_REQUEST['state']) || !isset($_SESSION['tinymeng_oauth_state']) || $_REQUEST['state'] != $_SESSION['tinymeng_oauth_state']) {
194
                throw new \Exception('传递的STATE参数不匹配!');
195
            }
196
        }
197
    }
198
199
    /**
200
     * Description:  默认获取AccessToken请求参数
201
     * @author: JiaMeng <[email protected]>
202
     * Updater:
203
     * @return array
204
     */
205
    protected function accessTokenParams(){
206
        $params = [
207
            'client_id'     => $this->config['app_id'],
208
            'client_secret' => $this->config['app_secret'],
209
            'grant_type'    => $this->config['grant_type'],
210
            'code'          => isset($_REQUEST['code']) ? $_REQUEST['code'] : '',
211
            'redirect_uri'  => $this->config['callback'],
212
        ];
213
        return $params;
214
    }
215
216
    /**
217
     * Description:  获取AccessToken
218
     * @author: JiaMeng <[email protected]>
219
     * Updater:
220
     */
221
    protected function getToken(){
222
        if (empty($this->token)) {
223
            /** 验证state参数 */
224
            $this->checkState();
225
226
            /** 获取参数 */
227
            $params = $this->accessTokenParams();
228
229
            /** 获取access_token */
230
            $token =  $this->POST($this->AccessTokenURL, $params);
231
            /** 解析token值(子类实现此方法) */
232
            $this->token = $this->parseToken($token);
0 ignored issues
show
Bug introduced by
The method parseToken() does not exist on tinymeng\OAuth2\Connector\Gateway. Since it exists in all sub-types, consider adding an abstract or default implementation to tinymeng\OAuth2\Connector\Gateway. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

232
            /** @scrutinizer ignore-call */ 
233
            $this->token = $this->parseToken($token);
Loading history...
233
        }
234
    }
235
236
    /**
237
     * Description:  执行GET请求操作
238
     * @author: JiaMeng <[email protected]>
239
     * Updater:
240
     * @param $url
241
     * @param array $params
242
     * @param array $headers
243
     * @return string
244
     */
245
    protected function get($url, $params = [], $headers = [])
246
    {
247
        return \tinymeng\tools\HttpRequest::httpGet($url, $params,$headers);
248
    }
249
250
    /**
251
     * Description:  执行POST请求操作
252
     * @author: JiaMeng <[email protected]>
253
     * Updater:
254
     * @param $url
255
     * @param array $params
256
     * @param array $headers
257
     * @return mixed
258
     */
259
    protected function post($url, $params = [], $headers = [])
260
    {
261
        $headers[] = 'Accept: application/json';//GitHub需要的header
262
        return \tinymeng\tools\HttpRequest::httpPost($url, $params,$headers);
263
    }
264
265
    /**
266
     * 格式化性别参数
267
     * M代表男性,F代表女性
268
     * @param $gender
269
     */
270
    public function getGender($gender){
271
        return strtolower(substr($gender , 0 , 1)) == 'm' ? ConstCode::GENDER_MAN : ConstCode::GENDER_WOMEN;
272
    }
273
}
274