登录
原创

go语言实现github和qq第三方登录

发布于 2021-04-13 阅读 1145
  • Go
原创

go实现github第三方登录

github进行第三方登录的【官方文档](https://docs.github.com/en/developers/apps/building-oauth-apps)的每一步指导都很详尽,开发者只需要按照其文档进行操作就能实现第三方登录的功能。大体步骤如下

  1. 创建一个授权应用
    点击创建应用进行创建,页面如下
    image.png
  2. 授权应用程序,获取code
    当用户在第三方网站(即作为开发者的你开发的网站的登录页面)进行登录的时候,用户点击使用github进行登录,此时你应该引导用户跳转到github的授权登录页面,用户在登录之后,会跳转到第一步骤里面所填写的redirect_uri参数所指向的地址
  3. 根据code获取token
    用户授权后,github重定向到你所填写的回调地址时,会携带一个code参数,这个参数的有效期只有10分钟,将在第四步骤使用到
  4. 根据token获取用户信息
    拿到code参数之后,可以使用code参数重新向github发起请求,来获取用户的资料信息

代码目录结构

java0904@weigongdeMacBook-Pro github % tree
.
├── github
├── html
│   ├── github.jpeg
│   └── githubLogin.html
└── main.go

代码实现 main.go

package main


import (
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"io/ioutil"
	"net/http"
)

type GitHubConfig struct {
	ClientId     string
	ClientSecret string
	RedirectUrl  string
}

type TokenResponse struct {
	AccessToken string `json:"access_token"`
	Scope       string `json:"scope"`
	TokenType   string `json:"token_type"`
}

var conf = GitHubConfig{
	"xxxx",
	"xxxxxxxxxxxx",
	"http://localhost:8080/authorization",
}

func main() {

	engine := gin.Default()
	engine.LoadHTMLGlob("html/*")

	engine.GET("/", func(c *gin.Context) {

		c.HTML(200, "githubLogin.tmpl", conf)

	})
	engine.GET("authorization", func(c *gin.Context) {
		code, _ := c.GetQuery("code")
		if code != "" {
			token, err := getToken(code)
			if err != nil {
				panic(err)
			}
			info, err := getUserInfo(token.AccessToken)
			if err != nil {
				panic(err)
			}
			fmt.Println(info)
			c.String(200, info)
		} else {
			c.String(500, "nil")
		}
	})
	engine.Run(":8080")

}

func getToken(code string) (*TokenResponse, error) {
	var token TokenResponse
	client := &http.Client{}
	request, err := http.NewRequest("GET", fmt.Sprintf("https://github.com/login/oauth/access_token?client_id=%s&client_secret=%s&code=%s", conf.ClientId, conf.ClientSecret, code), nil)
	if err != nil {
		return nil, err
	}
	request.Header.Set("Accept", "application/json")
	response, err := client.Do(request)
	if err != nil {
		return nil, err
	}
	defer response.Body.Close()

	if err = json.NewDecoder(response.Body).Decode(&token); err != nil {
		return nil, err
	}
	return &token, nil
}

func getUserInfo(token string) (string, error) {
	url := "https://api.github.com/user"
	client := &http.Client{}
	request, _ := http.NewRequest("GET", url, nil)
	request.Header.Add("Authorization", "token "+token)
	request.Header.Add("Accept", "application/json")
	resp1, err := client.Do(request)
	if err != nil {
		panic(err)
	}
	defer resp1.Body.Close()
	all, err := ioutil.ReadAll(resp1.Body)
	if err != nil {
		panic(err)
	}
	return string(all), nil
}

代码githubLogin.tmpl


<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
    <title>Bootstrap 101 Template</title>
    <style>
        body {
            background-size: cover;
            font-size: 16px;
        }

        .form {
            background: rgba(255, 255, 255, 0.2);
            width: 400px;
            margin: 100px auto;
        }

        #login_form {
            display: block;
        }

        #register_form {
            display: none;
        }

        .fa {
            display: inline-block;
            top: 27px;
            left: 6px;
            position: relative;
            color: #ccc;
        }

        input[type="text"], input[type="password"] {
            padding-left: 26px;
        }


        .checkbox {
            padding-left: 21px;
        }

    </style>
    <!-- Bootstrap -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" rel="stylesheet">

    <!-- HTML5 shim 和 Respond.js 是为了让 IE8 支持 HTML5 元素和媒体查询(media queries)功能 -->
    <!-- 警告:通过 file:// 协议(就是直接将 html 页面拖拽到浏览器中)访问页面时 Respond.js 不起作用 -->
    <!--[if lt IE 9]>
    <script src="https://cdn.jsdelivr.net/npm/html5shiv@3.7.3/dist/html5shiv.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/respond.js@1.4.2/dest/respond.min.js"></script>
    <![endif]-->
