Kullanıcılar Go'da kimlik doğrulamayı nasıl yönetiyor? [kapalı]


187

Go'da RESTful API'leri ve JS ön uç uygulamaları geliştirenler için kimlik doğrulamayı nasıl yönetiyorsunuz? Belirli bir kütüphane veya teknik kullanıyor musunuz?

Bununla ilgili çok az tartışma bulduğuma şaşırdım. Aşağıdaki gibi cevapları aklımda tutuyorum ve kendi uygulamamı geliştirmekten kaçınmaya çalışıyorum:

ASP.Net'te Kimlik Doğrulama Formu

Herkes kendi çözümünü ayrı ayrı kodluyor mu?


5
Kimlik doğrulaması, büyük ölçüde takip ettiğiniz uygulamanın türüne bağlıdır. Herkese uyan tek bir çözüm yoktur. Ayrıca, çözülmesi zor bir sorundur. Bu nedenle kesin bir belge bulamazsınız.
jimt

21
Hey, hızlı yanıt için teşekkürler. Anlaşıldı, ancak çoğu dil ve çerçeve, uygulamaların çoğunluğu tarafından paylaşılan en yaygın kimlik doğrulama gereksinimlerini kapsayan ve geniş topluluk katılımı ve desteğine sahip kimlik doğrulama çözümleri ile geldi. Bunun zor bir sorun olduğuna katılıyorum. Bunlar işbirlikçi çabadan en fazla yararı görmez mi? (Bu bir şikayet değil, çünkü bu açık kaynak, ama hepimizin tekerleği yeniden icat ettiğine dair bir gözlem. :)
SexxLuthor

13
@jimt Zor bir problem olması, ölümlüleri yanlış yapamayacağımız kononik bir çözümle bize sağlamayı daha da önemli hale getiriyor.
timtam

Bu soruyu konu dışı olarak kapatmak için oy kullanıyorum çünkü bu bir anket sorusu.
Flimzy

Yanıtlar:


115

Bu soru bir sürü görüşe sahip - ve Popüler bir Soru rozetine sahip - bu konuya çok fazla gizli ilgi olduğunu biliyorum ve birçok insan tam olarak aynı şeyi soruyor ve Interweb'lerde cevap bulamıyor.

Mevcut bilgilerin çoğu "dalgalı okuyucunun alıştırması" olarak bırakılan el dalgalı şeyin metinsel eşdeğeri ile sonuçlanır. ;)

Ancak nihayet golang-nut posta listesinin bir üyesi tarafından sağlanan (cömertçe) somut bir örnek buldum:

https://groups.google.com/forum/#!msg/golang-nuts/GE7a_5C5kbA/fdSnH41pOPYJ

Bu, özel kimlik doğrulama için temel olarak önerilen bir şema ve sunucu tarafı uygulaması sağlar. İstemci tarafı kodu hala size bağlıdır.

(Umarım yazının yazarı bunu görür: Teşekkürler!)

Alıntı yapıldı (ve yeniden biçimlendirildi):


"Aşağıdaki tasarım gibi bir şey öneririm:

create table User (
 ID int primary key identity(1,1),
 Username text,
 FullName text,
 PasswordHash text,
 PasswordSalt text,
 IsDisabled bool
)

create table UserSession (
 SessionKey text primary key,
 UserID int not null, -- Could have a hard "references User"
 LoginTime <time type> not null,
 LastSeenTime <time type> not null
)
  • Bir kullanıcı sitenize TLS altında bir POST aracılığıyla oturum açtığında, şifrenin geçerli olup olmadığını belirleyin.
  • Sonra rastgele bir oturum anahtarı verin, örneğin 50 veya daha fazla kripto rand karakteri ve güvenli bir Çerezde bir şeyler söyleyin.
  • Bu oturum anahtarını UserSession tablosuna ekleyin.
  • Daha sonra bu kullanıcıyı tekrar gördüğünüzde, ilk olarak SessionKey'in orada geçerli bir LoginTime ve LastSeenTime ve User silinip silinmediğini görmek için UserSession tablosuna basın. Bir zamanlayıcının UserSession'daki eski satırları otomatik olarak temizlemesi için tasarlayabilirsiniz. "

