Go语言实现第三方登录Github (通过OAuth2.0)

导言

  1. 关于 OAuth2.0 是什么,可以参考阮一峰老师的文章 — OAuth 2.0 的一个简单解释
  2. 以下将使用 Go 语言,通过 OAuth2.0 ,达到第三方登录Github的目的。并在登录成功后,展示用户 Github 的信息。
  3. 最终源码参考: Go语言第三方登录Github

原理

第三方网站登录 Github 的原理如下:

  1. 用户在第三方网站点击 Github授权登录 后,浏览器跳转到 Github 登录页面。
  2. 用户在 Github 登录成功后,浏览器重定向回第三方网站。此时浏览器会携带一个 code
  3. 第三方网站服务器通过 codeGithub 索取 token
  4. Github 返回 token
  5. 第三方网站服务器收到 token 后,就可以通过 token 获取用户信息了。

不懂也没关系,下面将循序渐进的进行实现。


实战

登记阶段

第三方网站要登录 Github 必须进行登记。访问这个网址,可以进行登记。
在这里插入图片描述
上面的 Authorization callback URL 就是 用户在 Github 登录成功后重定向回的 url

登记成功后,可以看到以下信息:
在这里插入图片描述
Github 会通过识别这些信息,判断第三方网站能否进行合法登录。

在编写代码阶段,我会把这些信息放在一个结构体Conf 中。

结构体代码如下:

