记录一次对接Github授权登陆遇到的问题及经验分享!

前两天对接了Gitee,可以说,很快啊!非常快!就对接好了,半个小时都没要到!大大鼓舞了我的自信心!结果今晚对接Github授权登陆,MD,从完善8点吃完饭,一直对接到现在!主要是耽误时间的是卡到了 curl 设置 headers 和 github 对接接口除了基本的常见鉴权 Authorization 字段,还需要一个额外的 User-Agent,我滴妈,就这一个 User-Agent 字段,加上本身对 curlheaders 写法不熟,足足卡了一晚上!

截图_选择区域_20211109233351.png

申请步骤

Xnip2021-11-11_13-15-34.jpg

  1. 首先你肯定得有Github账号
  2. 其次你自己得登录这个账号
  3. 打开 https://github.com/settings/developers 这个链接,创建应用
  4. 填写对应信息
  5. 开始开发!

成品分享

因为昨天已经分享了对接gitee的经验,对接github其实也大同小异,因此我直接就先直接上成品代码供大家参考了!

目录结构

截图_选择区域_20211109234039.png

网络请求工具类封装

这个工具类我在昨天的基础上进一步优化了一下,支持设置头了!因为我项目是使用的 ThinkPHP 5.1,避免跟框架的 Request 类冲突,因此我给改名成 HttpReuqest 了!

<?php

namespace app\common\util;

/**
 * 发送网络请求工具类
 * @author huangjunjie
 * @version 1.0.1
 */
class HttpRequest
{
    /**
     * 发送 post 请求
     * @param $url
     * @param array $data
     * @param array $header
     * @param bool $json
     * @return mixed
     */
    public function post($url, $data = array(), $header = array(), $json = false)
    {
        // 初始化
        $curl = curl_init();
        // 设置抓取的url
        curl_setopt($curl, CURLOPT_URL, $url);
        // 设置请求头
        curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
        // 设置头文件的信息作为数据流输出
        curl_setopt($curl, CURLOPT_HEADER, 0);
        // 设置获取的信息以文件流的形式返回,而不是直接输出。
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        // 设置post方式提交
        curl_setopt($curl, CURLOPT_POST, 1);
        // 设置post数据
        curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
        // 关闭证书校验
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
        // 执行命令
        $output = curl_exec($curl);

        // 关闭URL请求
        curl_close($curl);

        return $json ? json_decode($output, true) : $output;
    }

    /**
     * 发送 GET 请求
     * @param $url
     * @param array $data
     * @param array $header
     * @param bool $json
     * @return mixed
     */
    public function get($url, $data = array(), $header = array(), $json = false)
    {
        // 初始化
        $curl = curl_init();
        // 设置选项,包括URL
        $query = http_build_query($data);
        // 拼接url
        $url = $url . '?' . $query;

        // 设置抓取的url
        curl_setopt($curl, CURLOPT_URL, $url);
        // 设置头文件的信息作为数据流输出
        curl_setopt($curl, CURLOPT_HEADER, 0);
        // 设置请求头
        curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
        // 设置获取的信息以文件流的形式返回,而不是直接输出。
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        // 关闭证书校验
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
        // 执行并获取HTML文档内容
        $output = curl_exec($curl);
        // 释放curl句柄
        curl_close($curl);

        return $json ? json_decode($output, true) : $output;
    }

    /**
     * 发送 POST 请求,且确认返回值为json
     * @param $url
     * @param array $data
     * @param array $header
     * @return mixed
     */
    public function postJson($url, $data = array(), $header = array())
    {
        return $this->post($url, $data, $header, true);
    }

    /**
     * 发送 GET 请求,且确认返回值为json
     * @param $url
     * @param array $data
     * @param array $header
     * @return mixed
     */
    public function getJson($url, $data = array(), $header = array())
    {
        return $this->get($url, $data, $header, true);
    }
}

配置文件分享

我比较喜欢把配置写在 common.php 里,这个因人而异,这里我直接把我完整的佩服发上来,也包含了 Gitee 的配置!

<?php
// 码云授权登陆配置,相关页面:https://gitee.com/oauth/applications
const AUTH_LOGIN_GITEE_CLIENT_ID = "换成你自己的 CLIENT_ID";
const AUTH_LOGIN_GITEE_CLIENT_SECRET = "换成你自己的!CLIENT_SECRET";
const AUTH_LOGIN_GITEE_REDIRECT_URI = "换成你自己的回调地址!";
const AUTH_LOGIN_GITEE_GET_TOKEN = "https://gitee.com/oauth/token";
const AUTH_LOGIN_GITEE_GET_USERINFO = "https://gitee.com/api/v5/user";
const AUTH_LOGIN_GITEE_AUTH_URI = "https://gitee.com/oauth/authorize";

