要使用github授权登录,需要先去github网站创建你的Oauth APPs,打开下面页面
https://github.com/settings/developers (settings-> Developer settings-> OAuth Apps)

点击Register a new application创建应用,填入应用的信息和回调地址

提交后就会看到分配给应用的Client IDClient Secret,在这里可以上传应用的图片

流程

文档地址:https://developer.github.com/apps/building-oauth-apps/authorizing-oauth-apps/

如果你对oauth2.0协议了解了,就会发现每个平台的授权登录流程都大同小异

  • 跳转到授权页面,用户同意授权后获取code,code有效期10分钟
  1. 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
  1. 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,格式如下

  1. access_token=e72e16c7e42f292c6912e7710c838347ae178b4a&token_type=bearer
  • 然后使用access_token获取用户信息
  1. Authorization: token OAUTH-TOKEN
  2. GET https://api.github.com/user

注意这块最新v3版本要在这块加上GitHub用户名或应用程序名称作为User-Agent标头值,文档地址

  1. User-Agent: Awesome-Octocat-App

示例代码

(使用方法)在最后面

  1. <?php
  2. /**
  3. * Github授权登录
  4. * @param $client_id GitHub oauth应用的Client ID
  5. * @param $client_secret GitHub oauth应用的Client Secret
  6. * @param $app_name GitHub用户名或应用程序名,作为User-Agent标头值
  7. * @author codehui <admin@codehui.net> 2019-07-22
  8. */
  9. class GitOauth {
  10. const GET_AUTH_CODE_URL = "https://github.com/login/oauth/authorize";
  11. const GET_ACCESS_TOKEN_URL = "https://github.com/login/oauth/access_token";
  12. const GET_USER_URL = "https://api.github.com/user";
  13. private $client_id;
  14. private $client_secret;
  15. private $app_name;
  16. public function __construct($client_id, $client_secret, $app_name = 1) {
  17. if($client_id && $client_secret){
  18. $this->client_id = $client_id;
  19. $this->client_secret = $client_secret;
  20. $this->app_name = $app_name;
  21. } else {
  22. $this->error('101', '缺少必要参数');
  23. }
  24. }
  25. /**
  26. * 授权页面
  27. */
  28. public function gitLogin() {
  29. // 生成唯一随机串防CSRF攻击
  30. $state = md5(uniqid(rand(), TRUE));
  31. session('state', $state);
  32. $uri = $this->combineURL(self::GET_AUTH_CODE_URL, [
  33. "client_id" => $this->client_id,
  34. "state" => $state,
  35. "scope" => 'read:user%20user:email'
  36. ]);
  37. header("Location:$uri");
  38. }
  39. /**
  40. * 获取信息
  41. * @return array
  42. */
  43. public function getInfo(){
  44. $token = $this->getToken();
  45. if (isset($token['errcode'])){
  46. return $token;
  47. }
  48. $info = $this->getUser($token['access_token']);
  49. return $info;
  50. }
  51. /**
  52. * 获取access_token
  53. * @return array
  54. */
  55. public function getToken() {
  56. // 验证state防止CSRF攻击
  57. if (!$_REQUEST['state'] || $_REQUEST['state'] != session('state')){
  58. return $this->error(0, 'state验证失败');
  59. }
  60. $response = $this->httpsRequest(self::GET_ACCESS_TOKEN_URL, [
  61. 'client_id' =>$this->client_id,
  62. 'client_secret' => $this->client_secret,
  63. 'code' => $_REQUEST['code']
  64. ], 'POST');
  65. $params = [];
  66. parse_str($response, $params);
  67. if(isset($params['error'])){
  68. return $this->error($params['error'], $params['error_description']);
  69. }
  70. return $params;
  71. }
  72. /**
  73. * 获取用户信息
  74. * @param $access_token 上一步获取到的access_token
  75. * @return array
  76. */
  77. public function getUser($access_token) {
  78. $response = $this->httpsRequest(self::GET_USER_URL, [], 'GET', [
  79. "User-Agent: {$this->app_name}",
  80. "Authorization: token {$access_token}"
  81. ]);
  82. $response = json_decode($response);
  83. if(!isset($response->login)) {
  84. return $this->error(105, $response);
  85. }
  86. return $response;
  87. }
  88. /**
  89. * 错误信息
  90. * @param int $code 错误代码
  91. * @param string $info 描述信息
  92. * @return array
  93. */
  94. public function error($code = 0, $msg = ''){
  95. return [
  96. 'errcode' => $code,
  97. 'errmsg' => $msg
  98. ];
  99. }
  100. /**
  101. * 拼接url
  102. * @param string $baseURL 请求的url
  103. * @param array $keysArr 参数列表数组
  104. * @return string 返回拼接的url
  105. */
  106. public function combineURL($baseURL, $keysArr) {
  107. $combined = $baseURL . "?";
  108. $valueArr = [];
  109. foreach($keysArr as $key => $val){
  110. $valueArr[] = "$key=$val";
  111. }
  112. $keyStr = implode("&", $valueArr);
  113. $combined .= ($keyStr);
  114. return $combined;
  115. }
  116. /**
  117. * 获取服务器数据
  118. * @param string $url 请求的url
  119. * @return unknown 请求返回的内容
  120. */
  121. public function httpsRequest($url, $keysArr = [], $type = 'GET', $header = []) {
  122. $curl = curl_init();
  123. curl_setopt($curl, CURLOPT_URL, $url);
  124. curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $type);
  125. curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
  126. curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
  127. curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
  128. if ($header) {
  129. curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
  130. }
  131. if ($type == 'POST') {
  132. curl_setopt($curl, CURLOPT_POST, 1);
  133. curl_setopt($curl, CURLOPT_POSTFIELDS, $keysArr);
  134. }
  135. $output = curl_exec($curl);
  136. curl_close($curl);
  137. return $output;
  138. }
  139. }