type Conf struct {
	ClientId     string		// 对应: Client ID
	ClientSecret string		// 对应: Client Secret
	RedirectUrl  string		// 对应: Authorization callback URL
}```

接下来,我们进行代码编写。


页面展示

前端代码如下:
views/hello.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <a href="https://github.com/login/oauth/authorize?client_id={{.ClientId}}&redirect_uri={{.RedirectUrl}}">Github 第三方授权登录</a>
</body>
</html>

上面的 ClientIdRedirectUrl 将在后续传入。

后端代码如下:
main.go

package main

type Conf struct {
	ClientId     string
	ClientSecret string
	RedirectUrl  string
}

var conf = Conf{
	ClientId:     "7e5fe351bc9b131c6f2a",
	ClientSecret: "9fd22c13ae790685c59e3fb4a9b444b75b506a5b",
	RedirectUrl:  "http://localhost:9090/oauth/redirect",
}

func Hello(w http.ResponseWriter, r *http.Request) {
	// 解析指定文件生成模板对象
	var temp *template.Template
	var err error
	if temp, err = template.ParseFiles("views/hello.html"); err != nil {
		fmt.Println("读取文件失败,错误信息为:", err)
		return
	}

	// 利用给定数据渲染模板(html页面),并将结果写入w,返回给前端
	if err = temp.Execute(w, conf); err != nil {
		fmt.Println("读取渲染html页面失败,错误信息为:", err)
		return
	}
}

func main() {
	http.HandleFunc("/", Hello)
	if err := http.ListenAndServe(":9090", nil); err != nil {
		fmt.Println("监听失败,错误信息为:", err)
		return
	}
}

此时,开启 Go 服务器后,打开浏览器访问 http://localhost:9090,将会有以下结果:
在这里插入图片描述

获取 code

点击上面的 Github 第三方授权登录 后,会发现浏览器跳转到了Github登录页面。
在这里插入图片描述当成功登录了Github后,浏览器跳转回了Authorization callback URL,而且还在后面拼接了一串字符串。
在这里插入图片描述
这里, 2549ef9e7720ec61354a 就是 Github 给我们返回的 code

显然,此时我们已经知道 code 了,那服务器怎么获取?

这里采用了一个方法,就是在服务器再编写一个 handler,代码如下:

// 这个函数下面还会用到,请记住函数名
func Oauth(w http.ResponseWriter, r *http.Request) {

	var err error
	var code = r.URL.Query().Get("code") // 获取code
	
	// (省略的代码下面会说)...
}

并在main.go中加入一句代码:

http.HandleFunc("/oauth/redirect", Oauth)	// 这个和 Authorization callback URL 有关

这样,当用户在 Github 登录成功后,服务器就能得到 code 了。

接下来,服务器就可以通过 code 去获取用户的 token 了。


获取用户 token

要想获得 token,必须访问Github 提供 token 的接口。这个接口其实就是一个 url,以下代码可以获得这个 url

// 通过code获取token认证url
func GetTokenAuthUrl(code string) string {
	return fmt.Sprintf(
		"https://github.com/login/oauth/access_token?client_id=%s&client_secret=%s&code=%s",
		conf.ClientId, conf.ClientSecret, code,
	)
}

直接访问这个 url 就能获得 token 了,代码如下:

// 获取 token
func GetToken(url string) (*Token, error) {

	// 形成请求
	var req *http.Request
	var err error
	if req, err = http.NewRequest(http.MethodGet, url, nil); err != nil {
		return nil, err
	}
	req.Header.Set("accept", "application/json")

	// 发送请求并获得响应
	var httpClient = http.Client{}
	var res *http.Response
	if res, err = httpClient.Do(req); err != nil {
		return nil, err
	}

	// 将响应体解析为 token,并返回
	var token Token
	if err = json.NewDecoder(res.Body).Decode(&token); err != nil {
		return nil, err
	}
	return &token, nil
}

type Token struct {
	AccessToken string `json:"access_token"`
	TokenType   string `json:"token_type"` // 这个字段没用到
	Scope       string `json:"scope"`      // 这个字段也没用到
}

小提示: token中,只有 AccessToken 字段是有用的。

于是,OAuth 函数变成了这样:

func Oauth(w http.ResponseWriter, r *http.Request) {

	var err error
	
	// 获取 code
	var code = r.URL.Query().Get("code")

	// 获取 token
	var tokenAuthUrl = GetTokenAuthUrl(code)
	var token *Token	
	if token, err = GetToken(tokenAuthUrl); err != nil {
		fmt.Println(err)
		return
	}
	fmt.Printf("%+v",token)
	// ....
}

接下来,我们测试一下。

重启 Go 服务器,继续访问 http://localhost:9090 ,点击链接并登录。

如果没有出现登录页面,那就是你的电脑的 cookies 中已经保存了登录状态

在服务器端会输出以下信息:
在这里插入图片描述
至此,第三方网站已经成功登录了 Github

接下来,我们利用这个 token,就能获取用户的Github 信息了。


获取用户信息

代码如下:

// 获取用户信息
func GetUserInfo(token *Token) (map[string]interface{}, error) {

	// 形成请求
	var userInfoUrl = "https://api.github.com/user"	// github用户信息获取接口
	var req *http.Request
	var err error
	if req, err = http.NewRequest(http.MethodGet, userInfoUrl, nil); err != nil {
		return nil, err
	}
	req.Header.Set("accept", "application/json")
	req.Header.Set("Authorization", fmt.Sprintf("token %s", token.AccessToken))
	
	// 发送请求并获取响应
	var client = http.Client{}
	var res *http.Response
	if res, err = client.Do(req); err != nil {
		return nil, err
	}

	// 将响应的数据写入 userInfo 中,并返回
	var userInfo = make(map[string]interface{})
	if err = json.NewDecoder(res.Body).Decode(&userInfo); err != nil {
		return nil, err
	}
	return userInfo, nil
}

以上代码将会返回一个 用户信息map


展示用户信息

为了方便,我们继续在Oauth 函数中添加代码。

最终,Oauth 函数如下:

func Oauth(w http.ResponseWriter, r *http.Request) {

	var err error
	
	// 获取 code
	var code = r.URL.Query().Get("code")

	// 通过 code, 获取 token
	var tokenAuthUrl = GetTokenAuthUrl(code)
	var token *Token	
	if token, err = GetToken(tokenAuthUrl); err != nil {
		fmt.Println(err)
		return
	}
	
	// 通过token,获取用户信息
	var userInfo map[string]interface{}
	if userInfo, err = GetUserInfo(token); err != nil {
		fmt.Println("获取用户信息失败,错误信息为:", err)
		return
	}

	//  将用户信息返回前端
	var userInfoBytes []byte
	if userInfoBytes, err = json.Marshal(userInfo); err != nil {
		fmt.Println("在将用户信息(map)转为用户信息([]byte)时发生错误,错误信息为:", err)
		return
	}
	w.Header().Set("Content-Type", "application/json")
	if _, err = w.Write(userInfoBytes); err != nil {
		fmt.Println("在将用户信息([]byte)返回前端时发生错误,错误信息为:", err)
		return
	}

}

最终结果展示

  1. 在所有代码编写完毕后,重启 Go 服务器。
  2. 访问 http://localhost:9090
    在这里插入图片描述2. 点击 Github 第三方授权登录链接。
    在这里插入图片描述3. 在 Github 登录成功后。
    在这里插入图片描述隔了一会儿,跳转回第三方网站。
    在这里插入图片描述以上就是用户的 Github 信息了。

项目源码

Go语言第三方登录Github


最后

感谢阮一峰老师。

阮老师的个人网站

  • 7
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值