Github Oauth2

首先,在github上申请一个Oauth App, 获取client id / secret

需要这些信息,下边的代码是放在环境变量中

    AUTH_URL      = os.Getenv("AUTH_URL") // github authorization url
    TOKEN_URL     = os.Getenv("TOKEN_URL") // github token url
    CLIENT_ID     = os.Getenv("CLIENT_ID") // client id
    CLIENT_SECRET = os.Getenv("CLIENT_SECRET") // client secret
    REDIRECT_URL  = os.Getenv("REDIRECT_URL") // the redirect url

在包的初始化代码中,初始化

  var (
    oauth2Config *oauth2.Config
  )

  init() {
    oauth2Config = &oauth2.Config{
    ClientID:     CLIENT_ID,
    ClientSecret: CLIENT_SECRET,
    RedirectURL:  REDIRECT_URL,

    // Discovery returns the OAuth2 endpoints.
    Endpoint: oauth2.Endpoint{
            AuthURL:   AUTH_URL,
            TokenURL:  TOKEN_URL,
            AuthStyle: oauth2.AuthStyleInHeader,
    },

    Scopes: []string{"openid", "email", "site_admin", "repo", "admin:org", "user"},
  }

Login handler

  func HandleRedirect(w http.ResponseWriter, r *http.Request) {
    //you need to generate random state here
  http.Redirect(w, r, oauth2Config.AuthCodeURL(state), http.StatusFound)
  }

callback handler

  func HandleOAuth2Callback(w http.ResponseWriter, r *http.Request) {
        log.Printf("Processing response")
        state := r.URL.Query().Get("state")
        target, ok := stateMap[state]
        if !ok {
                http.Error(w, "missing target in request", http.StatusBadRequest)
        }

        // remove from map
        // delete(stateMap, state)

        log.Printf("in HandleOAuth2Callback, target url : %s", target)

        user, err := getUserInfo(r.FormValue("code"))

        // create the user if not found

        tNow := time.Now()
           claims := jwt.StandardClaims{
                Issuer:    "CCMS Application",
                Subject:   user,
                IssuedAt:  tNow.Unix(),
                ExpiresAt: tNow.Add(2 * time.Hour).Unix(), // two hours
        }
        token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
        ss, err := token.SignedString(jwtKey)
        if err != nil {
                http.Error(w, "Failed to sign the token : "+err.Error(), http.StatusInternalServerError)
                return
        }
        rUrl := fmt.Sprintf("%s?token=%s", target, ss)
        log.Printf("redirect to :%s", rUrl)
        http.Redirect(w, r, rUrl, http.StatusFound)

the function to exchange code to get access token

  func getUserInfo(code string) (string, error) {
        token, err := oauth2Config.Exchange(oauth2.NoContext, code)
        if err != nil {
                return "", fmt.Errorf("code exchange failed: %s", err.Error())
        }
        ctx := context.Background()
        log.Printf("access token: %+v", token)
        // token.AccessToken --- this is the token you can use to call github api
        return email, nil
  }