前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >从0开始构建一个Oauth2Server服务 <2> 访问 OAuth 服务器中的数据

从0开始构建一个Oauth2Server服务 <2> 访问 OAuth 服务器中的数据

作者头像
用户1418987
发布2023-10-16 09:26:31
1230
发布2023-10-16 09:26:31
举报
文章被收录于专栏:codercoder
从0开始构建一个Oauth2Server服务 <2> 访问 OAuth 服务器中的数据_应用程序
从0开始构建一个Oauth2Server服务 <2> 访问 OAuth 服务器中的数据_应用程序

本节中我们将介绍如何在现有的 OAuth 2.0 服务器上访问您的数据。对于此示例,我们将使用 GitHub API 并构建一个简单的应用程序,该应用程序将列出登录用户创建的所有存储库。

创建一个应用程序

在我们开始之前, 我们需要在github上面创建一个Application, 获取到ClientID 和Secret

在github上面找到设置页面, 点击Developer Settings, 会打开网页 https://github.com/settings/developers , 在这儿我们点击 New OAuth App您将看到一个简短的表格,如下所示

填写必填信息,包括回调 URL。如果您在本地开发应用程序,则必须使用本地地址作为回调 URL。由于 GitHub 只允许每个应用程序注册一个回调 URL,因此创建两个应用程序很有用,一个用于开发,另一个用于生产。

从0开始构建一个Oauth2Server服务 <2> 访问 OAuth 服务器中的数据_应用程序_02
从0开始构建一个Oauth2Server服务 <2> 访问 OAuth 服务器中的数据_应用程序_02

完成此表格后,您将被带到一个页面,您可以在其中查看颁发给您的应用程序的客户端 ID 和密码,如下所示。

客户端 ID 被视为公共信息,用于构建授权 URL,或者可以包含在网页的 JavaScript 源代码中。客户端机密必须保密。不要将其提交到您的 git 存储库或将其包含在任何 JavaScript 文件中!

从0开始构建一个Oauth2Server服务 <2> 访问 OAuth 服务器中的数据_golang_03
从0开始构建一个Oauth2Server服务 <2> 访问 OAuth 服务器中的数据_golang_03

环境配置

此示例代码是用 Golang 编写的,不需要外部包,也不需要框架。希望这可以在需要时轻松翻译成其他语言。要跟随此示例代码,您可以将其全部放在一个 main.go 文件中。

创建一个新文件夹并在该文件夹中创建一个名为main.go. 在命令行中,go run main.go从该文件夹内运行,您将能够在浏览器中访问http://localhost:8080以运行您的代码。以下示例中的所有代码都应添加到此main.go文件中。

首先我们需要定义几个变量

代码语言:javascript
复制
var (
	clientID    = "567bcc7f346c8ce22e1893cee0f43a3a" // 修改为自己的 clientID
	secret      = "a4a2d532e29a262a8fc67bc5e4db01be" // 修改为自己的 clientID
	serverURL   = "https://github.com/login/oauth/authorize" // github server url
	redirectURL = "http://127.0.0.1:8080/oauth/callback" // 本地服务地址
	scope       = "user read:user" // 定义授权的范围
	state       = "" 
)

定义主函数main

代码语言:javascript
复制
func main() {
	http.HandleFunc("/", handler)
	http.ListenAndServe(":8080", nil)
}

http.HandleFunc("/", handler) 主要作用是浏览器打开http://localhost:8080 后回执行handler 函数

我们定义 handler 函数的实现
代码语言:javascript
复制
func handler(w http.ResponseWriter, r *http.Request) {
	githubClient := oauth.NewOauth2Client(serverURL, clientID, oauth.WithRedirectURI(redirectURL), oauth.WithState(state), oauth.WithScope(scope))
	authURL, err := githubClient.AuthorizeURL()
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		w.Write([]byte(err.Error()))
		return
	}
	http.Redirect(w, r, authURL, http.StatusFound)
	return
}

这个函数首先需要实例化一个client ,并传入参数

  • serverURL: github服务地址
  • clientID: github 创建应用的clientID
  • oauth.WithRedirectURI(redirectURL) 配置回调地址, github授权成功后会携带code参数回调 http://localhost:8080/callback?code=xxxx
  • oauth.WithState(state) 配置state参数,statestate参数将与我们在初始授权请求中设置的参数相同,用于我们的应用程序在继续之前检查它是否匹配。这有助于我们的应用程序避免被诱骗将授权代码发送到 GitHub,并防止 CSRF Attack。
  • oauth.WithScope(scope) 配置授权范围. 具体作用可参考我前面的文章介绍

执行 go run main.go 启动服务, 打开浏览器 http://localhost:8080, 浏览器会执行函数 handler 函数, 并将地址重定向到 https://github.com/login/oauth/authorize 地址, 授权成功后浏览器跳转到我们本地地址并携带code参数 http://localhost:8080/callback?code=xxx,

现在我们需要给callback的路由设置一个处理函数, 那就是需要在main 函数中添加回调执行代码

