0Pricing
R Academy · บทเรียน

การยืนยันตัวตนและความปลอดภัยของ API

เพิ่มการตรวจสอบคีย์ API ส่วนหัว CORS และตัวกรองจำกัดอัตรา

การยืนยันตัวตนและความปลอดภัยของ API เป็นบทเรียน R Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน R Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส R Academy มีบทเรียนทั้งหมด 4 บทเรียน

เหตุใดความปลอดภัยของ API จึงสำคัญ

API ของ Plumber คือเซิร์ฟเวอร์ HTTP สาธารณะ หากไม่มีการยืนยันตัวตน ทุกคนที่เข้าถึงพอร์ตได้ก็สามารถเรียกจุดปลายของคุณได้ ชั้นความปลอดภัยประกอบด้วยการยืนยันตัวตน (คุณเป็นใคร) การอนุญาต (คุณทำอะไรได้บ้าง) การตรวจสอบความถูกต้องของข้อมูลนำเข้า และความปลอดภัยของการรับส่งข้อมูล

ตัวกรอง Plumber ในฐานะมิดเดิลแวร์

ตัวกรองใน Plumber จะทำงานก่อนตัวจัดการเส้นทาง ใช้ pr_filter(name, function(req, res){...}) เพื่อเพิ่มมิดเดิลแวร์ที่ตรวจสอบทุกคำขอ เรียก plumber::forward() เพื่อส่งต่อไปยังตัวกรองหรือเส้นทางถัดไป หรือส่งคืนทันทีเพื่อปฏิเสธคำขอ

# 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)

ตัวกรองการยืนยันตัวตนด้วยคีย์ API

รูปแบบการยืนยันตัวตนอย่างง่ายที่ใช้กันทั่วไปที่สุดสำหรับ API ระหว่างเซิร์ฟเวอร์คือการส่งคีย์ API แบบคงที่ในส่วนหัว ตัวกรองจะตรวจสอบส่วนหัวในทุกคำขอ และส่งคืน 401 หากไม่มีคีย์หรือคีย์ไม่ถูกต้อง

# 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()
# }

การตรวจสอบส่วนหัว Authorization

โทเค็น Bearer จะถูกส่งในส่วนหัว Authorization: Bearer <token> เข้าถึงส่วนหัวนี้ผ่าน req$HTTP_AUTHORIZATION แยกวิเคราะห์ด้วย strsplit() เพื่อดึงส่วนของโทเค็นออกมา จากนั้นตรวจสอบความถูกต้องกับแหล่งจัดเก็บของคุณ

# #* @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()
# }

ข้ามการยืนยันตัวตนด้วย #* @preempt

จุดปลายบางรายการ เช่น การตรวจสอบสถานะและเอกสารสาธารณะ ควรข้ามการยืนยันตัวตน ให้ใส่คำอธิบายกำกับ #* @preempt auth โดยที่ auth ตรงกับชื่อตัวกรอง Plumber จะส่งคำขอไปยังตัวจัดการโดยตรงและข้ามตัวกรองนั้น

# #* 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 ด้วย pr_cors()

หากมีการเรียก API ของคุณจากเบราว์เซอร์บนโดเมนอื่น คุณต้องเปิดใช้ CORS (การแบ่งปันทรัพยากรข้ามต้นทาง) ใช้ pr_cors() เพื่อกำหนดค่าต้นทาง เมธอด และส่วนหัวที่อนุญาต โดยไม่ต้องเขียนส่วนหัวดิบด้วยตนเอง

# 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)

การทำความสะอาดข้อมูลนำเข้า — อย่าเชื่อถือข้อมูลจากผู้ใช้

ตรวจสอบความถูกต้องและทำความสะอาดข้อมูลนำเข้าทุกครั้งก่อนนำไปใช้ในคำสั่งค้นหาหรือการดำเนินการกับไฟล์:

  • ตรวจสอบชนิดข้อมูล: is.numeric(), is.character()
  • ตรวจสอบช่วงค่า: id >= 1 && id <= 1e9
  • ปฏิเสธอักขระที่ไม่คาดคิด: grepl('[^a-zA-Z0-9_]', name)
  • อย่าแทรกสตริงจากผู้ใช้ลงใน SQL โดยตรง — ให้ใช้คำสั่งค้นหาแบบกำหนดพารามิเตอร์
# #* @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))
# }