使用方法
  1. // 跳转到授权页面
  2. $git = new GitOauth('Client ID', 'Client Secret', 'app_name');
  3. $git->gitLogin();
  4. // 回调方法
  5. $info = $git->getInfo();
  6. echo json_encode($info);

返回数据如下,可以使用node_id作为用户识别码

  1. {
  2. "login": "octocat",
  3. "id": 1,
  4. "node_id": "MDQ6VXNlcjE=",
  5. "avatar_url": "https://github.com/images/error/octocat_happy.gif",
  6. "gravatar_id": "",
  7. "url": "https://api.github.com/users/octocat",
  8. "html_url": "https://github.com/octocat",
  9. "followers_url": "https://api.github.com/users/octocat/followers",
  10. "following_url": "https://api.github.com/users/octocat/following{/other_user}",
  11. "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
  12. "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
  13. "subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
  14. "organizations_url": "https://api.github.com/users/octocat/orgs",
  15. "repos_url": "https://api.github.com/users/octocat/repos",
  16. "events_url": "https://api.github.com/users/octocat/events{/privacy}",
  17. "received_events_url": "https://api.github.com/users/octocat/received_events",
  18. "type": "User",
  19. "site_admin": false,
  20. "name": "monalisa octocat",
  21. "company": "GitHub",
  22. "blog": "https://github.com/blog",
  23. "location": "San Francisco",
  24. "email": "octocat@github.com",
  25. "hireable": false,
  26. "bio": "There once was...",
  27. "public_repos": 2,
  28. "public_gists": 1,
  29. "followers": 20,
  30. "following": 0,
  31. "created_at": "2008-01-14T04:33:35Z",
  32. "updated_at": "2008-01-14T04:33:35Z",
  33. "private_gists": 81,
  34. "total_private_repos": 100,
  35. "owned_private_repos": 100,
  36. "disk_usage": 10000,
  37. "collaborators": 8,
  38. "two_factor_authentication": true,
  39. "plan": {
  40. "name": "Medium",
  41. "space": 400,
  42. "private_repos": 20,
  43. "collaborators": 0
  44. }
  45. }