go 第三方github登录

     阅读(78)  2019-06-08 23:41:34

给本网站加了一个第三方github登录的功能

在github上新建oauth app

  • 登录github,在用户菜单中选择Settings->Deleloper settings->OAuth Apps->New OAuth App
  • 记住Client ID,Client Secret,Authorization callback URL

点击github登录

html标签

<a href="/githublogin">github</a>

路由

router.GET("/githublogin", controller.GithubLogin)

处理登录,向github发起login请求

func GithubLogin(c *gin.Context) {
    c.Redirect(http.StatusMovedPermanently, "https://github.com/login/oauth/authorize?client_id=531ad8e4517595748d97&state=123456789")
}

此时会打开github授权登录的页面,输入用户名和密码授权登录

github登录成功后回调

上文中设置的Authorization callback URL就是回调到本网站的地址,如我的是:

http://ningto.com/github_oauth_callback_comment

给它增加路由

router.GET("/github_oauth_callback_comment", controller.GithubOAuthCallbackComment)

处理github回调后的路由

func GithubOAuthCallbackComment(c *gin.Context) {
    errmsg := ""
    for {
        // 第一步,获取github回调的code和state
        code := c.Query("code")
        state := c.Query("state")
    
        // 第二步,POST获取access token
        payload := make(map[string]interface{})
        payload["client_id"] = "531ad8e4517595xxxxxx"
        payload["client_secret"] = "bf123fc9fe25a30e3e33d7a07daf825b73xxxxxx"
        payload["code"] = code
        payload["state"] = state
        data, err := json.Marshal(payload)
        if err != nil {
            errmsg = "json marsha1 error"
            break
        }
        reader := bytes.NewReader(data)
        url := "https://github.com/login/oauth/access_token"
        request, err := http.NewRequest("POST", url, reader)
        if err != nil {
            errmsg = "http new post request error"
            break
        }
        request.Header.Set("Accept", "application/json;charset=UTF-8")
        request.Header.Set("Content-Type", "application/json;charset=UTF-8")
        client := http.Client{}
        rsp, err := client.Do(request)
        if err != nil {
            errmsg = "client do request error"
            break
        }
        var jsonAccessToken AccessTokenResponse
        err = json.NewDecoder(rsp.Body).Decode(&jsonAccessToken)
        if err != nil {
            errmsg = "json decoder access token response error"
            break
        }
        token := jsonAccessToken.AccessToken
    
        // 第三步,使用access token获取用户基本信息
        url = "https://api.github.com/user?access_token=" + token
        rsp, err = http.Get(url)
        if err != nil {
            errmsg = "http get access token error"
            break
        }
    
        var jsonLogin GithubLoginResponse
        err = json.NewDecoder(rsp.Body).Decode(&jsonLogin)
        if err != nil {
            errmsg = "json decode error"
            break
        }
    
        // 第四步,判断数据库中是否已存在此用户
        user, err := model.GetUser("github", jsonLogin.Login)
        if err != nil {
            newUser := model.User {
                Id: bson.NewObjectId(),
                Provider: "github",
                Login: jsonLogin.Login,
                Password: "",
                Token: token,
            }
            model.InsertUser(newUser)
        } else {
            model.UpdateUserToken(user, token)
        }
    
        // 第五步,将token保存在session中,浏览器端会将token加密后放在cookie中,
        // 当前用户再次进行http请求时判断浏览器传过来的token是否在session中,
        // 如果存在表示已登录
        session := sessions.Default(c)
        session.Set("token", token)
        if session.Save() != nil {
            errmsg = "session save token failed"
        }
        break
    }

    // 完成
    if len(errmsg) > 0 {
        c.HTML(http.StatusOK, "login.tmpl", gin.H{
            "errmsg": errmsg,
        })
    } else {
        c.Redirect(http.StatusFound, "/")
    }
}

下面定义的两个结构体是github返回的json应答,由于我只需要用到部分数据,所以没有全部定义

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

    GithubLoginResponse struct {
        Login string `json:"login"`
        Id int `json:"id"`
        AvatarUrl string `json:"avatar_url"`
    }
)

文章评论

Keep it simple,stupid
文章数
290
总访问量
305750
今日访问
393
最近评论

xuehaoyun : 很不错,来围观一下
tujiaw : 抱歉csdn code服务关闭了,这个代码我也找不到了
于淞 : 你好,这个文章的源码能分享一下吗,songsong9181@163.com,谢谢了 上面的写错了
于淞 : 你好,这个文章的源码能分享一下吗,838106303@163.com,谢谢了 上面的链接不能用了
tujiaw : 多谢多谢
essaypinglun college-paper.org : 很好的博客,赞赞
Folly : 这个实现有点奇怪,Qt为什么没有统一的比对方法。
过多s : alert("hello, world!")
tujiaw : 还不错哦
回到顶部