15 Membuat Middleware Session Based Authentication Pada Golang
Pada artikel kali ini, kita akan membahas langkah-langkah pembuatan middleware untuk Session-based Authentication menggunakan Golang dan library httprouter. Middleware ini berguna untuk memvalidasi sesi pengguna di setiap request yang masuk ke aplikasi.
Apa itu Session-based Authentication?
Session-based authentication adalah metode otentikasi di mana pengguna login melalui aplikasi dan server menyimpan informasi tentang sesi pengguna dalam bentuk session ID yang disimpan di server atau dalam cookie di browser pengguna. Setiap kali pengguna mengakses resource yang dilindungi, server akan memverifikasi sesi tersebut.
Untuk contoh kali ini, kita akan menggunakan httprouter, sebuah router HTTP yang sangat cepat dan simpel di Golang, untuk membuat middleware autentikasi berbasis sesi.
Langkah 1: Persiapan Proyek Golang
Jika belum, pastikan proyek Golang telah disiapkan dengan langkah berikut:
- Buat direktori proyek di terminal atau melalui IDE favorit Anda.
- Inisialisasi proyek Go.
1go mod init session-auth-example
Langkah 2: Menginstal Dependensi
Pertama, kita perlu menambahkan dependensi untuk httprouter dan beberapa dependensi lain yang dibutuhkan, seperti gorilla/sessions untuk menangani sesi pengguna.
Instalasi httprouter dan gorilla/sessions dapat dilakukan dengan menjalankan perintah:
1go get github.com/julienschmidt/httprouter
2go get github.com/gorilla/sessionsLangkah 3: Menyiapkan Middleware Autentikasi
Sekarang kita akan membuat middleware untuk memverifikasi sesi yang ada di setiap permintaan HTTP. Pada tahap ini, kita memerlukan:
Storedari gorilla/sessions yang akan digunakan untuk menyimpan sesi di memori.- Fungsi middleware untuk memeriksa apakah sesi yang sah tersedia.
Kode Program authMiddleware.go
1package main
2
3import (
4 "github.com/gorilla/sessions"
5 "github.com/julienschmidt/httprouter"
6 "net/http"
7 "log"
8)
9
10var Store *sessions.CookieStore
11
12// Session memeriksa apakah sesi pengguna valid
13func Session(next httprouter.Handle) httprouter.Handle {
14 return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
15 // Mengambil session dari request
16 session, err := Store.Get(r, "session_key")
17 if err != nil {
18 http.Error(w, "Could not get session", http.StatusInternalServerError)
19 return
20 }
21
22 // Mengecek apakah sesi "user" ada
23 user, ok := session.Values["user"]
24 if !ok || user == nil {
25 http.Error(w, "Unauthorized", http.StatusUnauthorized)
26 return
27 }
28
29 // Melanjutkan permintaan jika sudah terautentikasi
30 next(w, r, ps)
31 }
32}
33
34func main() {
35 // set cookies store
36 middleware.Store = sessions.NewCookieStore([]byte("1234567890"))
37
38 // Membuat router dan route
39 router := httprouter.New()
40 router.GET("/protected-session", Session(ProtectedSessionHandler))
41
42 // Menjalankan server
43 log.Fatal(http.ListenAndServe(":8080", router))
44}
45
46// Handler untuk halaman private yang membutuhkan otentikasi
47func ProtectedSessionHandler(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
48 w.Write([]byte("Welcome to the session private page"))
49}Penjelasan kode:
- store adalah objek
gorilla/sessionsyang digunakan untuk menyimpan sesi menggunakan cookie. - AuthMiddleware adalah middleware yang akan mengecek apakah sesi pengguna yang valid ada dalam cookie.
- Jika sesi valid, middleware akan meneruskan request ke handler berikutnya; jika tidak, akan mengirimkan respons dengan status 401 Unauthorized.
Langkah 4: Menyiapkan Endpoint Login untuk Menyimpan Sesi
Untuk menguji autentikasi, kita membutuhkan endpoint untuk login. Endpoint ini akan menginisialisasi sesi saat pengguna login berhasil.
Kode Program loginHandler.go
1package main
2
3import (
4 "github.com/julienschmidt/httprouter"
5 "net/http"
6 "log"
7)
8
9func LoginHandler(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
10 // Mengambil sesi
11 session, _ := midleware.Store.Get(r, "session_key")
12
13 // Set nilai sesi user (misalnya setelah login berhasil)
14 session.Values["user"] = "authenticated-user"
15 session.Save(r, w)
16
17 // Menampilkan pesan setelah login berhasil
18 w.Write([]byte("Login berhasil"))
19}
20
21func main() {
22 // Membuat router dan route
23 router := httprouter.New()
24 router.GET("/login", LoginHandler)
25 router.GET("/protected-session", Session(ProtectedSessionHandler))
26
27 // Menjalankan server
28 log.Fatal(http.ListenAndServe(":8080", router))
29}Penjelasan:
- Saat pengguna mengunjungi endpoint
/login, sesi untuk pengguna akan diset dengan nilai"user". - Dengan begitu, sesi ini dapat digunakan untuk memvalidasi permintaan selanjutnya di endpoint yang dilindungi (
/private).
Langkah 5: Menulis Unit Test untuk Middleware
Membuat unit test adalah bagian penting untuk memastikan middleware berfungsi dengan baik. Di sini, kita akan menggunakan paket testing standar dari Golang untuk menulis unit test.
Kode Program authMiddleware_test.go
1package main
2
3import (
4 "github.com/julienschmidt/httprouter"
5 "net/http"
6 "net/http/httptest"
7 "testing"
8)
9
10func TestSession(t *testing.T) {
11 type args struct {
12 setupRequest func() *http.Request
13 }
14 tests := []struct {
15 name string
16 args args
17 wantStatusCode int
18 wantNextCalled bool
19 }{
20 {
21 name: "unauthorized request should return 401",
22 args: args{
23 setupRequest: func() *http.Request {
24 req := httptest.NewRequest(http.MethodGet, "/", nil)
25
26 // Set empty session (no user)
27 session, _ := Store.Get(req, "session_key")
28 _ = session.Save(req, httptest.NewRecorder())
29
30 return req
31 },
32 },
33 wantStatusCode: http.StatusUnauthorized,
34 wantNextCalled: false,
35 },
36 {
37 name: "success authorized",
38 args: args{
39 setupRequest: func() *http.Request {
40 req := httptest.NewRequest(http.MethodGet, "/", nil)
41
42 // Set session with user
43 session, _ := Store.Get(req, "session_key")
44 session.Values["user"] = "someuser"
45 _ = session.Save(req, httptest.NewRecorder())
46
47 return req
48 },
49 },
50 wantStatusCode: http.StatusOK,
51 wantNextCalled: true,
52 },
53 {
54 name: "error when session not found",
55 args: args{
56 setupRequest: func() *http.Request {
57 // Create request with invalid session cookie (simulate corrupted cookie)
58 req := httptest.NewRequest(http.MethodGet, "/", nil)
59
60 // Manually inject a bad cookie
61 req.AddCookie(&http.Cookie{
62 Name: "session_key",
63 Value: "invalid_base64",
64 })
65
66 return req
67 },
68 },
69 wantStatusCode: http.StatusInternalServerError,
70 wantNextCalled: false,
71 },
72 }
73
74 // Setup global Store before tests
75 Store = sessions.NewCookieStore([]byte("test-secret-key"))
76
77 for _, tt := range tests {
78 t.Run(tt.name, func(t *testing.T) {
79 rr := httptest.NewRecorder()
80 req := tt.args.setupRequest()
81 params := httprouter.Params{}
82
83 // Dummy next handler
84 nextCalled := false
85 next := func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
86 nextCalled = true
87 w.WriteHeader(http.StatusOK)
88 }
89
90 handler := Session(next)
91 handler(rr, req, params)
92
93 if rr.Code != tt.wantStatusCode {
94 t.Errorf("handler returned wrong status code: got %v, want %v", rr.Code, tt.wantStatusCode)
95 }
96 if nextCalled != tt.wantNextCalled {
97 t.Errorf("next handler call = %v, want %v", nextCalled, tt.wantNextCalled)
98 }
99 })
100 }
101}
102
103
104func TestLogin(t *testing.T) {
105 // Membuat router dan route untuk tes login
106 router := httprouter.New()
107 router.GET("/login", loginHandler)
108
109 // Membuat request HTTP untuk login
110 req, err := http.NewRequest("GET", "/login", nil)
111 if err != nil {
112 t.Fatal(err)
113 }
114
115 // Membangun ResponseRecorder
116 rr := httptest.NewRecorder()
117 router.ServeHTTP(rr, req)
118
119 // Memeriksa apakah response berhasil login
120 if rr.Code != http.StatusOK {
121 t.Errorf("Expected status OK, got %v", rr.Code)
122 }
123}Penjelasan Unit Test:
- TestAuthMiddleware: Menguji apakah middleware mengembalikan status 401 Unauthorized jika sesi pengguna tidak valid.
- TestLogin: Menguji apakah request login berhasil dengan status 200 OK.
Langkah 6: Kesimpulan
Dengan menggunakan Golang, kita dapat membuat middleware untuk Session-based Authentication secara efisien menggunakan httprouter. Dalam contoh ini, kita menyiapkan middleware yang memverifikasi keberadaan sesi pengguna dalam cookie untuk mengamankan endpoint.
Untuk informasi lebih lanjut mengenai Golang dan HTTP router, Anda dapat mengunjungi:
Ini adalah dasar dari bagaimana sistem autentikasi berbasis sesi dapat diimplementasikan di Golang menggunakan middleware. Jangan ragu untuk menggali lebih dalam tentang teknik-teknik dan implementasi lainnya!