本节中我们将介绍如何在现有的 OAuth 2.0 服务器上访问您的数据。对于此示例,我们将使用 GitHub API 并构建一个简单的应用程序,该应用程序将列出登录用户创建的所有存储库。
在我们开始之前, 我们需要在github上面创建一个Application, 获取到ClientID 和Secret
在github上面找到设置页面, 点击Developer Settings, 会打开网页 https://github.com/settings/developers , 在这儿我们点击 New OAuth App
您将看到一个简短的表格,如下所示
填写必填信息,包括回调 URL。如果您在本地开发应用程序,则必须使用本地地址作为回调 URL。由于 GitHub 只允许每个应用程序注册一个回调 URL,因此创建两个应用程序很有用,一个用于开发,另一个用于生产。
完成此表格后,您将被带到一个页面,您可以在其中查看颁发给您的应用程序的客户端 ID 和密码,如下所示。
客户端 ID 被视为公共信息,用于构建授权 URL,或者可以包含在网页的 JavaScript 源代码中。客户端机密必须保密。不要将其提交到您的 git 存储库或将其包含在任何 JavaScript 文件中!
此示例代码是用 Golang 编写的,不需要外部包,也不需要框架。希望这可以在需要时轻松翻译成其他语言。要跟随此示例代码,您可以将其全部放在一个 main.go 文件中。
创建一个新文件夹并在该文件夹中创建一个名为main.go
. 在命令行中,go run main.go
从该文件夹内运行,您将能够在浏览器中访问http://localhost:8080以运行您的代码。以下示例中的所有代码都应添加到此main.go
文件中。
首先我们需要定义几个变量
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
func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}
http.HandleFunc("/", handler) 主要作用是浏览器打开http://localhost:8080 后回执行handler 函数
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 ,并传入参数
state
该state
参数将与我们在初始授权请求中设置的参数相同,用于我们的应用程序在继续之前检查它是否匹配。这有助于我们的应用程序避免被诱骗将授权代码发送到 GitHub,并防止 CSRF Attack。执行 go run main.go 启动服务, 打开浏览器 http://localhost:8080, 浏览器会执行函数 handler 函数, 并将地址重定向到 https://github.com/login/oauth/authorize 地址, 授权成功后浏览器跳转到我们本地地址并携带code参数 http://localhost:8080/callback?code=xxx,
现在我们需要给callback的路由设置一个处理函数, 那就是需要在main 函数中添加回调执行代码
func main() {
http.HandleFunc("/", handler)
http.HandleFunc("/oauth/callback", callback)
http.ListenAndServe(":8080", nil)
}
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()
参数说明:
如果一切正常,GitHub 会生成一个访问令牌并在响应中返回它。我们将访问令牌存储在会话中并重定向到主页,用户已登录。
GitHub 的响应如下所示。
{
"access_token": "e2f8c8e136c73b1e909bb1021b3b4c29",
"token_type": "Bearer",
"scope": "public_repo,user"
}
请求到accessToken后就可以执行 getUserinfo 获取github授权的用户信息
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类型数据
要想代码正常运行需要在文件顶部导入包:
import (
"log"
"net/http"
"net/url"
"github.com/demo007x/oauth2-client/oauth"
)
代码中用到的包地址 github.com/demo007x/oauth2-client/oauth
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) 查看