Cara menggunakan mongodb jwt authentication

JWT merupakan salah satu standar JSON (RFC 7519) untuk keperluan akses token. Token dibentuk dari kombinasi beberapa informasi yang di-encode dan di-enkripsi. Informasi yang dimaksud adalah header, payload, dan signature.

Contoh JWT:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Skema JWT:

Cara menggunakan mongodb jwt authentication

  • Header, isinya adalah jenis algoritma yang digunakan untuk generate signature.
  • Payload, isinya adalah data penting untuk keperluan otentikasi, seperti grant, group, kapan login terjadi, dan atau lainnya. Data ini dalam konteks JWT biasa disebut dengan CLAIMS.
  • Signature, isinya adalah hasil dari enkripsi data menggunakan algoritma kriptografi. Data yang dimaksud adalah gabungan dari (encoded) header, (encoded) payload, dan secret key.

Umumnya pada aplikasi yang menerapkan teknik otorisasi menggunakan token, token di-generate di back end secara acak (menggunakan algoritma tertentu) lalu disimpan di database bersamaan dengan data user. Token tersebut bisa jadi tidak ada isinya, hanya random string, atau mungkin saja ada isinya.

Nantinya di setiap http call, token yang disertakan pada request header dicocokan dengan token yang ada di database, dilanjutkan dengan pengecekan grant/group/sejenisnya, untuk menentukan apakah request tersebut adalah verified request yang memang berhak mengakses endpoint.

Pada aplikasi yang menerapkan JWT, yang terjadi sedikit berbeda. Token adalah hasil dari proses kombinasi, encoding, dan enkripsi terhadap beberapa informasi. Nantinya pada sebuah http call, pengecekan token tidak dilakukan dengan membandingkan token yang ada di request vs token yang tersimpan di database, karena memang token pada JWT tidak disimpan di database. Pengecekan token dilakukan dengan cara mengecek hasil decode dan decrypt token yang ditautkan dalam request.

Ada kalanya token JWT perlu juga untuk disimpan di back-end, misalnya untuk keperluan auto-invalidate session pada multiple login, atau kasus lainnya.

Mungkin sekilas terlihat mengerikan, terlihat sangat gampang sekali untuk di-retas, buktinya adalah data otorisasi bisa dengan mudah diambil dari token JWT. Dan penulis sampaikan, bahwa ini adalah presepsi yang salah.

Informasi yang ada dalam token, selain di-encode, juga di-enkripsi. Dalam enkripsi diperlukan private key atau secret key, dan hanya pengembang yang tau. Jadi pastikan simpan baik-baik key tersebut.

Selama peretas tidak tau secret key yang digunakan, hasil decoding dan dekripsi data PASTI TIDAK VALID.

C.32.2. Persiapan Praktek

Kita akan buat sebuah aplikasi RESTful web service sederhana, isinya dua buah endpoint

package main

import "net/http"

type CustomMux struct {
    http.ServeMux
    middlewares []func(next http.Handler) http.Handler
}

func (c *CustomMux) RegisterMiddleware(next func(next http.Handler) http.Handler) {
    c.middlewares = append(c.middlewares, next)
}

func (c *CustomMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    var current http.Handler = &c.ServeMux

    for _, next := range c.middlewares {
        current = next(current)
    }

    current.ServeHTTP(w, r)
}
9 dan
[{
    "username": "noval",
    "password": "kaliparejaya123",
    "email": "[email protected]",
    "group": "admin"
}, {
    "username": "farhan",
    "password": "masokpakeko",
    "email": "[email protected]",
    "group": "publisher"
}]
0. Berikut merupakan spesifikasi aplikasinya:

  • Pengaksesan
    package main
    
    import "net/http"
    
    type CustomMux struct {
        http.ServeMux
        middlewares []func(next http.Handler) http.Handler
    }
    
    func (c *CustomMux) RegisterMiddleware(next func(next http.Handler) http.Handler) {
        c.middlewares = append(c.middlewares, next)
    }
    
    func (c *CustomMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
        var current http.Handler = &c.ServeMux
    
        for _, next := range c.middlewares {
            current = next(current)
        }
    
        current.ServeHTTP(w, r)
    }
    
    9 memerlukan token JWT.
  • Token didapat dari proses otentikasi ke endpoint
    [{
        "username": "noval",
        "password": "kaliparejaya123",
        "email": "[email protected]",
        "group": "admin"
    }, {
        "username": "farhan",
        "password": "masokpakeko",
        "email": "[email protected]",
        "group": "publisher"
    }]
    
    0 dengan menyisipkan username dan password.
  • Pada aplikasi yang sudah kita buat, sudah ada data list user yang tersimpan di database (sebenarnya bukan di-database, tapi di file json).