8
SO'da burada bulunan bağımsız bir siteyi sevme eğilimindeyiz, bu yüzden çözümü burada da yayınlamak ister misiniz? Bağlantının zamanında değişmesi durumunda (link rot ve başka neler ...) Gelecekteki ziyaretçiler bundan memnun olabilir.
24'te atlayın

Bu saygılı bir şekilde adil bir soru. Teşekkür ederim. Çözümü ekledim; sizce yazarın adı da eklenmeli mi? (Herkese açık, ancak her iki seçeneğin de görgü kurallarını merak ediyorum.)
SexxLuthor

Bence olduğu gibi iyi. Bu snippet'in "sahibi" olduğunu iddia etmiyorsunuz ve bu snippet'in orijinal yazarının her kopyanın bir atıfta bulunmasını gerektirdiğini göremiyorum. (Sadece iki sentim).
topskip

35
Veritabanınızda "PasswordSalt" alanı olmamalıdır, çünkü otomatik olarak bir tuz oluşturan ve döndürülen hash'a dahil eden hash algoritmanız olarak bcrypt kullanmalısınız. Ayrıca sabit bir zaman karşılaştırma fonksiyonu kullanın.
15:15

4
Bcrypt için +1. Ayrıca, 'şifreleme' ve 'kimlik doğrulama' anahtarlarıyla goril oturumları, oturum bilgilerini bir DB tablosu kullanmadan güvenli bir şekilde depolamanızı sağlar.
crantok


14

Kimlik doğrulamasını yapmak için ara katman yazılımı kullanırsınız.

Deneyebilirsin go-http-kimlik doğrulama temel ve kimlik doğrulama ve sindirmek gomniauth OAuth2'ye için.

Ancak, nasıl kimlik doğrulaması yapılacağı gerçekten uygulamanıza bağlıdır.

Kimlik doğrulama, http.Handlers'ınıza durum / bağlam ekler ve son zamanlarda bununla ilgili bazı tartışmalar olmuştur.

Bağlam problemine iyi bilinen çözümler goril / bağlam ve burada açıklanan google bağlamıdır .

Birlikte veya diğer ikisi olmadan kullanılabilen ve bağlamsız ara katman yazılımı ile güzel bir şekilde bütünleşen go-on / wrap'de küresel duruma ihtiyaç duymadan daha genel bir çözüm yaptım .

wraphttpauth , go-http- auth'un go-on / wrap ile entegrasyonunu sağlar.


Yeni başlayanlarla çok fazla yeni şey var. Acemi bir aceminin ne tür bir şeyle başlaması gerektiğini merak ediyorum. go-http-authveya gomniauthikisini birden mi?
Casper

Burada kimse golang OAuth 1.0 uyguladı? ConsumerKey ve Secret tabanlı kimlik doğrulaması?
user2888996

OAuth 1.0'ı nasıl uygulayabilirim? Tüketici Anahtarı ve sırrı mı kullanıyorsunuz? Lütfen yardım et. Aynı kütüphane almıyorum.
user2888996

9

Bunu 2018'de cevaplıyorum. JWT (JSON Web Token) kullanmanızı öneririm. Çözülmüş olarak işaretlediğiniz yanıtın ön (kullanıcı) ve arka (sunucu / db) yaptığı yolculuk dezavantajı vardır. Kullanıcı kimlik doğrulaması gerektiren sık sık istekte bulunursa daha da kötüsü, sunucudan ve veritabanından / sunucusundan gelen şişirilmiş istekle sonuçlanır. Bu sorunu çözmek için, jetonu kullanıcı tarafından erişilmesi / talep edilmesi gerektiğinde kullanıcı tarafından kullanılabilen JWT kullanın. Belirteç geçerliliğini kontrol etmek için veritabanı ve sunucu işlemlerine gerek yoktur.



2

