From 0f5fe7bfe6698a5213c34a9fe108b505d796cff3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B2=88=E5=94=81?= <52o@qq52o.cn> Date: Mon, 29 Nov 2021 16:51:24 +0800 Subject: [PATCH] Support GitLab (#17) --- README.md | 1 + src/GitLab/OAuth2.php | 187 +++++++++++++++++++++++++++++++++++++ src/GitLab/loginAgent.html | 87 +++++++++++++++++ test/GitLab/callback.php | 16 ++++ test/GitLab/common.php | 8 ++ test/GitLab/login.php | 16 ++++ test/GitLab/loginAgent.php | 5 + 7 files changed, 320 insertions(+) create mode 100644 src/GitLab/OAuth2.php create mode 100644 src/GitLab/loginAgent.html create mode 100644 test/GitLab/callback.php create mode 100644 test/GitLab/common.php create mode 100644 test/GitLab/login.php create mode 100644 test/GitLab/loginAgent.php diff --git a/README.md b/README.md index 10e85f6..faaf17c 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ API 文档:[https://apidoc.gitee.com/yurunsoft/YurunOAuthLogin](https://apidoc - Coding - 开源中国(OSChina) - CSDN +- GitLab > 后续将不断添加新的平台支持,也欢迎你来提交PR,一起完善! diff --git a/src/GitLab/OAuth2.php b/src/GitLab/OAuth2.php new file mode 100644 index 0000000..d34cdd2 --- /dev/null +++ b/src/GitLab/OAuth2.php @@ -0,0 +1,187 @@ +authDomain = $domain; + + return $this; + } + + /** + * 设置api域名. + * + * @param string $domain + * @return $this + */ + public function setApiDomain(string $domain) + { + $this->apiDomain = $domain; + + return $this; + } + + /** + * 获取登录授权url地址 + * + * @param string $name 跟在域名后的文本 + * @param array $params GET参数 + * + * @return string + */ + public function getAuthLoginUrl($name, $params = []) + { + return $this->authDomain . $name . (empty($params) ? '' : ('?' . $this->http_build_query($params))); + } + + /** + * 获取url地址 + * + * @param string $name 跟在域名后的文本 + * @param array $params GET参数 + * + * @return string + */ + public function getUrl($name, $params = []) + { + return $this->apiDomain . $name . (empty($params) ? '' : ('?' . $this->http_build_query($params))); + } + + /** + * 第一步:获取登录页面跳转url. + * + * @param string $callbackUrl 登录回调地址 + * @param string $state 状态值,不传则自动生成,随后可以通过->state获取。用于第三方应用防止CSRF攻击,成功授权后回调时会原样带回。一般为每个用户登录时随机生成state存在session中,登录回调中判断state是否和session中相同 + * @param array $scope 请求用户授权时向用户显示的可进行授权的列表。可空 + * + * @return string + */ + public function getAuthUrl($callbackUrl = null, $state = null, $scope = null) + { + $option = [ + 'client_id' => $this->appid, + 'redirect_uri' => null === $callbackUrl ? $this->callbackUrl : $callbackUrl, + 'response_type' => 'code', + 'state' => $this->getState($state), + 'scope' => null === $scope ? $this->scope : $scope, + ]; + if (null === $this->loginAgentUrl) { + return $this->getAuthLoginUrl('oauth/authorize', $option); + } else { + return $this->loginAgentUrl . '?' . $this->http_build_query($option); + } + } + + /** + * 第二步:处理回调并获取access_token。与getAccessToken不同的是会验证state值是否匹配,防止csrf攻击。 + * + * @param string $storeState 存储的正确的state + * @param string $code 第一步里$redirectUri地址中传过来的code,为null则通过get参数获取 + * @param string $state 回调接收到的state,为null则通过get参数获取 + * + * @return string + */ + protected function __getAccessToken($storeState, $code = null, $state = null) + { + $response = $this->http->post($this->getAuthLoginUrl('oauth/token'), [ + 'client_id' => $this->appid, + 'client_secret' => $this->appSecret, + 'code' => isset($code) ? $code : (isset($_GET['code']) ? $_GET['code'] : ''), + 'redirect_uri' => $this->getRedirectUri(), + 'state' => isset($state) ? $state : (isset($_GET['state']) ? $_GET['state'] : ''), + 'grant_type' => 'authorization_code', + ]); + $this->result = $response->json(true); + if (isset($this->result['error_description'])) { + throw new ApiException($this->result['error_description'], 0); + } else { + return $this->accessToken = $this->result['access_token']; + } + } + + /** + * 获取用户资料. + * + * @param string $accessToken + * + * @return array + */ + public function getUserInfo($accessToken = null) + { + $token = null === $accessToken ? $this->accessToken : $accessToken; + $this->result = $this->http->header('Authorization', "Bearer {$token}") + ->get($this->getUrl('user')) + ->json(true); + if (isset($this->result['error_description'])) { + throw new ApiException($this->result['error_description'], 0); + } else { + $this->openid = $this->result['id']; + + return $this->result; + } + } + + /** + * 刷新AccessToken续期 + * + * @param string $refreshToken + * + * @return bool + */ + public function refreshToken($refreshToken) + { + $response = $this->http->post($this->getAuthLoginUrl('oauth/token'), [ + 'client_id' => $this->appid, + 'client_secret' => $this->appSecret, + 'refresh_token' => $refreshToken, + 'grant_type' => 'refresh_token', + 'redirect_uri' => $this->getRedirectUri(), + ]); + $this->result = $response->json(true); + if (isset($this->result['error_description'])) { + throw new ApiException($this->result['error_description'], 0); + } else { + return $this->accessToken = $this->result['access_token']; + } + } + + /** + * 检验授权凭证AccessToken是否有效. + * + * @param string $accessToken + * + * @return bool + */ + public function validateAccessToken($accessToken = null) + { + try { + $this->getUserInfo($accessToken); + + return true; + } catch (ApiException $e) { + return false; + } + } +} diff --git a/src/GitLab/loginAgent.html b/src/GitLab/loginAgent.html new file mode 100644 index 0000000..32c90dd --- /dev/null +++ b/src/GitLab/loginAgent.html @@ -0,0 +1,87 @@ + + + + + + GitLab登录 + + + + + + + diff --git a/test/GitLab/callback.php b/test/GitLab/callback.php new file mode 100644 index 0000000..86b6ff4 --- /dev/null +++ b/test/GitLab/callback.php @@ -0,0 +1,16 @@ +loginAgentUrl = 'http://test.com/test/GitLab/loginAgent.php'; + +var_dump( + 'access_token:', $gitlabOAuth->getAccessToken($_SESSION['YURUN_GITLAB_STATE']), + '我也是access_token:', $gitlabOAuth->accessToken, + '请求返回:', $gitlabOAuth->result +); +var_dump( + '用户资料:', $gitlabOAuth->getUserInfo(), + 'openid:', $gitlabOAuth->openid +); diff --git a/test/GitLab/common.php b/test/GitLab/common.php new file mode 100644 index 0000000..2962000 --- /dev/null +++ b/test/GitLab/common.php @@ -0,0 +1,8 @@ + '', + 'appkey' => '', + 'callbackUrl' => 'http://test.com/test/GitLab/callback.php', +]; diff --git a/test/GitLab/login.php b/test/GitLab/login.php new file mode 100644 index 0000000..0ebbb2e --- /dev/null +++ b/test/GitLab/login.php @@ -0,0 +1,16 @@ +loginAgentUrl = 'http://localhost/test/GitLab/loginAgent.php'; + +// 所有为null的可不传,这里为了演示和加注释就写了 +$url = $gitlabOAuth->getAuthUrl( + null, // 回调地址,登录成功后返回该地址 + null, // state 为空自动生成 + null // scope 只要登录默认为空即可 +); +$_SESSION['YURUN_GITLAB_STATE'] = $gitlabOAuth->state; +header('location:' . $url); diff --git a/test/GitLab/loginAgent.php b/test/GitLab/loginAgent.php new file mode 100644 index 0000000..e5d18e4 --- /dev/null +++ b/test/GitLab/loginAgent.php @@ -0,0 +1,5 @@ +displayLoginAgent();