Ok, sekarang siapkan folder project baru.

• File
[{
    "username": "noval",
    "password": "kaliparejaya123",
    "email": "[email protected]",
    "group": "admin"
}, {
    "username": "farhan",
    "password": "masokpakeko",
    "email": "[email protected]",
    "group": "publisher"
}]
3

Lanjut isi file

[{
    "username": "noval",
    "password": "kaliparejaya123",
    "email": "[email protected]",
    "group": "admin"
}, {
    "username": "farhan",
    "password": "masokpakeko",
    "email": "[email protected]",
    "group": "publisher"
}]
3 dengan kode middleware yang sudah biasa kita gunakan.

package main

import "net/http"

type CustomMux struct {
    http.ServeMux
    middlewares []func(next http.Handler) http.Handler
}

func (c *CustomMux) RegisterMiddleware(next func(next http.Handler) http.Handler) {
    c.middlewares = append(c.middlewares, next)
}

func (c *CustomMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    var current http.Handler = &c.ServeMux

    for _, next := range c.middlewares {
        current = next(current)
    }

    current.ServeHTTP(w, r)
}

• File
[{
    "username": "noval",
    "password": "kaliparejaya123",
    "email": "[email protected]",
    "group": "admin"
}, {
    "username": "farhan",
    "password": "masokpakeko",
    "email": "[email protected]",
    "group": "publisher"
}]
5

Juga isi file

[{
    "username": "noval",
    "password": "kaliparejaya123",
    "email": "[email protected]",
    "group": "admin"
}, {
    "username": "farhan",
    "password": "masokpakeko",
    "email": "[email protected]",
    "group": "publisher"
}]
5 yang merupakan database aplikasi. Silakan tambahkan data JSON berikut.

[{
    "username": "noval",
    "password": "kaliparejaya123",
    "email": "[email protected]",
    "group": "admin"
}, {
    "username": "farhan",
    "password": "masokpakeko",
    "email": "[email protected]",
    "group": "publisher"
}]

• File
[{
    "username": "noval",
    "password": "kaliparejaya123",
    "email": "[email protected]",
    "group": "admin"
}, {
    "username": "farhan",
    "password": "masokpakeko",
    "email": "[email protected]",
    "group": "publisher"
}]
7

Sekarang kita fokus ke file

[{
    "username": "noval",
    "password": "kaliparejaya123",
    "email": "[email protected]",
    "group": "admin"
}, {
    "username": "farhan",
    "password": "masokpakeko",
    "email": "[email protected]",
    "group": "publisher"
}]
7. Import packages yang diperlukan. Salah satu dari packages tersebut adalah golang-jwt/jwt, yang digunakan untuk keperluan JWT.

go get -u github.com/golang-jwt/jwt/[email protected]
go get -u github.com/novalagung/gubrak/v2
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "net/http"
    "os"
    "path/filepath"
    "strings"

    jwt "github.com/golang-jwt/jwt/v4"
    gubrak "github.com/novalagung/gubrak/v2"
)

Masih di file yang sama, siapkan 4 buah konstanta yaitu: nama aplikasi, durasi login, metode enkripsi token, dan secret key.

type M map[string]interface{}

var APPLICATION_NAME = "My Simple JWT App"
var LOGIN_EXPIRATION_DURATION = time.Duration(1) * time.Hour
var JWT_SIGNING_METHOD = jwt.SigningMethodHS256
var JWT_SIGNATURE_KEY = []byte("the secret of kalimdor")