Dürüst olmak gerekirse, uygulamanıza bağlayabileceğiniz ve uygulamaların iş mantığı ve gereksinimlerine bağlı olan birçok kimlik doğrulama yöntemi ve tekniği vardır.
Örneğin Oauth2, LDAP, yerel kimlik doğrulama, vb.
Cevabım , yerel kimlik doğrulamayı aradığınızı varsayar; bu da uygulamanızdaki kullanıcının kimliklerini yönettiğiniz anlamına gelir. Sunucu, kullanıcıların ve yöneticilerin Hesapları yönetmesine ve güvenilir iletişimi sağlamak için kendilerini Sunucu'ya nasıl tanımlamak istediklerine izin veren bir dizi harici API'yi göstermelidir. kullanıcı bilgilerini içeren bir DB tablosu oluşturacaksınız. güvenlik nedeniyle şifrenin sağlandığı yer Bkz . Parola veritabanında nasıl saklanır?

aşağıdaki yöntemlerden birini kullanarak kullanıcıların kimliğini doğrulamak için uygulama gereksinimlerini varsayalım:

  • temel kimlik doğrulama (kullanıcı adı, şifre):
    Bu kimlik doğrulama yöntemi, base64 içinde kodlanan ve rfc7617'de tanımlanan Yetkilendirme üstbilgisinde ayarlanan kullanıcı kimlik bilgilerine bağlıdır , temel olarak uygulama kullanıcı yetkisini çözdüğünde ve şifresini DB içinde karşılaştırmak için parolayı yeniden oluşturur eşleşirse hash doğrulanmışsa, aksi takdirde kullanıcıya 401 durum kodu döndürür.

  • sertifika tabanlı kimlik doğrulama:
    Bu kimlik doğrulama yöntemi, bir kullanıcıyı tanımlamak için Dijital Sertifikaya bağlıdır ve x509 kimlik doğrulaması olarak bilinir, bu nedenle uygulama kullanıcı isteklerini aldığında istemcinin sertifikasını okur ve sağlanan CA Kök sertifikasına uygun olduğunu doğrular APP.

  • taşıyıcı belirteci:
    Bu kimlik doğrulama yöntemi kısa ömürlü Erişim belirteçlerine bağlıdır, Taşıyıcı belirteci, genellikle bir oturum açma isteğine yanıt olarak sunucu tarafından oluşturulan şifreli bir dizedir. böylece uygulama kullanıcı isteklerini aldığında yetkilendirmeyi okur ve kullanıcının kimliğini doğrulamak için jetonu doğrular.

Ancak, go-guardian'ı , kimlik doğrulaması kütüphanesi için stratejiler olarak bilinen genişletilebilir bir kimlik doğrulama yöntemleri seti ile öneriyoruz . Temel olarak Go-Guardian, esnekliği en üst düzeye çıkaran ve geliştirici tarafından karar alınmasına izin veren belirli bir veritabanı şeması oluşturmaz veya herhangi bir veritabanı şeması kabul etmez.

Bir go-guard kimlik doğrulayıcısının kurulumu basittir.

Burada yukarıdaki yöntemlerin tam örneği.

package main

import (
    "context"
    "crypto/x509"
    "encoding/pem"
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "sync"

    "github.com/golang/groupcache/lru"
    "github.com/gorilla/mux"
    "github.com/shaj13/go-guardian/auth"
    "github.com/shaj13/go-guardian/auth/strategies/basic"
    "github.com/shaj13/go-guardian/auth/strategies/bearer"
    gx509 "github.com/shaj13/go-guardian/auth/strategies/x509"
    "github.com/shaj13/go-guardian/store"
)

var authenticator auth.Authenticator
var cache store.Cache

func middleware(next http.Handler) http.HandlerFunc {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        log.Println("Executing Auth Middleware")
        user, err := authenticator.Authenticate(r)
        if err != nil {
            code := http.StatusUnauthorized
            http.Error(w, http.StatusText(code), code)
            return
        }
        log.Printf("User %s Authenticated\n", user.UserName())
        next.ServeHTTP(w, r)
    })
}

