要使用github授权登录,需要先去github网站创建你的Oauth APPs
,打开下面页面
https://github.com/settings/developers (settings-> Developer settings-> OAuth Apps)
点击Register a new application
创建应用,填入应用的信息和回调地址
提交后就会看到分配给应用的Client ID
和Client Secret
,在这里可以上传应用的图片
流程
文档地址:https://developer.github.com/apps/building-oauth-apps/authorizing-oauth-apps/
如果你对oauth2.0协议了解了,就会发现每个平台的授权登录流程都大同小异
- 跳转到授权页面,用户同意授权后获取code,code有效期10分钟
GET https://github.com/login/oauth/authorize
参数:
名称 | 类型 | 描述 |
---|---|---|
client_id | string | 必填。您在注册时从GitHub获取收到的Client ID 。 |
redirect_uri | string | 用户授权后回调跳转地址,不传的话使用应用配置填的URL |
login | string | 建议用于登录和授权应用程序的特定帐户。 |
scope | string | 以空格分隔的范围列表。可选择获取哪些数据。详细 |
state | string | 随机字符串,防止跨站点请求伪造攻击。 |
allow_signup | string | 是否为未经身份验证的用户提供了在OAuth流程期间注册GitHub的选项。默认是true。false在策略禁止注册的情况下使用。 |
- 用户同意授权后,携带code跳转回回调地址,使用code获取access_token
POST https://github.com/login/oauth/access_token
参数
名称 | 类型 | 描述 |
---|---|---|
client_id | string | 必填。 您在注册时从GitHub获取收到的Client ID |
client_secret | string | 必填。 您从GitHub收到的GitHub应用程序的Client Secret |
code | string | 必填。 上一步收到的code |
redirect_uri | string | 回调地址 |
state | string | 上一步的随机字符串,防止跨站点请求伪造攻击 |
将会返回access_token,格式如下
access_token=e72e16c7e42f292c6912e7710c838347ae178b4a&token_type=bearer
- 然后使用access_token获取用户信息
Authorization: token OAUTH-TOKEN
GET https://api.github.com/user
注意这块最新v3版本要在这块加上GitHub用户名或应用程序名称作为User-Agent
标头值,文档地址
User-Agent: Awesome-Octocat-App
示例代码
(使用方法)在最后面
<?php
/**
* Github授权登录
* @param $client_id GitHub oauth应用的Client ID
* @param $client_secret GitHub oauth应用的Client Secret
* @param $app_name GitHub用户名或应用程序名,作为User-Agent标头值
* @author codehui <admin@codehui.net> 2019-07-22
*/
class GitOauth {
const GET_AUTH_CODE_URL = "https://github.com/login/oauth/authorize";
const GET_ACCESS_TOKEN_URL = "https://github.com/login/oauth/access_token";
const GET_USER_URL = "https://api.github.com/user";
private $client_id;
private $client_secret;
private $app_name;
public function __construct($client_id, $client_secret, $app_name = 1) {
if($client_id && $client_secret){
$this->client_id = $client_id;
$this->client_secret = $client_secret;
$this->app_name = $app_name;
} else {
$this->error('101', '缺少必要参数');
}
}
/**
* 授权页面
*/
public function gitLogin() {
// 生成唯一随机串防CSRF攻击
$state = md5(uniqid(rand(), TRUE));
session('state', $state);
$uri = $this->combineURL(self::GET_AUTH_CODE_URL, [
"client_id" => $this->client_id,
"state" => $state,
"scope" => 'read:user%20user:email'
]);
header("Location:$uri");
}
/**
* 获取信息
* @return array
*/
public function getInfo(){
$token = $this->getToken();
if (isset($token['errcode'])){
return $token;
}
$info = $this->getUser($token['access_token']);
return $info;
}
/**
* 获取access_token
* @return array
*/
public function getToken() {
// 验证state防止CSRF攻击
if (!$_REQUEST['state'] || $_REQUEST['state'] != session('state')){
return $this->error(0, 'state验证失败');
}
$response = $this->httpsRequest(self::GET_ACCESS_TOKEN_URL, [
'client_id' =>$this->client_id,
'client_secret' => $this->client_secret,
'code' => $_REQUEST['code']
], 'POST');
$params = [];
parse_str($response, $params);
if(isset($params['error'])){
return $this->error($params['error'], $params['error_description']);
}
return $params;
}
/**
* 获取用户信息
* @param $access_token 上一步获取到的access_token
* @return array
*/
public function getUser($access_token) {
$response = $this->httpsRequest(self::GET_USER_URL, [], 'GET', [
"User-Agent: {$this->app_name}",
"Authorization: token {$access_token}"
]);
$response = json_decode($response);
if(!isset($response->login)) {
return $this->error(105, $response);
}
return $response;
}
/**
* 错误信息
* @param int $code 错误代码
* @param string $info 描述信息
* @return array
*/
public function error($code = 0, $msg = ''){
return [
'errcode' => $code,
'errmsg' => $msg
];
}
/**
* 拼接url
* @param string $baseURL 请求的url
* @param array $keysArr 参数列表数组
* @return string 返回拼接的url
*/
public function combineURL($baseURL, $keysArr) {
$combined = $baseURL . "?";
$valueArr = [];
foreach($keysArr as $key => $val){
$valueArr[] = "$key=$val";
}
$keyStr = implode("&", $valueArr);
$combined .= ($keyStr);
return $combined;
}
/**
* 获取服务器数据
* @param string $url 请求的url
* @return unknown 请求返回的内容
*/
public function httpsRequest($url, $keysArr = [], $type = 'GET', $header = []) {
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $type);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
if ($header) {
curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
}
if ($type == 'POST') {
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $keysArr);
}
$output = curl_exec($curl);
curl_close($curl);
return $output;
}
}
使用方法
// 跳转到授权页面
$git = new GitOauth('Client ID', 'Client Secret', 'app_name');
$git->gitLogin();
// 回调方法
$info = $git->getInfo();
echo json_encode($info);
返回数据如下,可以使用node_id
作为用户识别码
{
"login": "octocat",
"id": 1,
"node_id": "MDQ6VXNlcjE=",
"avatar_url": "https://github.com/images/error/octocat_happy.gif",
"gravatar_id": "",
"url": "https://api.github.com/users/octocat",
"html_url": "https://github.com/octocat",
"followers_url": "https://api.github.com/users/octocat/followers",
"following_url": "https://api.github.com/users/octocat/following{/other_user}",
"gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
"starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
"organizations_url": "https://api.github.com/users/octocat/orgs",
"repos_url": "https://api.github.com/users/octocat/repos",
"events_url": "https://api.github.com/users/octocat/events{/privacy}",
"received_events_url": "https://api.github.com/users/octocat/received_events",
"type": "User",
"site_admin": false,
"name": "monalisa octocat",
"company": "GitHub",
"blog": "https://github.com/blog",
"location": "San Francisco",
"email": "octocat@github.com",
"hireable": false,
"bio": "There once was...",
"public_repos": 2,
"public_gists": 1,
"followers": 20,
"following": 0,
"created_at": "2008-01-14T04:33:35Z",
"updated_at": "2008-01-14T04:33:35Z",
"private_gists": 81,
"total_private_repos": 100,
"owned_private_repos": 100,
"disk_usage": 10000,
"collaborators": 8,
"two_factor_authentication": true,
"plan": {
"name": "Medium",
"space": 400,
"private_repos": 20,
"collaborators": 0
}
}