這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
生命不止,繼續 go go go!!!
今天繼續分享golang中的認證問題,之前寫過兩篇:
一篇是關於basic認證:Go實戰–通過basic認證的http(basic authentication)
一篇是關於JWT的:Go實戰–golang中使用JWT(JSON Web Token)
這裡就介紹一下golang中使用oauth2.0.
OAuth2.0
OAuth2.0是OAuth協議的下一版本,但不向後相容OAuth 1.0即完全廢止了OAuth1.0。 OAuth 2.0關注用戶端開發人員的簡易性。要麼通過組織在資源擁有者和HTTP服務商之間的被獲批准的互動動作代表使用者,要麼允許第三方應用代表使用者獲得訪問的許可權。同時為Web應用,案頭應用和手機,和起居室裝置提供專門的認證流程。2012年10月,OAuth 2.0協議正式發布為RFC 6749.
在認證和授權的過程中涉及的三方包括:
1、服務提供者,使用者使用服務提供者來儲存受保護的資源,如照片,視頻,連絡人清單。
2、使用者,存放在服務提供者的受保護的資源的擁有者。
3、用戶端,要訪問服務提供者資源的第三方應用,通常是網站,如提供照片列印服務的網站。在認證過程之前,用戶端要向服務提供者申請用戶端標識。
使用OAuth進行認證和授權的過程如下所示:
(A)使用者開啟用戶端以後,用戶端要求使用者給予授權。
(B)使用者同意給予用戶端授權。
(C)用戶端使用上一步獲得的授權,向證明伺服器申請令牌。
(D)證明伺服器對用戶端進行認證以後,確認無誤,同意發放令牌。
(E)用戶端使用令牌,向資原始伺服器申請擷取資源。
(F)資原始伺服器確認令牌無誤,同意向用戶端開放資源
更詳細的內容,可以參考:http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html
package oauth2
Package oauth2 provides support for making OAuth2 authorized and authenticated HTTP requests. It can additionally grant authorization with Bearer JWT.
擷取:
go get golang.org/x/oauth2
type Config
type Config struct { // ClientID is the application's ID. ClientID string // ClientSecret is the application's secret. ClientSecret string // Endpoint contains the resource server's token endpoint // URLs. These are constants specific to each server and are // often available via site-specific packages, such as // google.Endpoint or github.Endpoint. Endpoint Endpoint // RedirectURL is the URL to redirect users going through // the OAuth flow, after the resource owner's URLs. RedirectURL string // Scope specifies optional requested permissions. Scopes []string}
func (*Config) AuthCodeURL
func (c *Config) AuthCodeURL(state string, opts ...AuthCodeOption) string
AuthCodeURL returns a URL to OAuth 2.0 provider’s consent page that asks for permissions for the required scopes explicitly.
func (*Config) Exchange
func (c *Config) Exchange(ctx context.Context, code string) (*Token, error)
Exchange converts an authorization code into a token.
type Endpoint
type Endpoint struct { AuthURL string TokenURL string}
Endpoint contains the OAuth 2.0 provider’s authorization and token endpoint URLs.
使用google帳號進行登陸驗證
1.去Google Cloud Platform,建立一個項目
2.憑據,建立憑據,選擇OAuth用戶端ID
3.
選擇應用類型為”網頁應用”
輸入JavaScript來源:http://localhost:8000
輸入已獲授權的重新導向URI:http://localhost:8000/GoogleCallback
4.記錄下用戶端ID和用戶端密鑰
編碼
package mainimport ( "fmt" "io/ioutil" "net/http" "golang.org/x/oauth2")const htmlIndex = `<html><body><a href="/GoogleLogin">Log in with Google</a></body></html>`var endpotin = oauth2.Endpoint{ AuthURL: "https://accounts.google.com/o/oauth2/auth", TokenURL: "https://accounts.google.com/o/oauth2/token",}var googleOauthConfig = &oauth2.Config{ ClientID: "your_client_id", ClientSecret: "your_client_secret", RedirectURL: "http://localhost:8000/GoogleCallback", Scopes: []string{"https://www.googleapis.com/auth/userinfo.profile", "https://www.googleapis.com/auth/userinfo.email"}, Endpoint: endpotin,}const oauthStateString = "random"func main() { http.HandleFunc("/", handleMain) http.HandleFunc("/GoogleLogin", handleGoogleLogin) http.HandleFunc("/GoogleCallback", handleGoogleCallback) fmt.Println(http.ListenAndServe(":8000", nil))}func handleMain(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, htmlIndex)}func handleGoogleLogin(w http.ResponseWriter, r *http.Request) { url := googleOauthConfig.AuthCodeURL(oauthStateString) fmt.Println(url) http.Redirect(w, r, url, http.StatusTemporaryRedirect)}func handleGoogleCallback(w http.ResponseWriter, r *http.Request) { state := r.FormValue("state") if state != oauthStateString { fmt.Printf("invalid oauth state, expected '%s', got '%s'\n", oauthStateString, state) http.Redirect(w, r, "/", http.StatusTemporaryRedirect) return } fmt.Println(state) code := r.FormValue("code") fmt.Println(code) token, err := googleOauthConfig.Exchange(oauth2.NoContext, code) fmt.Println(token) if err != nil { fmt.Println("Code exchange failed with '%s'\n", err) http.Redirect(w, r, "/", http.StatusTemporaryRedirect) return } response, err := http.Get("https://www.googleapis.com/oauth2/v2/userinfo?access_token=" + token.AccessToken) defer response.Body.Close() contents, err := ioutil.ReadAll(response.Body) fmt.Fprintf(w, "Content: %s\n", contents)}
把ClientID和ClientSecret換成你自己的!!!
瀏覽器訪問:http://localhost:8000
點擊Log in with Google
結果:
Content: { "id": "114512230444013345330", "email": "wangshubo1989@126.com", "verified_email": true, "name": "王書博", "given_name": "書博", "family_name": "王", "picture": "https://lh3.googleusercontent.com/-XdUIqdMkCWA/AAAAAAAAAAI/AAAAAAAAAAA/4252rscbv5M/photo.jpg", "locale": "zh-CN"}