![](/contact/xiaochengxu.jpg)
![](/contact/xiaohongshu.jpg)
从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,因此创建两个应用程序很有用,一个用于开发,另一个用于生产。
完成此表格后,您将被带到一个页面,您可以在其中查看颁发给您的应用程序的客户端 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 函数
我们定义 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 ,并传入参数
-
serverURL: github服务地址
-
clientID: github 创建应用的clientID
-
oauth.WithRedirectURI(redirectURL) 配置回调地址, github授权成功后会携带code参数回调 http://localhost:8080/callback?code=xxxx
-
oauth.WithState(state) 配置state参数,
state
该state
参数将与我们在初始授权请求中设置的参数相同,用于我们的应用程序在继续之前检查它是否匹配。这有助于我们的应用程序避免被诱骗将攻击者的授权代码发送到 GitHub,并防止 CSRF 攻击。 -
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 函数中添加回调执行代码
func main() {
http.HandleFunc("/", handler)
http.HandleFunc("/oauth/callback", callback)
http.ListenAndServe(":8080", nil)
}
定义callback回调执行函数
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 的响应如下所示。
{
"access_token": "e2f8c8e136c73b1e909bb1021b3b4c29",
"token_type": "Bearer",
"scope": "public_repo,user"
}
请求到accessToken后就可以执行 getUserinfo 获取github授权的用户信息
我们再来实现函数 getUserinfo
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) 这个函数需要两个参数
- serverURL:获取用户数据的服务地址 https://api.github.com/user
- 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)
}
详细代码可以访问 github.com/demo007x/oauth2-client/oauth 查看
类似的帖子
![](/contact/xiaochengxu.jpg)
![](/contact/xiaohongshu.jpg)