Skip to content

Commit

Permalink
Support GitLab (#17)
Browse files Browse the repository at this point in the history
  • Loading branch information
sy-records committed Nov 29, 2021
1 parent 096a740 commit 0f5fe7b
Show file tree
Hide file tree
Showing 7 changed files with 320 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ API 文档:[https://apidoc.gitee.com/yurunsoft/YurunOAuthLogin](https://apidoc
- Coding
- 开源中国(OSChina)
- CSDN
- GitLab

> 后续将不断添加新的平台支持,也欢迎你来提交PR,一起完善!
Expand Down
187 changes: 187 additions & 0 deletions src/GitLab/OAuth2.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
<?php

namespace Yurun\OAuthLogin\GitLab;

use Yurun\OAuthLogin\ApiException;
use Yurun\OAuthLogin\Base;

class OAuth2 extends Base
{
/**
* 授权接口域名.
*/
public $authDomain = 'https://gitlab.com/';

/**
* api域名.
*/
public $apiDomain = 'https://gitlab.com/api/v4/';

/**
* 设置授权接口域名.
*
* @param string $domain
* @return $this
*/
public function setAuthDomain(string $domain)
{
$this->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;
}
}
}
87 changes: 87 additions & 0 deletions src/GitLab/loginAgent.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8">
<title>GitLab登录</title>
</head>

<body>
<script>
var GWC = {
version: '1.0.0',
urlParams: {},
appendParams: function(url, params) {
if (params) {
var baseWithSearch = url.split('#')[0];
var hash = url.split('#')[1];
for (var key in params) {
var attrValue = params[key];
if (attrValue !== undefined) {
var newParam = key + "=" + attrValue;
if (baseWithSearch.indexOf('?') > 0) {
var oldParamReg = new RegExp('^' + key + '=[-%.!~*\'\(\)\\w]*', 'g');
if (oldParamReg.test(baseWithSearch)) {
baseWithSearch = baseWithSearch.replace(oldParamReg, newParam);
} else {
baseWithSearch += "&" + newParam;
}
} else {
baseWithSearch += "?" + newParam;
}
}
}

if (hash) {
url = baseWithSearch + '#' + hash;
} else {
url = baseWithSearch;
}
}
return url;
},
getUrlParams: function() {
var pairs = location.search.substring(1).split('&');
for (var i = 0; i < pairs.length; i++) {
var pos = pairs[i].indexOf('=');
if (pos === -1) {
continue;
}
GWC.urlParams[pairs[i].substring(0, pos)] = decodeURIComponent(pairs[i].substring(pos + 1));
}
},
doRedirect: function() {
var code = GWC.urlParams['code'];
var appId = GWC.urlParams['client_id'];
var state = GWC.urlParams['state'];
var response_type = GWC.urlParams['response_type'];
var redirectUri;

if (!code) {
//第一步,没有拿到code,跳转至授权页面获取code
redirectUri = GWC.appendParams('https://gitlab.com/oauth/authorize', {
'client_id': appId,
'redirect_uri': encodeURIComponent(GWC.appendParams(location.href.split('?')[0], {
'redirect_uri': encodeURIComponent(GWC.urlParams['redirect_uri']),
})),
'state': state,
'response_type': response_type,
});
} else {
//第二步,从授权页面跳转回来,已经获取到了code,再次跳转到实际所需页面
redirectUri = GWC.appendParams(GWC.urlParams['redirect_uri'], {
'code': code,
'state': state
});
}

location.href = redirectUri;
}
};

GWC.getUrlParams();
GWC.doRedirect();
</script>
</body>

</html>
16 changes: 16 additions & 0 deletions test/GitLab/callback.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

require __DIR__ . '/common.php';
$gitlabOAuth = new \Yurun\OAuthLogin\GitLab\OAuth2($GLOBALS['oauth_gitlab']['appid'], $GLOBALS['oauth_gitlab']['appkey'], $GLOBALS['oauth_gitlab']['callbackUrl']);
// 解决只能设置一个回调域名的问题,下面地址需要改成你项目中的地址,可以参考./loginAgent.php写法
// $gitlabOAuth->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
);
8 changes: 8 additions & 0 deletions test/GitLab/common.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

require dirname(__DIR__) . '/common.php';
$GLOBALS['oauth_gitlab'] = [
'appid' => '',
'appkey' => '',
'callbackUrl' => 'http://test.com/test/GitLab/callback.php',
];
16 changes: 16 additions & 0 deletions test/GitLab/login.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

require __DIR__ . '/common.php';
$gitlabOAuth = new \Yurun\OAuthLogin\GitLab\OAuth2($GLOBALS['oauth_gitlab']['appid'], $GLOBALS['oauth_gitlab']['appkey'], $GLOBALS['oauth_gitlab']['callbackUrl']);

// 解决只能设置一个回调域名的问题,下面地址需要改成你项目中的地址,可以参考./loginAgent.php写法
// $gitlabOAuth->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);
5 changes: 5 additions & 0 deletions test/GitLab/loginAgent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?php

require __DIR__ . '/common.php';
$gitlabOAuth = new \Yurun\OAuthLogin\GitLab\OAuth2();
$gitlabOAuth->displayLoginAgent();

0 comments on commit 0f5fe7b

Please sign in to comment.