Go 语言实现 GitHub 第三方登录(基于 Gin 框架实现)

本文介绍了如何使用OAuth2.0协议实现GitHub第三方登录功能。首先解释了OAuth2.0的基本概念及其在第三方登录和分布式项目授权中的作用。接着详细阐述了在GitHub上注册应用并获取ClientID和Secret,以及前端和后端的实现方法,包括前端创建登录链接,后端处理回调获取Access Token,并进一步获取用户信息。最后展示了简单的 Gin 框架API实现。
摘要由CSDN通过智能技术生成

前言

在我们制作网站或者制作 APP 的时候,经常就会想到去实现一个第三方登录,因为 GitHub 的相关接口已经非常完善,所以这次用 GitHub 进行演示。

OAuth2.0

OAuth2.0是什么

说到第三方登录,那不得不谈的就是 OAuth2.0 。 OAuth2.0 是 OAuth 协议的延续版本,但不向前兼容 OAuth 1.0 (即完全废止了 OAuth1.0 )。 OAuth 2.0 关注客户端开发者的简易性。要么通过组织在资源拥有者和 HTTP 服务商之间的被批准的交互动作代表用户,要么允许第三方应用代表用户获得访问的权限。同时为 Web 应用,桌面应用和手机,和起居室设备提供专门的认证流程。2012年10月, OAuth 2.0 协议正式发布为 RFC 6749 。

OAuth2.0有什么用

  • 第三方应用登录: 比如利用 QQ ,微博,微信授权登录到其他网站或 App 。
  • 分布式或微服务项目中授权: 在 Go 分布式或微服务开发时,后端业务拆分成若干服务,服务之间或前端进行请求调用时,为了安全认证,可以利用 OAuth2.0 进行认证授权。

实现方法

我们需要先在 GitHub 上进行登记处理,依次按以下操作进行.

image-20220313172451550

image-20220313172526740

image-20220313172544797

callback URL 最为重要,此地址为重定向回的 URL 。

image-20220313172600886

image-20220313172625131

Client ID 和 secrets 会在后面有帮助。

前端页面

因为博主并不会前端,所以只起了一个非常简单的页面,并命为register.html,图标随意找一个或者不用都行

 <a href="https://github.com/login/oauth/authorize?
 client_id=a915******53c297a8ea&redirect_uri=www.*****.work/login/register.html">
 <img src="image2/github.jpeg" alt=""></a>

client_id 为上文中所获得的,url 需要和 GitHub 中输入的保持一致

image-20220313173756982

后端实现

model层

type Conf struct {
    ClientId     string
    ClientSecret string //GitHub里所获取
    RedirectUrl  string //重定向URL
}

type Token struct {
    AccessToken string `json:"access_token"` //唯一有用,所以只传了这个
}

service层

var conf = model.Conf{
   ClientId:     "a91******c53c297a8ea",
   ClientSecret: "d39c4******b4d493b17745ac2db24f699be08f",
   RedirectUrl:  "http://42.192.***.29:8080/oauth",
}

//获取地址
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,
   )
}

func GetToken(url string) (*model.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 model.Token
   if err = json.NewDecoder(res.Body).Decode(&token); err != nil {
      return nil, err
   }
   return &token, nil
}

func GetUserInfo(token *model.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
}

api层

func Oauth(ctx *gin.Context) {
   var err error
   // 获取 code
   var code = ctx.Query("code")
   // 通过 code, 获取 token
   var tokenAuthUrl = service.GetTokenAuthUrl(code)
   var token *model.Token
   if token, err = service.GetToken(tokenAuthUrl); err != nil {
      tool.RespInternalError(ctx)
      return
   }// 通过token,获取用户信息
   var userInfo map[string]interface{}
   userInfo, err = service.GetUserInfo(token)
   if err != nil {
      tool.RespInternalError(ctx)
      return
   }
   user := userInfo["login"].(string)//获取GitHub用户的注册名便于注册
   c := model.MyClaims{
      Username: user,
      StandardClaims: jwt.StandardClaims{
         NotBefore: time.Now().Unix() - 60,
         ExpiresAt: time.Now().Unix() + 6000000,
         Issuer:    "xx",
      },
   }
   t := jwt.NewWithClaims(jwt.SigningMethodHS256, c)
   s, err := t.SignedString(mySigningKey)
   if err != nil {
      tool.RespInternalError(ctx)
   }
   tool.RespSuccessfulWithTwoDate2(ctx, user, s)//向前端传出token以及用户名

}

最后将其注册在你的路由中即可。

效果

由于没有前端,只能看看网页呈现的JSON格式资源

image-20220313193624273

结语

如果有没弄清楚的地方欢迎大家向我提问,我都会尽力解答

这是我的 GitHub 主页 github.com/L2ncE

欢迎大家 Follow/Star/Fork 三连

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

L2ncE

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值