注册
在https://github.com/settings/applications/new 注册一个应用,获取clientId 和 client secrets
通过github进行授权
前段页面 访问:
<a href="https://github.com/login/oauth/authorize?client_id=e511f4733c56d5487d5d&redirect_uri=http://localhost:8087/oauth/redirect"> Login by GitHub </a>
跳转到github的授权页面 确认授权,回调/oauth/redirect 通过传递参数code
(注意 href 的 redirect_uri 必须是在github上配置的 callback URL 匹配,否则调用callback URL的时候不会传递code,提示错误。
关于redirect_uri ,这个redirect_uri 作为参数传递给githhub服务,github 会调用这个redirect_uri
redirect_uri 必须是和application上配置Authorization callback URL 一样活着是它的子域名下。详见:https://docs.github.com/en/developers/apps/building-oauth-apps/authorizing-oauth-apps#redirect-urls)
正常:
错误:
错误信息:/oauth/redirect?error=redirect_uri_mismatch&error_description=The+redirect_uri+MUST+match+the+registered+callback+URL+for+this+application.&error_uri=https%3A%2F%2Fdocs.github.com%2Fapps%2Fmanaging-oauth-apps%2Ftroubleshooting-authorization-request-errors%2F%23redirect-uri-mismatch
回调服务器端接口
服务器端拿到这个code之后调用接口https://github.com/login/oauth/access_token?" +
"client_id=%s&client_secret=%s&code=%s 获取accessToken。然后重定向到某个页面
w.Header().Set("Location", "/hello.html?access_token="+t.AccessToken) 讲token带上。
http.HandleFunc("/oauth/redirect", func(w http.ResponseWriter, r *http.Request) {
err := r.ParseForm()
if err != nil {
fmt.Fprintf(os.Stdout, "could not parse query: %v", err)
w.WriteHeader(http.StatusBadRequest)
}
code := r.FormValue("code")
reqURL := fmt.Sprintf("https://github.com/login/oauth/access_token?" +
"client_id=%s&client_secret=%s&code=%s", clientID, clientSecret, code)
req, err := http.NewRequest(http.MethodPost, reqURL, nil)
if err != nil {
fmt.Fprintf(os.Stdout, "could not create HTTP request: %v", err)
w.WriteHeader(http.StatusBadRequest)
}
req.Header.Set("accept", "application/json")
res, err := httpClient.Do(req)
if err != nil {
fmt.Fprintf(os.Stdout, "could not send HTTP request: %v", err)
w.WriteHeader(http.StatusInternalServerError)
}
defer res.Body.Close()
var t AccessTokenResponse
if err := json.NewDecoder(res.Body).Decode(&t); err != nil {
fmt.Fprintf(os.Stdout, "could not parse JSON response: %v", err)
w.WriteHeader(http.StatusBadRequest)
}
w.Header().Set("Location", "/hello.html?access_token="+t.AccessToken)
w.WriteHeader(http.StatusFound)
})
拿到这个token之后,就可以调用github的用户信息接口:
页面上调用
// 获取access_token
const token = getQueryVariable("access_token");
// 调用用户信息接口
fetch('https://api.github.com/user', {
headers: {
Authorization: 'token ' + token
}
})
// 解析请求的JSON
.then(res => res.json())
.then(res => {
// 返回用户信息
const nameNode = document.createTextNode(`Hi, ${res.login}, Welcome to login our site by GitHub!`)
document.body.appendChild(nameNode)
})
restclient 调用打印结果
返回json格式的数据
{
"login": "xiaojianlee",
"id": 12822795,
"node_id": "MDQ6VXNlcjEyODIyNzk1",
"avatar_url": "https://avatars.githubusercontent.com/u/12822795?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/xiaojianlee",
"html_url": "https://github.com/xiaojianlee",
"followers_url": "https://api.github.com/users/xiaojianlee/followers",
"following_url": "https://api.github.com/users/xiaojianlee/following{/other_user}",
"gists_url": "https://api.github.com/users/xiaojianlee/gists{/gist_id}",
"starred_url": "https://api.github.com/users/xiaojianlee/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/xiaojianlee/subscriptions",
"organizations_url": "https://api.github.com/users/xiaojianlee/orgs",
"repos_url": "https://api.github.com/users/xiaojianlee/repos",
"events_url": "https://api.github.com/users/xiaojianlee/events{/privacy}",
"received_events_url": "https://api.github.com/users/xiaojianlee/received_events",
"type": "User",
"site_admin": false,
"name": null,
"company": null,
"blog": "",
"location": null,
"email": null,
"hireable": null,
"bio": null,
"twitter_username": null,
"public_repos": 7,
"public_gists": 0,
"followers": 0,
"following": 0,
"created_at": "2015-06-10T02:00:52Z",
"updated_at": "2021-06-29T13:39:15Z"
}