Kemudian buat fungsi

[{
    "username": "noval",
    "password": "kaliparejaya123",
    "email": "[email protected]",
    "group": "admin"
}, {
    "username": "farhan",
    "password": "masokpakeko",
    "email": "[email protected]",
    "group": "publisher"
}]
9, siapkan didalmnya sebuah
go get -u github.com/golang-jwt/jwt/[email protected]
go get -u github.com/novalagung/gubrak/v2
0 baru, dan daftarkan middleware
go get -u github.com/golang-jwt/jwt/[email protected]
go get -u github.com/novalagung/gubrak/v2
1 dan dua buah rute
package main

import "net/http"

type CustomMux struct {
    http.ServeMux
    middlewares []func(next http.Handler) http.Handler
}

func (c *CustomMux) RegisterMiddleware(next func(next http.Handler) http.Handler) {
    c.middlewares = append(c.middlewares, next)
}

func (c *CustomMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    var current http.Handler = &c.ServeMux

    for _, next := range c.middlewares {
        current = next(current)
    }

    current.ServeHTTP(w, r)
}
9 dan
[{
    "username": "noval",
    "password": "kaliparejaya123",
    "email": "[email protected]",
    "group": "admin"
}, {
    "username": "farhan",
    "password": "masokpakeko",
    "email": "[email protected]",
    "group": "publisher"
}]
0.

func main() {
    mux := new(CustomMux)
    mux.RegisterMiddleware(MiddlewareJWTAuthorization)

    mux.HandleFunc("/login", HandlerLogin)
    mux.HandleFunc("/index", HandlerIndex)

    server := new(http.Server)
    server.Handler = mux
    server.Addr = ":8080"

    fmt.Println("Starting server at", server.Addr)
    server.ListenAndServe()
}

Middleware

go get -u github.com/golang-jwt/jwt/[email protected]
go get -u github.com/novalagung/gubrak/v2
1 nantinya akan kita buat, tugasnya memvalidasi setiap request yang masuk, dengan cara mengecek token JWT yang disertakan. Middleware ini hanya berguna pada request ke selain endpoint
[{
    "username": "noval",
    "password": "kaliparejaya123",
    "email": "[email protected]",
    "group": "admin"
}, {
    "username": "farhan",
    "password": "masokpakeko",
    "email": "[email protected]",
    "group": "publisher"
}]
0, karena pada endpoint tersebut proses otentikasi terjadi.

C.32.3. Otentikasi & Generate Token

Siapkan handler

go get -u github.com/golang-jwt/jwt/[email protected]
go get -u github.com/novalagung/gubrak/v2
6. Tulis kode berikut.

Handler ini bertugas untuk meng-otentikasi client/consumer. Data username dan password dikirimkan ke endpoint dalam bentuk B.18. HTTP Basic Auth. Data tersebut kemudian disisipkan dalam pemanggilan fungsi otentikasi

go get -u github.com/golang-jwt/jwt/[email protected]
go get -u github.com/novalagung/gubrak/v2
7, yang nantinya juga akan kita buat.

ok, userInfo := authenticateUser(username, password)
if !ok {
    http.Error(w, "Invalid username or password", http.StatusBadRequest)
    return
}

Fungsi

go get -u github.com/golang-jwt/jwt/[email protected]
go get -u github.com/novalagung/gubrak/v2
7 memiliki dua nilai balik yang ditampung oleh variabel berikut:

  • Variabel
    go get -u github.com/golang-jwt/jwt/[email protected]
    go get -u github.com/novalagung/gubrak/v2
    
    9, penanda sukses tidaknya otentikasi.
  • Variabel
    package main
    
    import (
        "context"
        "encoding/json"
        "fmt"
        "io/ioutil"
        "net/http"
        "os"
        "path/filepath"
        "strings"
    
        jwt "github.com/golang-jwt/jwt/v4"
        gubrak "github.com/novalagung/gubrak/v2"
    )
    
    0, isinya informasi user yang sedang login, datanya didapat dari
    package main
    
    import (
        "context"
        "encoding/json"
        "fmt"
        "io/ioutil"
        "net/http"
        "os"
        "path/filepath"
        "strings"
    
        jwt "github.com/golang-jwt/jwt/v4"
        gubrak "github.com/novalagung/gubrak/v2"
    )
    
    1 (tetapi tanpa password).

