OAuth2.0在golang下的使用
一、簡介
1、OAuth2.0使用https來做安全保護,避免了OAuth1.0的複雜加密,讓開發人員更容易使用。
2、接入的四種模式,一般採用授權碼模式,比較安全,其次是密碼模式,不建議使用,其他2種更不推薦。
二、接入流程
- 1、客戶端可以是手機app,也可以是web瀏覽器,開始請求自己的服務端。
- 2、服務端發現沒有登陸,則重定向跳轉到認證服務器。
- 3、認證服務器展示授權頁面,等待用戶手動確認授權。
- 4、用戶點擊確認後,授權頁面請求認證服務器,獲取授權碼
- 5、客戶端獲取上一步返回的授權碼。
- 6、客戶端將授權碼上報給自己的服務端。
- 7、服務端拿着授權碼去認證服務器換取access_token。
- 8、服務端通過access_token去認證服務器獲取用戶資料,如openid,用戶暱稱,性別等信息。
三、使用golang開發oauth2服務端
1、導入fasthttp版本的oauth2三方工具包
go get -u github.com/wyanlord/oauth2
2、先看一個示例代碼
package main
import (
"github.com/dgrijalva/jwt-go"
"github.com/wyanlord/oauth2/generates"
"github.com/wyanlord/oauth2/server"
"github.com/wyanlord/oauth2/store"
"github.com/wyanlord/oauth2/manage"
"github.com/wyanlord/oauth2/errors"
"github.com/wyanlord/oauth2/models"
"github.com/valyala/fasthttp"
"log"
)
func main() {
manager := manage.NewDefaultManager()
manager.SetAuthorizeCodeTokenCfg(manage.DefaultAuthorizeCodeTokenCfg)
// token store
manager.MustTokenStorage(store.NewMemoryTokenStore())
// generate jwt access token
manager.MapAccessGenerate(generates.NewJWTAccessGenerate([]byte("00000000"), jwt.SigningMethodHS512))
clientStore := store.NewClientStore()
_ = clientStore.Set("222222", &models.Client{
ID: "222222",
Secret: "22222222",
Domain: "http://localhost:9094",
})
manager.MapClientStorage(clientStore)
srv := server.NewServer(server.NewConfig(), manager)
srv.SetClientInfoHandler(server.ClientFormHandler)
srv.SetPasswordAuthorizationHandler(func(username, password string) (userID string, err error) {
if username == "test" && password == "test" {
return "123456", nil
}
return "", errors.ErrAccessDenied
})
srv.SetUserAuthorizationHandler(func(ctx *fasthttp.RequestCtx) (userID string, err error) {
// 根據您的項目登錄權限的方式來判斷用戶的身份,獲取用戶的id
return "123456", nil
})
srv.SetInternalErrorHandler(func(err error) (re *errors.Response) {
log.Println("Internal Error:", err.Error())
return
})
srv.SetResponseErrorHandler(func(re *errors.Response) {
log.Println("Response Error:", re.Error.Error())
})
h := fasthttp.CompressHandler(func(ctx *fasthttp.RequestCtx) {
switch string(ctx.Path()) {
case "/authorize":
err := srv.HandleAuthorizeRequest(ctx)
if err != nil {
ctx.SetStatusCode(fasthttp.StatusBadRequest)
_, _ = ctx.WriteString(err.Error())
}
case "/token":
_ = srv.HandleTokenRequest(ctx)
default:
ctx.SetStatusCode(fasthttp.StatusNotFound)
}
})
log.Fatal(fasthttp.ListenAndServe(":9096", h))
}
3、示例代碼講解
- 創建一個默認的管理器manage,用來管理授權碼code和access_token的創建方式和存取方式,以及client_id和client_secret的存取方式。
- 臨時創建了一個client_id爲222222,client_secret爲22222222,跳轉地址爲http://localhost:9094的三方應用。
- 設置三方應用上報client_id和client_secret的方式,是通過basic auth方式還是url參數方式。
- 設置獲取用戶ID的方式。
- 定義了2個函數,/authorize用來獲取授權碼, /token用來交換access_token。
4、請求示例
- 獲取授權碼的地址:
http://localhost:9096/authorize?client_id=222222&redirect_uri=http%3A%2F%2Flocalhost%3A9094&response_type=code
- 請在上述的請求頭或者路由裏帶上認證服務器信任的用戶登錄憑證,因爲用戶必須是登錄狀態,才能去認證服務器獲取到攜帶用戶ID的授權碼。
- 交換access_token的地址:
http://localhost:9096/token?client_id=222222&client_secret=22222222&grant_type=authorization_code&redirect_uri=http%3A%2F%2Flocalhost%3A9094&code=SDUF7-HFNXON8V809VVMZW
- 最終獲取的access_token格式如下:
{
"access_token": "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiIyMjIyMjIiLCJleHAiOjE1NzQ1MzA5OTIsInN1YiI6IjEyMzQ1NiJ9.CTwRImAbgIi82_hrfrhLRzkyzepxtTm-NrI9FaiiOUOFLbey2YYXMywMjPQS6KyTckhOIvctQAdeH48rsJ9HPg",
"expires_in": 7200,
"refresh_token": "JUBVTTJQX5S4SEF2LFASHQ",
"token_type": "Bearer"
}