Skip to content
Santekno.com | Level Up Your Engineering Skills
ID
📖 0%
30 Mar 2024 · 5 mnt baca ·Artikel 87 / 119
Go

10 Menambahkan Authentication Sederhana

IH
Ihsan Arif
Penulis di Santekno · Backend Engineer

Pada tahapan ini kita akan mencoba menambahkan Authentication sederhana dengan menggunakan middleware pada Golang. Perlu teman-teman ketahui bahwa middleware adalah proses mencegat suatu API yang mana sebelum service ketika diakses menuju ke dalam handler layer maka akan melewati middleware layer ini (yang akan kita buat) untuk menangkap dan memproses sesuatu untuk kebutuhan tertentu. Misalkan, pada kasus ini kita akan mencekat proses service untuk melihat apakah API tersebut memiliki header dengan ketentuan key X-API-Key.

Maka, middleware yang akan kita buat ini memiliki aturan sebagai berikut ini.

  1. Melakukan pengecekan apakah memiliki API tersebut memiliki header X-API-Key
  2. Jika tidak ada, maka akan memberikan informasi error Unauthorized
  3. Dan jika ada dan sesuai dengan yang sudah ditentukan valuenya yaitu s3cr3t dan sama, maka proses akan dilanjutkan.

Berikut kurang lebih flow middleware yang akan kita buat.

MERMAID
---
title: Authientication Middleware
---
stateDiagram-v2
    [*] --> hasHeader
    hasHeader --> unAuthorized
    unAuthorized --> [*]

    hasHeader --> HeaderXAPIKey
    HeaderXAPIKey --> unAuthorized

    HeaderXAPIKey --> SuccessContinue
    SuccessContinue --> [*]

Pembuatan Chain Middleware

Pertama kita akan buat folder pkg/middleware-chain dengan nama middleware_chain.go. Berikut ini isi dari file tersebut.

go
 1package middleware_chain
 2
 3import (
 4	"net/http"
 5
 6	"github.com/julienschmidt/httprouter"
 7)
 8
 9// Constructor is type of httprouter handler
10type Constructor func(httprouter.Handle) httprouter.Handle
11
12// Chain is struck for list of middleware
13type Chain struct {
14	constructors []Constructor
15}
16
17// New is for innitial new chain of
18func New(constructors ...Constructor) Chain {
19	return Chain{append(([]Constructor)(nil), constructors...)}
20}
21
22// Then is for http router handler
23func (c Chain) Then(h httprouter.Handle) httprouter.Handle {
24	if h == nil {
25		return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {}
26	}
27	for i := range c.constructors {
28		h = c.constructors[len(c.constructors)-1-i](h)
29	}
30
31	return h
32}
33
34// Append is for add chain router handler
35func (c Chain) Append(constructors ...Constructor) Chain {
36	newCons := make([]Constructor, 0, len(c.constructors)+len(constructors))
37	newCons = append(newCons, c.constructors...)
38	newCons = append(newCons, constructors...)
39
40	return Chain{newCons}
41}
Pada middleware yang sudah kita buat ini digunakan untuk general handling yang mana ketika nanti kita memiliki middleware yang lebih dari satu maka tidak perlu melakukan extend lebih sehingga mengakibatkan router yang cukup panjang pada penamaannya tetapi kita hanya cukup menambahkan saat inisialisasi router dengan mudah seperti ini.
go
1	// inisialisasi http router
2	router := httprouter.New()
3
4	// inisialisasi chain middleware
5	m := middleware_chain.New(
6		// fungsi middleware yang akan kita tambahkan
7	)

Membuat Middleware Authentication Sederhana

Pada fungsi yang akan kita buat ini yaitu middleware yang kebutuhannya untuk melakukan Authentication service agar tidak sembarangan orang mengakses service dan data kita sehingga lebih aman.

Sesuai dengan yang sudah dijelaskan diatas proses authentication middleware ini akan kita buat untuk service kita yang mana file-nya akan kita simpan di folder middleware/auth.go dan isi file tersebut dengan kode dibawah ini.

go
 1func AuthenticationBasic(next httprouter.Handle) httprouter.Handle {
 2	return func(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
 3		if r.Header.Get(XApiKey) != Secret {
 4			var statusCode = http.StatusUnauthorized
 5			var response models.HeaderResponse
 6			response.Code = statusCode
 7			response.Status = "Unauthorized"
 8			util.Response(w, response, statusCode)
 9			return
10		}
11
12		next(w, r, params)
13	}
14}

Sangat simpel karena kita ingin mencoba membuat middleware yang sederhana dan mudah terlebih dahulu agar teman-teman bisa paham proses dari middleware ini.

Mengubah Inisialisasi Router menjadi Fungsi Sendiri

Pada tahapan ini kita akan memisahkan inisialisasi Router API menjadi satu fungsi tersendiri agar mudah mengenal dan tidak terlalu panjang pada saat memiliki endpoint yang banyak mengakibatkan file main.go menjadi panjang dan besar. Sehingga akan kita separate kode inisialisasi Router API dengan kode seperti dibawah ini.

go
 1func NewRouter(articleHandler *httpHandler.Delivery) *httprouter.Router {
 2	// inisialisasi http router
 3	router := httprouter.New()
 4
 5	// inisialisasi chain middleware
 6	m := middleware_chain.New(
 7		middleware.AuthenticationBasic,
 8	)
 9
10	// entrypoint
11	router.GET("/api/articles", m.Then(articleHandler.GetAll))
12	router.GET("/api/articles/:article_id", m.Then(articleHandler.GetByID))
13	router.POST("/api/articles/", m.Then(articleHandler.Store))
14	router.PUT("/api/articles/:article_id", m.Then(articleHandler.Update))
15	router.DELETE("/api/articles/:article_id", m.Then(articleHandler.Delete))
16
17	return router
18}

Dan jangan lupa kita ubah inisialisasi Router API pada file main.go seperti ini.

go
 1func main() {
 2	fileEnv := ".env"
 3	if os.Getenv("environment") == "development" {
 4		fileEnv = "../.env"
 5	}
 6
 7	err := godotenv.Load(fileEnv)
 8	if err != nil {
 9		log.Fatalf("error loading .env file")
10	}
11
12	// inisialisasi database
13	db := database.New()
14
15	// inisialisasi repository
16	repository := mysqlRepository.New(db)
17	// inisialisasi usecase
18	articleUsecase := articleUsecase.New(repository)
19	// inisialisasi handler
20	articleHandler := httpHandler.New(articleUsecase)
21	// inisialisasi new router
22	router := NewRouter(articleHandler)
23
24	server := http.Server{
25		Addr:    "localhost:3000",
26		Handler: router,
27	}
28
29	err = server.ListenAndServe()
30	if err != nil {
31		panic(err)
32	}
33}

Pengujian

Setelah kita memasang Authentication Middleware kita perlu mencobanya di setiap endpoint yang sudah kita buat. Pengujiannya itu berarti ada dua skenario yaitu

  1. Unauthorized ketika kita mengakses service tanpa mengirimkan Header X-API-Key dengan value s3cr3t
  2. Sukses mengakses service dengan mengirimkan Header yang sesuai
  3. Unauthorized ketika kita mengirimkan Header X-API-Key dengan value yang salah misalkan secret.

Berikut Hasil dari pengujian kita coba

without header api key

Pengujian tanpa header X-API-Key terjadi error

with header api key success

Pengujian sukses dengan header X-API-Key dengan value yang sesuai

wrong header api key

Pengujian dengan header key yang salah

Artikel Terkait

💬 Komentar