Selanjutnya kita akan buat objek claims. Objek ini harus memenuhi persyaratan interface

package main

import (
    "context"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "net/http"
    "os"
    "path/filepath"
    "strings"

    jwt "github.com/golang-jwt/jwt/v4"
    gubrak "github.com/novalagung/gubrak/v2"
)
2. Objek claims bisa dibuat dari tipe
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "net/http"
    "os"
    "path/filepath"
    "strings"

    jwt "github.com/golang-jwt/jwt/v4"
    gubrak "github.com/novalagung/gubrak/v2"
)
3 dengan cara membungkusnya dalam fungsi
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "net/http"
    "os"
    "path/filepath"
    "strings"

    jwt "github.com/golang-jwt/jwt/v4"
    gubrak "github.com/novalagung/gubrak/v2"
)
4; atau dengan meng-embed interface
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "net/http"
    "os"
    "path/filepath"
    "strings"

    jwt "github.com/golang-jwt/jwt/v4"
    gubrak "github.com/novalagung/gubrak/v2"
)
5 pada struct baru, dan cara inilah yang akan kita pakai.

Seperti yang sudah kita bahas di awal, bahwa claims isinya adalah data-data untuk keperluan otentikasi. Dalam prakteknya, claims merupakan sebuah objek yang memilik banyak property atau fields. Nah, objek claims harus memiliki fields yang termasuk di dalam list . Dengan meng-embed interface

package main

import (
    "context"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "net/http"
    "os"
    "path/filepath"
    "strings"

    jwt "github.com/golang-jwt/jwt/v4"
    gubrak "github.com/novalagung/gubrak/v2"
)
5, maka fields pada struct dianggap sudah terwakili.

Pada aplikasi yang sedang kita kembangkan, claims selain menampung standard fields, juga menampung beberapa informasi lain, oleh karena itu kita perlu buat

package main

import (
    "context"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "net/http"
    "os"
    "path/filepath"
    "strings"

    jwt "github.com/golang-jwt/jwt/v4"
    gubrak "github.com/novalagung/gubrak/v2"
)
7 baru yang meng-embed
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "net/http"
    "os"
    "path/filepath"
    "strings"

    jwt "github.com/golang-jwt/jwt/v4"
    gubrak "github.com/novalagung/gubrak/v2"
)
5.

type MyClaims struct {
    jwt.StandardClaims
    Username string `json:"Username"`
    Email    string `json:"Email"`
    Group    string `json:"Group"`
}

Ok, struct

package main

import (
    "context"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "net/http"
    "os"
    "path/filepath"
    "strings"

    jwt "github.com/golang-jwt/jwt/v4"
    gubrak "github.com/novalagung/gubrak/v2"
)
9 sudah siap, sekarang buat objek baru dari struct tersebut.

claims := MyClaims{
    StandardClaims: jwt.StandardClaims{
        Issuer:    APPLICATION_NAME,
        ExpiresAt: time.Now().Add(LOGIN_EXPIRATION_DURATION).Unix(),
    },
    Username: userInfo["username"].(string),
    Email:    userInfo["email"].(string),
    Group:    userInfo["group"].(string),
}

Ada beberapa standard claims, pada contoh di atas hanya dua yang di-isi nilainya,

type M map[string]interface{}

var APPLICATION_NAME = "My Simple JWT App"
var LOGIN_EXPIRATION_DURATION = time.Duration(1) * time.Hour
var JWT_SIGNING_METHOD = jwt.SigningMethodHS256
var JWT_SIGNATURE_KEY = []byte("the secret of kalimdor")
0 dan
type M map[string]interface{}

