Autentikasi dan Keamanan API
Tambahkan validasi kunci API, header CORS, dan penyaring pembatasan laju.
Autentikasi dan Keamanan API adalah pelajaran R Academy gratis di CoddyKit. Ini adalah pelajaran 3 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar R Academy, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus R Academy mencakup 4 pelajaran total.
Mengapa Keamanan API Penting
API Plumber adalah server HTTP publik. Tanpa autentikasi, siapa pun yang dapat menjangkau PORT dapat memanggil titik akhir Anda. Lapisan keamanan mencakup autentikasi (siapa Anda?), otorisasi (apa yang dapat Anda lakukan?), validasi input, dan keamanan transportasi.
Filter Plumber sebagai Middleware
Filter di Plumber berjalan sebelum pengendali rute. Gunakan pr_filter(name, function(req, res){...}) untuk menambahkan middleware yang memeriksa setiap permintaan. Panggil plumber::forward() untuk meneruskan ke filter atau rute berikutnya; kembalikan hasil lebih awal untuk menolak permintaan.
# library(plumber)
# pr <- plumb('api.R')
# pr |>
# pr_filter('logger', function(req, res) {
# cat(req$REQUEST_METHOD, req$PATH_INFO, '
')
# plumber::forward() # must call to continue
# }) |>
# pr_run(port = 8000)Filter Autentikasi Kunci API
Pola autentikasi sederhana yang paling umum untuk API antars server adalah kunci API statis yang dikirim dalam header. Filter memeriksa header tersebut pada setiap permintaan dan mengembalikan 401 jika kunci tidak ada atau salah.
# In api.R:
# VALID_KEY <- Sys.getenv('API_SECRET_KEY')
#
# #* @filter auth
# function(req, res) {
# key <- req$HTTP_X_API_KEY
# if (is.null(key) || key != VALID_KEY) {
# res$status <- 401L
# return(list(error = 'Unauthorized'))
# }
# plumber::forward()
# }Memeriksa Header Otorisasi
Token Bearer dikirim dalam header Authorization: Bearer <token>. Akses melalui req$HTTP_AUTHORIZATION. Uraikan dengan strsplit() untuk mengambil bagian token, lalu validasikan token tersebut terhadap penyimpanan Anda.
# #* @filter bearer_auth
# function(req, res) {
# auth_header <- req$HTTP_AUTHORIZATION
# if (is.null(auth_header) || !startsWith(auth_header, 'Bearer ')) {
# res$status <- 401L
# return(list(error = 'Bearer token required'))
# }
# token <- substring(auth_header, 8) # strip 'Bearer '
# if (!token_is_valid(token)) {
# res$status <- 401L
# return(list(error = 'Invalid token'))
# }
# plumber::forward()
# }Melewati Autentikasi dengan #* @preempt
Beberapa titik akhir (pemeriksaan kesehatan, dokumentasi publik) sebaiknya melewati autentikasi. Anotasikan dengan #* @preempt auth jika auth cocok dengan nama filter. Plumber mengarahkan permintaan langsung ke pengendali, sehingga melewati filter tersebut.
# #* Health check — no auth required
# #* @preempt auth
# #* @get /ping
# function() {
# list(status = 'ok', time = as.character(Sys.time()))
# }
#
# #* Protected endpoint — goes through auth filter
# #* @get /data
# function() {
# list(secret = 'sensitive data')
# }CORS dengan pr_cors()
Jika API Anda dipanggil dari peramban di domain yang berbeda, Anda harus mengaktifkan CORS (Berbagi Sumber Daya Lintas Asal). Gunakan pr_cors() untuk mengonfigurasi asal, metode, dan header yang diizinkan tanpa menulis header mentah secara manual.
# library(plumber)
# pr <- plumb('api.R')
# pr |>
# pr_cors(
# origin = 'https://myapp.example.com',
# methods = c('GET', 'POST'),
# headers = c('Content-Type', 'X-API-Key'),
# credentials = TRUE
# ) |>
# pr_run(port = 8000)Pembersihan Input — Jangan Pernah Memercayai Input Pengguna
Selalu validasikan dan bersihkan input sebelum menggunakannya dalam kueri atau operasi berkas:
- Periksa jenis:
is.numeric(),is.character() - Periksa rentang:
id >= 1 && id <= 1e9 - Tolak karakter yang tidak diharapkan:
grepl('[^a-zA-Z0-9_]', name) - Jangan pernah menyisipkan string pengguna secara langsung ke SQL — gunakan kueri berparameter
# #* @post /search
# function(req, res) {
# body <- jsonlite::fromJSON(req$postBody)
# query <- body$query
# if (!is.character(query) || nchar(query) > 200) {
# res$status <- 400L
# return(list(error = 'query must be a string <= 200 chars'))
# }
# if (grepl('[;\'"]', query)) {
# res$status <- 400L
# return(list(error = 'Invalid characters in query'))
# }
# list(results = search_db(query))
# }Konsep Pembatasan Laju
Plumber tidak memiliki pembatas laju bawaan, tetapi Anda dapat menerapkannya dalam filter menggunakan lingkungan bersama untuk melacak jumlah permintaan per IP:
- Catat stempel waktu setiap permintaan berdasarkan IP dalam lingkungan R
- Tolak dengan 429 jika jumlahnya melebihi batas dalam jendela waktu tersebut
- Untuk produksi, gunakan proksi balik seperti nginx untuk pembatasan laju
# request_log <- new.env()
#
# #* @filter rate_limit
# function(req, res) {
# ip <- req$REMOTE_ADDR
# now <- as.numeric(Sys.time())
# if (!exists(ip, envir = request_log)) assign(ip, c(), envir = request_log)
# times <- get(ip, envir = request_log)
# times <- times[times > now - 60] # last 60 seconds
# if (length(times) >= 60) { res$status <- 429L; return(list(error='Too Many Requests')) }
# assign(ip, c(times, now), envir = request_log)
# plumber::forward()
# }Menyimpan Kunci API dengan Aman
Jangan pernah menulis rahasia secara langsung dalam berkas sumber. Simpan rahasia dalam variabel lingkungan dan baca saat mulai dengan Sys.getenv(). Gunakan berkas .env secara lokal (dikecualikan dari git) dan masukkan rahasia melalui lingkungan deployment dalam produksi.
# In .env (never commit this file):
# API_SECRET_KEY=my_super_secret_key_here
#
# In api.R:
# VALID_KEY <- Sys.getenv('API_SECRET_KEY', unset = '')
# if (nchar(VALID_KEY) == 0) stop('API_SECRET_KEY not set')
#
# Load .env locally (devtools::load_dot_env or Sys.setenv):
# readRenviron('.env')
cat('Sys.getenv reads API keys without exposing them in source
')Melampirkan Konteks Pengguna ke Permintaan
Setelah memvalidasi token dalam filter autentikasi, lampirkan informasi pengguna yang telah didekodekan ke objek req agar pengendali berikutnya dapat mengaksesnya tanpa memvalidasi ulang. Kolom khusus pada req tetap ada selama rantai filter.
# #* @filter auth
# function(req, res) {
# token <- req$HTTP_AUTHORIZATION
# user <- validate_token(token) # returns list(id=1, role='admin')
# if (is.null(user)) { res$status <- 401L; return(list(error='Unauthorized')) }
# req$user <- user # attach to request
# plumber::forward()
# }
#
# #* @get /profile
# function(req) {
# list(user_id = req$user$id, role = req$user$role)
# }Penanganan Kesalahan dengan tryCatch
Bungkus logika titik akhir Anda dalam tryCatch() untuk menangkap kesalahan yang tidak terduga dan mengembalikan respons 500 yang rapi, alih-alih membuat pekerja berhenti atau membocorkan jejak tumpukan kepada pemanggil.
# #* @get /risky/<id:int>
# function(id, res) {
# tryCatch({
# result <- risky_db_call(id)
# list(data = result)
# }, error = function(e) {
# message('Error in /risky: ', conditionMessage(e))
# res$status <- 500L
# list(error = 'Internal server error')
# })
# }Pemeriksaan Singkat: Anotasi @preempt
Apa yang dilakukan anotasi #* @preempt auth terhadap titik akhir Plumber?
Ringkasan Keamanan API
Mengamankan API Plumber memerlukan pertahanan berlapis:
pr_filter('auth', ...)— memeriksa setiap permintaan dalam middlewarereq$HTTP_AUTHORIZATION/req$HTTP_X_API_KEY— membaca header autentikasi#* @preempt auth— melewati autentikasi untuk titik akhir publikpr_cors()— mengonfigurasi akses lintas asal dari peramban- Validasi input sebelum operasi basis data atau berkas apa pun
Sys.getenv()untuk rahasia — jangan pernah menulis kunci secara langsung
Pertanyaan yang Sering Diajukan
Apakah pelajaran “Autentikasi dan Keamanan API” gratis?
Ya — teks lengkap “Autentikasi dan Keamanan API” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus R Academy, upgrade ke CoddyKit PRO. Kursus R Academy mencakup 4 pelajaran total.
Apa yang akan aku pelajari di “Autentikasi dan Keamanan API”?
Tambahkan validasi kunci API, header CORS, dan penyaring pembatasan laju. Kamu berlatih R Academy dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.
Apakah aku perlu pengalaman untuk memulai R Academy?
Tidak diperlukan pengalaman sebelumnya. R Academy di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 3 dari 4.
Berapa lama pelajaran “Autentikasi dan Keamanan API” memakan waktu?
Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.
Bisakah aku menulis dan menjalankan kode dalam pelajaran R Academy ini?
Ya. Setiap pelajaran R Academy menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.
Semua pelajaran dalam kursus ini
- Pengantar Plumber dan REST
- Membuat Titik Akhir GET dan POST
- Autentikasi dan Keamanan API
- Menerapkan API Plumber ke Produksi