</head>
<body>
<div class="container">
    <div class="form row">
        <form class="form-horizontal col-sm-offset-3 col-md-offset-3" id="login_form">
            <h3 class="form-title">Login to your account</h3>
            <div class="col-sm-9 col-md-9">
                <div class="form-group">
                    <i class="fa fa-user fa-lg"></i>
                    <input class="form-control required" type="text" placeholder="Username" name="username"
                           autofocus="autofocus" maxlength="20"/>
                </div>
                <div class="form-group">
                    <i class="fa fa-lock fa-lg"></i>
                    <input class="form-control required" type="password" placeholder="Password" name="password"
                           maxlength="8"/>
                </div>
                <div class="form-group">
                    <label class="checkbox">
                        <input type="checkbox" name="remember" value="1"/> Remember me
                    </label>
                    <hr/>
                    <a href="javascript:;" id="register_btn" class="">Create an account</a>
                </div>
                <div class="form-group">
                    <a class="btn btn-success"  href="https://github.com/login/oauth/authorize?client_id={{.ClientId}}&redirect_uri={{.RedirectUrl}}"><img width="50px" height="20px" src="html/github.jpeg">GitHub登录</a>
                    <input type="submit" class="btn btn-success pull-right" value="Login "/>
                </div>
            </div>
        </form>
    </div>

    <div class="form row">
        <form class="form-horizontal col-sm-offset-3 col-md-offset-3" id="register_form">
            <h3 class="form-title">Login to your account</h3>
            <div class="col-sm-9 col-md-9">
                <div class="form-group">
                    <i class="fa fa-user fa-lg"></i>
                    <input class="form-control required" type="text" placeholder="Username" name="username"
                           autofocus="autofocus"/>
                </div>
                <div class="form-group">
                    <i class="fa fa-lock fa-lg"></i>
                    <input class="form-control required" type="password" placeholder="Password" id="register_password"
                           name="password"/>
                </div>
                <div class="form-group">
                    <i class="fa fa-check fa-lg"></i>
                    <input class="form-control required" type="password" placeholder="Re-type Your Password"
                           name="rpassword"/>
                </div>
                <div class="form-group">
                    <i class="fa fa-envelope fa-lg"></i>
                    <input class="form-control eamil" type="text" placeholder="Email" name="email"/>
                </div>
                <div class="form-group">
                    <input type="submit" class="btn btn-success pull-right" value="Sign Up "/>
                    <input type="submit" class="btn btn-info pull-left" id="back_btn" value="Back"/>
                </div>
            </div>
        </form>
    </div>
</div>
<!--<div class="container">-->
<!--    <h1>使用第三方登录测试页面</h1>-->
<!--    <a href="https://github.com/login/oauth/authorize?client_id={{.ClientId}}&redirect_uri={{.RedirectUrl}}">使用GitHub登录</a>-->
<!--</div>-->
<!-- jQuery (Bootstrap 的所有 JavaScript 插件都依赖 jQuery,所以必须放在前边) -->
<script src="https://cdn.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js"></script>
<!-- 加载 Bootstrap 的所有 JavaScript 插件。你也可以根据需要只加载单个插件。 -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js"></script>
</body>
</html>



![image.png](https://statics.sdk.cn/articles/img/202104/794b7085d71578090466012734_1001009.png?x-oss-process=style/thumb)

go实现qq登录

目录结构

java0904@weigongdeMacBook-Pro qq % tree 
.
├── html
│   ├── bt_92X1201.png
│   └── qqLogin.tmpl
├── main.go
└── qq

代码 qqLogin.tmpl

<html>
<body>
<a href="https://graph.qq.com/oauth2.0/authorize?response_type=code&client_id={{.AppId}}&redirect_uri={{.RedirectURI}}">
<img src="html/bt_92X1201.png">
</a>
</body>
</html>

图片bt_92X1201.png

image.png

代码 main.go

package main


import (
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"io/ioutil"
	"net/http"
)

type GitHubConfig struct {
	ClientId     string
	ClientSecret string
	RedirectUrl  string
}

type TokenResponse struct {
	AccessToken string `json:"access_token"`
	Scope       string `json:"scope"`
	TokenType   string `json:"token_type"`
}

var conf = GitHubConfig{
	"86650239386200a77f85",
	"7dd8bb75fce6d8acc787f47a3bec6a755235e64d",
	"http://localhost:8080/authorization",
}

func main() {

	engine := gin.Default()
	engine.LoadHTMLGlob("html/*")
	engine.Static("/html", "/Users/java0904/goProject/loginGithub/github/html")
	engine.GET("/", func(c *gin.Context) {

		c.HTML(200, "githubLogin.html", conf)

	})
	engine.GET("authorization", func(c *gin.Context) {
		code, _ := c.GetQuery("code")
		if code != "" {
			token, err := getToken(code)
			if err != nil {
				panic(err)
			}
			info, err := getUserInfo(token.AccessToken)
			if err != nil {
				panic(err)
			}
			fmt.Println(info)
			c.String(200, info)
		} else {
			c.String(500, "nil")
		}
	})
	engine.Run(":8080")

}

func getToken(code string) (*TokenResponse, error) {
	var token TokenResponse
	client := &http.Client{}
	request, err := http.NewRequest("GET", fmt.Sprintf("https://github.com/login/oauth/access_token?client_id=%s&client_secret=%s&code=%s", conf.ClientId, conf.ClientSecret, code), nil)
	if err != nil {
		return nil, err
	}
	request.Header.Set("Accept", "application/json")
	response, err := client.Do(request)
	if err != nil {
		return nil, err
	}
	defer response.Body.Close()

	if err = json.NewDecoder(response.Body).Decode(&token); err != nil {
		return nil, err
	}
	return &token, nil
}

func getUserInfo(token string) (string, error) {
	url := "https://api.github.com/user"
	client := &http.Client{}
	request, _ := http.NewRequest("GET", url, nil)
	request.Header.Add("Authorization", "token "+token)
	request.Header.Add("Accept", "application/json")
	resp1, err := client.Do(request)
	if err != nil {
		panic(err)
	}
	defer resp1.Body.Close()
	all, err := ioutil.ReadAll(resp1.Body)
	if err != nil {
		panic(err)
	}
	return string(all), nil
}

评论区

眉上的汗水,眉下的泪水,你总要选择一样

0

0

0

举报