// Github授权登陆配置,相关页面:https://github.com/settings/developers
const AUTH_LOGIN_GITHUB_CLIENT_ID = "换成你自己的 CLIENT_ID";
const AUTH_LOGIN_GITHUB_CLIENT_SECRET = "换成你自己的!CLIENT_SECRET";
const AUTH_LOGIN_GITHUB_REDIRECT_URI = "换成你自己的回调地址!";
const AUTH_LOGIN_GITHUB_GET_TOKEN = "https://github.com/login/oauth/access_token";
const AUTH_LOGIN_GITHUB_GET_USERINFO = "https://api.github.com/user";
const AUTH_LOGIN_GITHUB_AUTH_URI = "https://github.com/login/oauth/authorize";

业务代码分享

<?php

namespace app\oauth\controller;

use app\common\util\HttpRequest;
use think\facade\Request;
use think\response\Redirect;

/**
 * 这个控制器修改了下,不继承 Controller了,方便你们复制直接用
 * @author huangjunjie
 * @version 1.0.0
 */
class Platform
{
    /**
     * 码云授权登陆,也负责承担回调页面的责任
     * @return array|Redirect
     */
    public function gitee()
    {
        // 通过回调函数获取code
        $code = Request::get("code");

        // 如果没有code则自动重定向到授权页面
        if (is_null($code)) {
            $url = AUTH_LOGIN_GITEE_AUTH_URI;
            $query = http_build_query([
                "client_id" => AUTH_LOGIN_GITEE_CLIENT_ID,
                "redirect_uri" => AUTH_LOGIN_GITEE_REDIRECT_URI,
                "response_type" => "code"
            ]);
            return redirect($url . "?" . $query);
        } else {
            // 获取access_token
            $request = new HttpRequest();
            $login = $request->postJson(AUTH_LOGIN_GITEE_GET_TOKEN, [
                "grant_type" => "authorization_code",
                "code" => $code,
                "client_id" => AUTH_LOGIN_GITEE_CLIENT_ID,
                "redirect_uri" => AUTH_LOGIN_GITEE_REDIRECT_URI,
                "client_secret" => AUTH_LOGIN_GITEE_CLIENT_SECRET,
            ]);

            // 如果报错提示,没报错则请求获取用户信息接口
            if (isset($login["error"])) {
                return ["code" => 401, "msg" => $login["error_description"]];
            } else {
                // Gitee 这里是直接通过 GET 参数传递 Token
                $userinfo = $request->getJson(AUTH_LOGIN_GITEE_GET_USERINFO, ["access_token" => $login["access_token"]]);
                // 这里返回获得的用户信息,具体可自己根据实际业务继续走
                return ["code" => 200, "data" => $userinfo];
            }
        }
    }

    /**
     * Github授权登陆,也负责承担回调页面的责任
     * @return array|Redirect
     */
    public function github()
    {
        // 通过回调函数获取code
        $code = Request::get("code");

        // 如果没有code则自动重定向到授权页面
        if (is_null($code)) {
            $url = AUTH_LOGIN_GITHUB_AUTH_URI;
            $query = http_build_query([
                "client_id" => AUTH_LOGIN_GITHUB_CLIENT_ID,
                "redirect_uri" => AUTH_LOGIN_GITHUB_REDIRECT_URI
            ]);
            return redirect($url . "?" . $query);
        } else {
            // 获取access_token
            $request = new HttpRequest();
            $login = $request->post(AUTH_LOGIN_GITHUB_GET_TOKEN, [
                "code" => $code,
                "client_id" => AUTH_LOGIN_GITHUB_CLIENT_ID,
                "redirect_uri" => AUTH_LOGIN_GITHUB_REDIRECT_URI,
                "client_secret" => AUTH_LOGIN_GITHUB_CLIENT_SECRET,
            ]);
            // 这是里Github需要注意的,Github默认返回不是json,而是一个普通的query字符串
            // 因此这里我们使用PHP内置的 parse_str 将 query 字符串专为 json 数据
            parse_str($login, $json);

            // 如果报错提示,没报错则请求获取用户信息接口
            if (isset($json["error"])) {
                return ["code" => 401, "msg" => $json["error_description"]];
            } else {
                // 注意!这里Github需要在常规鉴权 Authorization 字段的基础上
                // 还需要额外包含一个 User-Agent 字段,这里为了方便,就直接把默认的头部对应字段转发过去了
                // 按照 Github 官方要求, 这里的 User-Agent 字段应该是联系方式或者应用地址
                // Github 官方的意思就是:如果你敢捣乱,就方便我找到你!嗯!
                $userinfo = $request->getJson(AUTH_LOGIN_GITHUB_GET_USERINFO, [], [
                    "Authorization: Bearer " . $json["access_token"],
                    "User-Agent: " . Request::header("user-agent")
                ]);
                // 这里返回获得的用户信息,具体可自己根据实际业务继续走
                return ["code" => 200, "data" => $userinfo];
            }
        }
    }
}