func Resource(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("Resource!!\n"))
}

func Login(w http.ResponseWriter, r *http.Request) {
    token := "90d64460d14870c08c81352a05dedd3465940a7"
    user := auth.NewDefaultUser("admin", "1", nil, nil)
    cache.Store(token, user, r)
    body := fmt.Sprintf("token: %s \n", token)
    w.Write([]byte(body))
}

func main() {
    opts := x509.VerifyOptions{}
    opts.KeyUsages = []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}
    opts.Roots = x509.NewCertPool()
    // Read Root Ca Certificate
    opts.Roots.AddCert(readCertificate("<root-ca>"))

    cache = &store.LRU{
        lru.New(100),
        &sync.Mutex{},
    }

    // create strategies
    x509Strategy := gx509.New(opts)
    basicStrategy := basic.New(validateUser, cache)
    tokenStrategy := bearer.New(bearer.NoOpAuthenticate, cache)

    authenticator = auth.New()
    authenticator.EnableStrategy(gx509.StrategyKey, x509Strategy)
    authenticator.EnableStrategy(basic.StrategyKey, basicStrategy)
    authenticator.EnableStrategy(bearer.CachedStrategyKey, tokenStrategy)

    r := mux.NewRouter()
    r.HandleFunc("/resource", middleware(http.HandlerFunc(Resource)))
    r.HandleFunc("/login", middleware(http.HandlerFunc(Login)))

    log.Fatal(http.ListenAndServeTLS(":8080", "<server-cert>", "<server-key>", r))
}

func validateUser(ctx context.Context, r *http.Request, userName, password string) (auth.Info, error) {
    // here connect to db or any other service to fetch user and validate it.
    if userName == "stackoverflow" && password == "stackoverflow" {
        return auth.NewDefaultUser("stackoverflow", "10", nil, nil), nil
    }

    return nil, fmt.Errorf("Invalid credentials")
}

func readCertificate(file string) *x509.Certificate {
    data, err := ioutil.ReadFile(file)

    if err != nil {
        log.Fatalf("error reading %s: %v", file, err)
    }

    p, _ := pem.Decode(data)
    cert, err := x509.ParseCertificate(p.Bytes)
    if err != nil {
        log.Fatalf("error parseing certificate %s: %v", file, err)
    }

    return cert
}

Kullanımı:

  • Jeton alın:
curl  -k https://127.0.0.1:8080/login -u stackoverflow:stackoverflow
token: 90d64460d14870c08c81352a05dedd3465940a7

  • Bir jetonla kimlik doğrulaması yapın:
curl  -k https://127.0.0.1:8080/resource -H "Authorization: Bearer 90d64460d14870c08c81352a05dedd3465940a7"

Resource!!
  • Bir kullanıcı kimlik bilgileriyle kimlik doğrulaması yapın:
curl  -k https://127.0.0.1:8080/resource -u stackoverflow:stackoverflow

Resource!!
  • Bir kullanıcı sertifikası ile kimlik doğrulaması:
curl --cert client.pem --key client-key.pem --cacert ca.pem https://127.0.0.1:8080/resource

Resource!!

Aynı anda birden fazla kimlik doğrulama yöntemini etkinleştirebilirsiniz. Genellikle en az iki yöntem kullanmalısınız


1

Labstack Echo'ya bir göz atın - RESTful API'leri ve ön uç uygulamaları için kimlik doğrulamasını, belirli API yollarını korumak için kullanabileceğiniz ara katman yazılımına kaydırır .

Örneğin, temel kimlik doğrulamayı ayarlamak, /adminrota için yeni bir alt yönlendirici oluşturmak kadar basittir :

e.Group("/admin").Use(middleware.BasicAuth(func(username, password string, c echo.Context) (bool, error) {
    if username == "joe" && password == "secret" {
        return true, nil
    }
    return false, nil
}))

Labstack'ın tüm katman yazılımı kimlik doğrulama seçeneklerine buradan bakın.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.