var APPLICATION_NAME = "My Simple JWT App"
var LOGIN_EXPIRATION_DURATION = time.Duration(1) * time.Hour
var JWT_SIGNING_METHOD = jwt.SigningMethodHS256
var JWT_SIGNATURE_KEY = []byte("the secret of kalimdor")
1, selebihnya kita kosongi. Lalu 3 fields tambahan yang kita buat (username, email, dan group) di-isi menggunakan data yang didapat dari
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "net/http"
    "os"
    "path/filepath"
    "strings"

    jwt "github.com/golang-jwt/jwt/v4"
    gubrak "github.com/novalagung/gubrak/v2"
)
0.

  • type M map[string]interface{}
    
    var APPLICATION_NAME = "My Simple JWT App"
    var LOGIN_EXPIRATION_DURATION = time.Duration(1) * time.Hour
    var JWT_SIGNING_METHOD = jwt.SigningMethodHS256
    var JWT_SIGNATURE_KEY = []byte("the secret of kalimdor")
    
    0 (code
    type M map[string]interface{}
    
    var APPLICATION_NAME = "My Simple JWT App"
    var LOGIN_EXPIRATION_DURATION = time.Duration(1) * time.Hour
    var JWT_SIGNING_METHOD = jwt.SigningMethodHS256
    var JWT_SIGNATURE_KEY = []byte("the secret of kalimdor")
    
    4), adalah penerbit JWT, dalam konteks ini adalah
    type M map[string]interface{}
    
    var APPLICATION_NAME = "My Simple JWT App"
    var LOGIN_EXPIRATION_DURATION = time.Duration(1) * time.Hour
    var JWT_SIGNING_METHOD = jwt.SigningMethodHS256
    var JWT_SIGNATURE_KEY = []byte("the secret of kalimdor")
    
    5.
  • type M map[string]interface{}
    
    var APPLICATION_NAME = "My Simple JWT App"
    var LOGIN_EXPIRATION_DURATION = time.Duration(1) * time.Hour
    var JWT_SIGNING_METHOD = jwt.SigningMethodHS256
    var JWT_SIGNATURE_KEY = []byte("the secret of kalimdor")
    
    1 (code
    type M map[string]interface{}
    
    var APPLICATION_NAME = "My Simple JWT App"
    var LOGIN_EXPIRATION_DURATION = time.Duration(1) * time.Hour
    var JWT_SIGNING_METHOD = jwt.SigningMethodHS256
    var JWT_SIGNATURE_KEY = []byte("the secret of kalimdor")
    
    7), adalah kapan token JWT dianggap expired.

Ok, objek claims sudah siap, sekarang buat token baru. Pembuatannya dilakukan menggunakan fungsi

type M map[string]interface{}

var APPLICATION_NAME = "My Simple JWT App"
var LOGIN_EXPIRATION_DURATION = time.Duration(1) * time.Hour
var JWT_SIGNING_METHOD = jwt.SigningMethodHS256
var JWT_SIGNATURE_KEY = []byte("the secret of kalimdor")
8 yang menghasilkan nilai balik bertipe
type M map[string]interface{}

var APPLICATION_NAME = "My Simple JWT App"
var LOGIN_EXPIRATION_DURATION = time.Duration(1) * time.Hour
var JWT_SIGNING_METHOD = jwt.SigningMethodHS256
var JWT_SIGNATURE_KEY = []byte("the secret of kalimdor")
9. Parameter pertama adalah metode enkripsi yang digunakan, yaitu
func main() {
    mux := new(CustomMux)
    mux.RegisterMiddleware(MiddlewareJWTAuthorization)

    mux.HandleFunc("/login", HandlerLogin)
    mux.HandleFunc("/index", HandlerIndex)

    server := new(http.Server)
    server.Handler = mux
    server.Addr = ":8080"

    fmt.Println("Starting server at", server.Addr)
    server.ListenAndServe()
}
0, dan parameter kedua adalah
func main() {
    mux := new(CustomMux)
    mux.RegisterMiddleware(MiddlewareJWTAuthorization)

    mux.HandleFunc("/login", HandlerLogin)
    mux.HandleFunc("/index", HandlerIndex)

    server := new(http.Server)
    server.Handler = mux
    server.Addr = ":8080"

    fmt.Println("Starting server at", server.Addr)
    server.ListenAndServe()
}
1.