แนวคิดการจำกัดอัตราการเรียกใช้

Plumber ไม่มีตัวจำกัดอัตราการเรียกใช้ในตัว แต่คุณสามารถสร้างขึ้นในตัวกรองโดยใช้สภาพแวดล้อมที่ใช้ร่วมกันเพื่อติดตามจำนวนคำขอแยกตาม IP:

  • บันทึกเวลาของแต่ละคำขอแยกตาม IP ในสภาพแวดล้อมของ R
  • ปฏิเสธคำขอด้วย 429 หากจำนวนเกินขีดจำกัดภายในช่วงเวลาที่กำหนด
  • สำหรับระบบจริง ให้ใช้พร็อกซีย้อนกลับ เช่น nginx เพื่อจำกัดอัตราการเรียกใช้
# 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()
# }

การจัดเก็บคีย์ API อย่างปลอดภัย

อย่าฝังค่า секрет ไว้ในไฟล์ต้นฉบับโดยตรง ให้จัดเก็บไว้ในตัวแปรสภาพแวดล้อมและอ่านเมื่อเริ่มต้นด้วย Sys.getenv() ใช้ไฟล์ .env ในเครื่อง (ไม่นำเข้า git) และส่งค่า секрет ผ่านสภาพแวดล้อมการปรับใช้ในระบบจริง

# 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
')

การแนบบริบทผู้ใช้เข้ากับคำขอ

หลังตรวจสอบโทเค็นในตัวกรองการยืนยันตัวตนแล้ว ให้แนบข้อมูลผู้ใช้ที่ถอดรหัสแล้วเข้ากับออบเจ็กต์ req เพื่อให้ตัวจัดการถัดไปเข้าถึงได้โดยไม่ต้องตรวจสอบซ้ำ ฟิลด์ที่กำหนดเองบน req จะคงอยู่ตลอดห่วงโซ่ตัวกรอง

# #* @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)
# }

การจัดการข้อผิดพลาดด้วย tryCatch

ครอบตรรกะของจุดปลายด้วย tryCatch() เพื่อดักจับข้อผิดพลาดที่ไม่คาดคิดและส่งคืนการตอบกลับ 500 ที่เหมาะสม แทนการทำให้กระบวนการทำงานหยุดลงหรือเปิดเผยการติดตามสแตกแก่ผู้เรียก

# #* @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')
#   })
# }

ตรวจสอบด่วน: คำอธิบายกำกับ @preempt

คำอธิบายกำกับ #* @preempt auth ทำอะไรกับจุดปลายของ Plumber

ทบทวนความปลอดภัยของ API

การรักษาความปลอดภัยให้ API ของ Plumber ประกอบด้วยการป้องกันหลายชั้น:

  • pr_filter('auth', ...) — ตรวจสอบทุกคำขอในมิดเดิลแวร์
  • req$HTTP_AUTHORIZATION / req$HTTP_X_API_KEY — อ่านส่วนหัวสำหรับการยืนยันตัวตน
  • #* @preempt auth — ข้ามการยืนยันตัวตนสำหรับจุดปลายสาธารณะ
  • pr_cors() — กำหนดค่าการเข้าถึงข้ามต้นทางจากเบราว์เซอร์
  • ตรวจสอบความถูกต้องของข้อมูลนำเข้าก่อนการดำเนินการกับ DB หรือไฟล์ใด ๆ
  • Sys.getenv() สำหรับค่า секрет — อย่าฝังคีย์ไว้ในโค้ดโดยตรง

คำถามที่พบบ่อย

บทเรียน “การยืนยันตัวตนและความปลอดภัยของ API” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การยืนยันตัวตนและความปลอดภัยของ API” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส R Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส R Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การยืนยันตัวตนและความปลอดภัยของ API”

เพิ่มการตรวจสอบคีย์ API ส่วนหัว CORS และตัวกรองจำกัดอัตรา คุณปฏิบัติ R Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน R Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน R Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน

บทเรียน “การยืนยันตัวตนและความปลอดภัยของ API” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน R Academy นี้ได้ไหม

ได้ บทเรียน R Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. แนะนำ Plumber และ REST
  2. การสร้างจุดปลายทาง GET และ POST
  3. การยืนยันตัวตนและความปลอดภัยของ API
  4. การนำ Plumber API ไปใช้งานจริง
← กลับไปที่ R Academy