在 Go 中使用 Gin 和 GitHub OAuth 实现授权

53 min read

在 Go 中使用 Gin 和 GitHub OAuth 实现授权,可以按照以下步骤进行:

1. 设置 GitHub OAuth 应用

首先,你需要在 GitHub 上创建一个 OAuth 应用。

  • 访问 GitHub Developer Settings
  • 点击 "New OAuth App"。
  • 填写应用名称、主页 URL 以及回调 URL(比如 http://localhost:8080/auth/github/callback)。
  • 提交表单,获取你的 Client IDClient Secret

2. 安装依赖

在你的 Go 项目中,使用 go mod 初始化项目,并安装所需的依赖。

go mod init your_project_name
go get github.com/gin-gonic/gin
go get golang.org/x/oauth2
go get golang.org/x/oauth2/github

3. 编写代码

下面是一个简单的示例,展示如何使用 Gin 和 GitHub OAuth 实现用户登录。

package main

import (
	"context"
	"fmt"
	"log"
	"net/http"

	"github.com/gin-gonic/gin"
	"golang.org/x/oauth2"
	"golang.org/x/oauth2/github"
)

// 设置 GitHub OAuth 配置
var (
	oauthConf = &oauth2.Config{
		ClientID:     "your_client_id",
		ClientSecret: "your_client_secret",
		RedirectURL:  "http://localhost:8080/auth/github/callback",
		Scopes:       []string{"user:email"},
		Endpoint:     github.Endpoint,
	}
	// 随机生成的状态码,可以用于防止 CSRF 攻击
	oauthStateString = "random_state"
)

func main() {
	router := gin.Default()

	// GitHub OAuth 登录路由
	router.GET("/auth/github/login", func(c *gin.Context) {
		url := oauthConf.AuthCodeURL(oauthStateString, oauth2.AccessTypeOffline)
		c.Redirect(http.StatusTemporaryRedirect, url)
	})

	// GitHub OAuth 回调路由
	router.GET("/auth/github/callback", func(c *gin.Context) {
		state := c.Query("state")
		if state != oauthStateString {
			log.Println("Invalid OAuth state")
			c.AbortWithStatus(http.StatusUnauthorized)
			return
		}

		code := c.Query("code")
		token, err := oauthConf.Exchange(context.Background(), code)
		if err != nil {
			log.Printf("Failed to exchange token: %s\n", err.Error())
			c.AbortWithStatus(http.StatusInternalServerError)
			return
		}

		// 使用 GitHub API 获取用户信息
		client := oauthConf.Client(context.Background(), token)
		resp, err := client.Get("https://api.github.com/user")
		if err != nil {
			log.Printf("Failed to get user info: %s\n", err.Error())
			c.AbortWithStatus(http.StatusInternalServerError)
			return
		}
		defer resp.Body.Close()

		var user map[string]interface{}
		if err := json.NewDecoder(resp.Body).Decode(&user); err != nil {
			log.Printf("Failed to decode user info: %s\n", err.Error())
			c.AbortWithStatus(http.StatusInternalServerError)
			return
		}

		// 输出用户信息
		fmt.Printf("User info: %v\n", user)
		c.JSON(http.StatusOK, user)
	})

	router.Run(":8080")
}

4. 代码解释

  • oauth2.Config:这是 OAuth2 的配置,包括 ClientIDClientSecret 和回调 URL 等。
  • AuthCodeURL:生成登录 GitHub 的 URL,并附带一个随机的 state 参数用于防止 CSRF。
  • Exchange:当 GitHub 重定向回应用程序时,使用 code 获取访问令牌。
  • oauthConf.Client:使用访问令牌创建 HTTP 客户端,用于发送请求获取 GitHub 用户信息。

5. 运行程序

确保将 ClientIDClientSecret 替换为你在 GitHub 上生成的实际值。然后运行应用:

go run main.go

访问 http://localhost:8080/auth/github/login,你将被重定向到 GitHub 登录页面,完成授权后,GitHub 会将你重定向回应用并显示用户信息。

注意事项

  • 切勿将 ClientSecret 暴露在前端或公开代码库中。
  • 可以使用环境变量来安全地存储 ClientIDClientSecret
  • 实际开发中应对 OAuth 的 state 值做更多的验证。

这样,你就可以使用 Gin 和 GitHub OAuth 实现用户登录功能了。