package main

import "net/http"

type CustomMux struct {
    http.ServeMux
    middlewares []func(next http.Handler) http.Handler
}

func (c *CustomMux) RegisterMiddleware(next func(next http.Handler) http.Handler) {
    c.middlewares = append(c.middlewares, next)
}

func (c *CustomMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    var current http.Handler = &c.ServeMux

    for _, next := range c.middlewares {
        current = next(current)
    }

    current.ServeHTTP(w, r)
}
0

Kemudian tanda-tangani token tersebut menggunakan secret key yang sudah didefinisikan di

func main() {
    mux := new(CustomMux)
    mux.RegisterMiddleware(MiddlewareJWTAuthorization)

    mux.HandleFunc("/login", HandlerLogin)
    mux.HandleFunc("/index", HandlerIndex)

    server := new(http.Server)
    server.Handler = mux
    server.Addr = ":8080"

    fmt.Println("Starting server at", server.Addr)
    server.ListenAndServe()
}
2, caranya dengan memanggil method
func main() {
    mux := new(CustomMux)
    mux.RegisterMiddleware(MiddlewareJWTAuthorization)

    mux.HandleFunc("/login", HandlerLogin)
    mux.HandleFunc("/index", HandlerIndex)

    server := new(http.Server)
    server.Handler = mux
    server.Addr = ":8080"

    fmt.Println("Starting server at", server.Addr)
    server.ListenAndServe()
}
3 milik objek
type M map[string]interface{}

var APPLICATION_NAME = "My Simple JWT App"
var LOGIN_EXPIRATION_DURATION = time.Duration(1) * time.Hour
var JWT_SIGNING_METHOD = jwt.SigningMethodHS256
var JWT_SIGNATURE_KEY = []byte("the secret of kalimdor")
9. Pemanggilan method ini mengembalikan data token string yang kemudian dijadikan nilai balik handler. Token string inilah yang dibutuhkan client/consumer untuk bisa mengakses endpoints yang ada.

package main

import "net/http"

type CustomMux struct {
    http.ServeMux
    middlewares []func(next http.Handler) http.Handler
}

func (c *CustomMux) RegisterMiddleware(next func(next http.Handler) http.Handler) {
    c.middlewares = append(c.middlewares, next)
}

func (c *CustomMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    var current http.Handler = &c.ServeMux

    for _, next := range c.middlewares {
        current = next(current)
    }

    current.ServeHTTP(w, r)
}
1

Bagian otentikasi dan generate token sebenarnya cukup sampai di sini. Tapi sebenarnya ada yang kurang, yaitu fungsi

go get -u github.com/golang-jwt/jwt/[email protected]
go get -u github.com/novalagung/gubrak/v2
7. Silakan buat fungsi tersebut.

package main

import "net/http"

type CustomMux struct {
    http.ServeMux
    middlewares []func(next http.Handler) http.Handler
}

func (c *CustomMux) RegisterMiddleware(next func(next http.Handler) http.Handler) {
    c.middlewares = append(c.middlewares, next)
}

func (c *CustomMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    var current http.Handler = &c.ServeMux

    for _, next := range c.middlewares {
        current = next(current)
    }

    current.ServeHTTP(w, r)
}
2

Isi fungsi

go get -u github.com/golang-jwt/jwt/[email protected]
go get -u github.com/novalagung/gubrak/v2
7 cukup jelas, sesuai namanya, yaitu melakukan pencocokan username dan password dengan data yang ada di dalam file
[{
    "username": "noval",
    "password": "kaliparejaya123",
    "email": "[email protected]",
    "group": "admin"
}, {
    "username": "farhan",
    "password": "masokpakeko",
    "email": "[email protected]",
    "group": "publisher"
}]
5.

