Go Native
- Postgresql is used.
- Imports.
import (
"database/sql"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"math/rand"
"net/http"
"strings"
"time"
"github.com/dgrijalva/jwt-go"
"github.com/gorilla/mux"
"github.com/lib/pq"
)
- Constants
const oidcAuthEndpoint = "https://tenantname.aws1.test1.com/auth/realms/{tenantname}/protocol/openid-connect/auth"
const oidcClient = "openidtestclient"
const oidcClientSecret = "0086d90a-221f-431c-ad35-741e6599bf6c"
const oidcTokenURI = "https://tenantname.aws1.test1.com/auth/realms/{tenantname}/protocol/openid-connect/token"
const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
- Used custom types
type user struct {
Email string `json:"email"`
}
type loginData struct {
Token string `json:"token"`
User user `json:"user"`
}
type oidcResponseData struct {
ClientID string `json:"client_id"`
AuthURL string `json:"auth_url"`
ComposedURL string `json:"composed_url"`
}
/auth/oidc
(GET)
func oidchandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*") // Cors için
w.Header().Set("Access-Control-Allow-Headers", "Content-Type,Cookie,Set-Cookie")
if r.Method == http.MethodOptions {
return
}
redirectURL := r.URL.Query().Get("redirect_uri") // Query param'dan redirect_uri'ı al
nonce := genNonce(8)
url := fmt.Sprintf("%s?client_id=%s&redirect_uri=%s&scope=openid&response_type=code&response_mode=query&nonce=%s", oidcAuthEndpoint, oidcClient, redirectURL, nonce)
// url oluşturulur
data := oidcResponseData{AuthURL: oidcAuthEndpoint, ClientID: oidcClient, ComposedURL: url} // response struct
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(data)
}
//Yardımcı getNonce fonksiyonu random string üretmeye yarıyor.
func genNonce(n int) string {
b := make([]byte, n)
for i := range b {
b[i] = letterBytes[rand.Intn(len(letterBytes))]
}
return string(b)
}
/auth/code
(POST)
func codehandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*") // Cors için
w.Header().Set("Access-Control-Allow-Headers", "Content-Type,Cookie,Set-Cookie")
if r.Method == http.MethodOptions {
return
}
defer r.Body.Close()
body, err := ioutil.ReadAll(r.Body)
var data map[string]string // Request bilgisi map'e alınır
json.Unmarshal([]byte(body), &data)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
// Token endpoint'ine istek parametreleri ayarlanır
url := oidcTokenURI
method := "POST"
payload := strings.NewReader(fmt.Sprintf("client_id=%s&redirect_uri=%s&grant_type=authorization_code&client_secret=%s&code=%s", oidcClient, data["redirect_uri"], oidcClientSecret, data["code"]))
client := &http.Client{}
req, err := http.NewRequest(method, url, payload)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
res, err := client.Do(req) // Post request token endpoint'ine atılır
var result map[string]string
json.Unmarshal([]byte(resBody), &result)
idToken := result["id_token"]
if idToken == "" {
http.Error(w, err.Error(), http.StatusUnauthorized)
return
}
parser := jwt.Parser{}
claims := jwt.MapClaims{}
parser.ParseUnverified(idToken, claims) // token parse edilip içeriği claim's e geliyor
var email string // Databaseden buraya kopyalamaya çalışacağız user email'ini
token := jwt.New(jwt.SigningMethodHS256) // session token'ımız oluşturulmaya başlanır
newTokenClaims := token.Claims.(jwt.MapClaims)
newTokenClaims["exp"] = time.Now().Add(time.Minute * 30).Unix()
// Bu email ile kullanıcı veri tabanında var mı diye bakılır
sqlStatement := `SELECT * FROM users WHERE email=$1;`
row := db.QueryRow(sqlStatement, claims["email"].(string))
switch err := row.Scan(&email); err { // Bu fonksiyon döndüğü değere göre işlem başarılı veya değil
case sql.ErrNoRows: // Böyle bir email ile kayıt yoksa
sqlStatement := `INSERT INTO users (email) VALUES ($1)`
_, err = db.Exec(sqlStatement, claims["email"].(string))
if err != nil {
panic(err)
}
newTokenClaims["email"] = claims["email"].(string)
email = claims["email"].(string) // response içine koymak için bunu dolduruyoruz
case nil: // başarılı şekilde email değişkenine databaseden kopyalandı
newTokenClaims["email"] = email
default: // Başka bir hata olursa
panic(err)
}
var hmacSampleSecret []byte
hmacSampleSecret = []byte("jwtsecretkey")
tokenString, err := token.SignedString(hmacSampleSecret) // Token imzalama
user := user{Email: email}
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
resData := loginData{ // response bilgisi
Token: tokenString,
User: user}
json.NewEncoder(w).Encode(resData)
}