代码语言:javascript
复制
func main() {
	http.HandleFunc("/", handler)
	http.HandleFunc("/oauth/callback", callback)

	http.ListenAndServe(":8080", nil)
}
定义callback回调执行函数
代码语言:javascript
复制
func callback(w http.ResponseWriter, r *http.Request) {
	var serverURL = "https://github.com/login/oauth/access_token"
	u, _ := url.ParseRequestURI(r.RequestURI)
	var code = u.Query().Get("code")
	log.Println("code = ", code)
	// get access token by code
	accessToken := oauth.NewAccessToken(serverURL, clientID, secret, code, oauth.AccessTokenWithContentType("application/json"))
	data, err := accessToken.DoRequest()
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		w.Write([]byte(err.Error()))
		return
	}
	getUserinfo(w, string(data))
}

这段代码接受到code参数, 并实例化 oauth.NewAccessToken()

参数说明:

  • serverURL: 获取github Access Token的服务器地址
  • clientID: github分配的ClientID
  • secret: github分配的Secret
  • code: 第一步query参数重获取到的code值, 这个是必须的
  • oauth.AccessTokenWithContentType("application/json"): 配置响应的数据格式

如果一切正常,GitHub 会生成一个访问令牌并在响应中返回它。我们将访问令牌存储在会话中并重定向到主页,用户已登录。

GitHub 的响应如下所示。

代码语言:javascript
复制
{
  "access_token": "e2f8c8e136c73b1e909bb1021b3b4c29",
  "token_type": "Bearer",
  "scope": "public_repo,user"
}

请求到accessToken后就可以执行 getUserinfo 获取github授权的用户信息

我们再来实现函数 getUserinfo
代码语言:javascript
复制
func getUserinfo(w http.ResponseWriter, requestURI string) {
	values, _ := url.ParseQuery(requestURI)
	var accessToken = values.Get("access_token")
	var serverURL = "https://api.github.com/user"
	user := oauth.NewUserInfo(serverURL, accessToken)
	data, err := user.DoRequest()
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		w.Write([]byte(err.Error()))
		return
	}
	w.Write(data)
}

这个函数我们获取到Github重返回的access_token

实例化 oauth.NewUserInfo(serverURL, accessToken) 这个函数需要两个参数

data 就是我们获取到的数据, 在本代码中就是一个 response.Body []byte类型数据

要想代码正常运行需要在文件顶部导入包:

代码语言:javascript
复制
import (
	"log"
	"net/http"
	"net/url"

	"github.com/demo007x/oauth2-client/oauth"
)

代码中用到的包地址 github.com/demo007x/oauth2-client/oauth

完整代码:
代码语言:javascript
复制
package main

import (
	"log"
	"net/http"
	"net/url"

	"github.com/demo007x/oauth2-client/oauth"
)

// This Is GitHub.com Oauth Restfull Demo

var (
	clientID    = "567bcc7f346c8ce22e1893cee0f43a3a" // change youself clientID
	secret      = "a4a2d532e29a262a8fc67bc5e4db01be"
	serverURL   = "https://github.com/login/oauth/authorize"
	redirectURL = "http://127.0.0.1:8080/oauth/callback"
	scope       = "user read:user"
	state       = "xxxx"
)

func handler(w http.ResponseWriter, r *http.Request) {
	githubClient := oauth.NewOauth2Client(serverURL, clientID, oauth.WithRedirectURI(redirectURL), oauth.WithState(state), oauth.WithScope(scope))
	authURL, err := githubClient.AuthorizeURL()
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		w.Write([]byte(err.Error()))
		return
	}
	http.Redirect(w, r, authURL, http.StatusFound)
	return
}

func callback(w http.ResponseWriter, r *http.Request) {
	var serverURL = "https://github.com/login/oauth/access_token"
	u, _ := url.ParseRequestURI(r.RequestURI)
	var code = u.Query().Get("code")
	log.Println("code = ", code)
	// get access token by code
	accessToken := oauth.NewAccessToken(serverURL, clientID, secret, code, oauth.AccessTokenWithContentType("application/json"))
	data, err := accessToken.DoRequest()
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		w.Write([]byte(err.Error()))
		return
	}
	getUserinfo(w, string(data))
}

func getUserinfo(w http.ResponseWriter, requestURI string) {
	values, _ := url.ParseQuery(requestURI)
	var accessToken = values.Get("access_token")
	var serverURL = "https://api.github.com/user"
	user := oauth.NewUserInfo(serverURL, accessToken)
	data, err := user.DoRequest()
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		w.Write([]byte(err.Error()))
		return
	}
	w.Write(data)
}

func main() {
	http.HandleFunc("/", handler)
	http.HandleFunc("/oauth/callback", callback)

	http.ListenAndServe(":8080", nil)
}

详细代码可以访问 demo007x/oauth2-client: Oauth2 Client package for Golang (github.com) 查看

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-04-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 创建一个应用程序
  • 环境配置
    • 我们定义 handler 函数的实现
      • 定义callback回调执行函数
        • 我们再来实现函数 getUserinfo
          • 完整代码:
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档