Sekarang kita perlu menyiapkan

go get -u github.com/golang-jwt/jwt/[email protected]
go get -u github.com/novalagung/gubrak/v2
1, yang tugasnya adalah mengecek setiap request yang masuk ke endpoint selain
[{
    "username": "noval",
    "password": "kaliparejaya123",
    "email": "[email protected]",
    "group": "admin"
}, {
    "username": "farhan",
    "password": "masokpakeko",
    "email": "[email protected]",
    "group": "publisher"
}]
0, apakah ada akses token yang dibawa atau tidak. Dan jika ada, akan diverifikasi valid tidaknya token tersebut.

Kita gunakan skema header

ok, userInfo := authenticateUser(username, password)
if !ok {
    http.Error(w, "Invalid username or password", http.StatusBadRequest)
    return
}
0, sesuai spesifikasi RFC 6750 untuk keperluan penempatan dan pengambilan token.

Token di-extract dari header, kemudian diparsing dan di-validasi menggunakan fungsi

ok, userInfo := authenticateUser(username, password)
if !ok {
    http.Error(w, "Invalid username or password", http.StatusBadRequest)
    return
}
1.

package main

import "net/http"

type CustomMux struct {
    http.ServeMux
    middlewares []func(next http.Handler) http.Handler
}

func (c *CustomMux) RegisterMiddleware(next func(next http.Handler) http.Handler) {
    c.middlewares = append(c.middlewares, next)
}

func (c *CustomMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    var current http.Handler = &c.ServeMux

    for _, next := range c.middlewares {
        current = next(current)
    }

    current.ServeHTTP(w, r)
}
3

Parameter ke-2 fungsi

ok, userInfo := authenticateUser(username, password)
if !ok {
    http.Error(w, "Invalid username or password", http.StatusBadRequest)
    return
}
1 berisikan callback untuk pengecekan valid tidak-nya signing method, jika valid maka secret key dikembalikan. Fungsi
ok, userInfo := authenticateUser(username, password)
if !ok {
    http.Error(w, "Invalid username or password", http.StatusBadRequest)
    return
}
1 ini sendiri mengembalikan objek token.

Dari objek token, informasi claims diambil, lalu dilakukan pengecekan valid-tidaknya claims tersebut.

package main

import "net/http"

type CustomMux struct {
    http.ServeMux
    middlewares []func(next http.Handler) http.Handler
}

func (c *CustomMux) RegisterMiddleware(next func(next http.Handler) http.Handler) {
    c.middlewares = append(c.middlewares, next)
}

func (c *CustomMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    var current http.Handler = &c.ServeMux

    for _, next := range c.middlewares {
        current = next(current)
    }

    current.ServeHTTP(w, r)
}
4

O iya, mungkin ada pertanyaan kenapa objek claims yang dihasilkan

ok, userInfo := authenticateUser(username, password)
if !ok {
    http.Error(w, "Invalid username or password", http.StatusBadRequest)
    return
}
1 tipenya bukan
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "net/http"
    "os"
    "path/filepath"
    "strings"

    jwt "github.com/golang-jwt/jwt/v4"
    gubrak "github.com/novalagung/gubrak/v2"
)
9. Hal ini karena setelah objek claims dimasukan dalam proses pembentukan token, lewat fungsi
type M map[string]interface{}

var APPLICATION_NAME = "My Simple JWT App"
var LOGIN_EXPIRATION_DURATION = time.Duration(1) * time.Hour
var JWT_SIGNING_METHOD = jwt.SigningMethodHS256
var JWT_SIGNATURE_KEY = []byte("the secret of kalimdor")
8, objek akan di-encode ke tipe
ok, userInfo := authenticateUser(username, password)
if !ok {
    http.Error(w, "Invalid username or password", http.StatusBadRequest)
    return
}
7.

Data claims yang didapat disisipkan ke dalam context, agar nantinya di endpoint, informasi

package main

import (
    "context"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "net/http"
    "os"
    "path/filepath"
    "strings"

    jwt "github.com/golang-jwt/jwt/v4"
    gubrak "github.com/novalagung/gubrak/v2"
)
0 bisa diambil dengan mudah dari context request.

package main

import "net/http"

type CustomMux struct {
    http.ServeMux
    middlewares []func(next http.Handler) http.Handler
}

func (c *CustomMux) RegisterMiddleware(next func(next http.Handler) http.Handler) {
    c.middlewares = append(c.middlewares, next)
}

func (c *CustomMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    var current http.Handler = &c.ServeMux

    for _, next := range c.middlewares {
        current = next(current)
    }

    current.ServeHTTP(w, r)
}
5

• Handler Index

Terakhir, kita perlu menyiapkan handler untuk rute

package main

import "net/http"

type CustomMux struct {
    http.ServeMux
    middlewares []func(next http.Handler) http.Handler
}

func (c *CustomMux) RegisterMiddleware(next func(next http.Handler) http.Handler) {
    c.middlewares = append(c.middlewares, next)
}

func (c *CustomMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    var current http.Handler = &c.ServeMux

    for _, next := range c.middlewares {
        current = next(current)
    }

    current.ServeHTTP(w, r)
}
9.

package main

import "net/http"

type CustomMux struct {
    http.ServeMux
    middlewares []func(next http.Handler) http.Handler
}

func (c *CustomMux) RegisterMiddleware(next func(next http.Handler) http.Handler) {
    c.middlewares = append(c.middlewares, next)
}

func (c *CustomMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    var current http.Handler = &c.ServeMux

    for _, next := range c.middlewares {
        current = next(current)
    }

    current.ServeHTTP(w, r)
}
6

Informasi

package main

import (
    "context"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "net/http"
    "os"
    "path/filepath"
    "strings"

    jwt "github.com/golang-jwt/jwt/v4"
    gubrak "github.com/novalagung/gubrak/v2"
)
0 diambil dari context, lalu ditampilkan sebagai response endpoint.

C.32.5. Testing

Jalankan aplikasi, lalu test menggunakan curl.

• Otentikasi

package main

import "net/http"

type CustomMux struct {
    http.ServeMux
    middlewares []func(next http.Handler) http.Handler
}

func (c *CustomMux) RegisterMiddleware(next func(next http.Handler) http.Handler) {
    c.middlewares = append(c.middlewares, next)
}

func (c *CustomMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    var current http.Handler = &c.ServeMux

    for _, next := range c.middlewares {
        current = next(current)
    }

    current.ServeHTTP(w, r)
}
7

Output:

Cara menggunakan mongodb jwt authentication

• Mengakses Endpoint

Test endpoint

package main

import "net/http"

type CustomMux struct {
    http.ServeMux
    middlewares []func(next http.Handler) http.Handler
}

func (c *CustomMux) RegisterMiddleware(next func(next http.Handler) http.Handler) {
    c.middlewares = append(c.middlewares, next)
}

func (c *CustomMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    var current http.Handler = &c.ServeMux

    for _, next := range c.middlewares {
        current = next(current)
    }

    current.ServeHTTP(w, r)
}
9. Sisipkan token yang dikembalikan pada saat otentikasi, sebagai value header otorisasi dengan skema
ok, userInfo := authenticateUser(username, password)
if !ok {
    http.Error(w, "Invalid username or password", http.StatusBadRequest)
    return
}
0.

package main

import "net/http"

type CustomMux struct {
    http.ServeMux
    middlewares []func(next http.Handler) http.Handler
}

func (c *CustomMux) RegisterMiddleware(next func(next http.Handler) http.Handler) {
    c.middlewares = append(c.middlewares, next)
}

func (c *CustomMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    var current http.Handler = &c.ServeMux

    for _, next := range c.middlewares {
        current = next(current)
    }

    current.ServeHTTP(w, r)
}
8

Output:

Cara menggunakan mongodb jwt authentication

Semua berjalan sesuai harapan. Agar lebih meyakinkan, coba lakukan beberapa test dengan skenario yg salah, seperti: