0Pricing
R Academy · درس

المصادقة وأمان API

أضف التحقق من مفاتيح API وترويسات CORS ومرشحات تحديد معدل الطلبات

المصادقة وأمان API درس مجاني في R Academy على CoddyKit. هذا هو الدرس 3 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في R Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة R Academy 4 دروس في المجموع.

لماذا يُعد أمان API مهمًا

إن Plumber API هو خادم 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

يتضمن تأمين Plumber API وسائل دفاع متعددة الطبقات:

  • pr_filter('auth', ...) — فحص كل طلب في البرمجية الوسيطة
  • req$HTTP_AUTHORIZATION / req$HTTP_X_API_KEY — قراءة ترويسات المصادقة
  • #* @preempt auth — تجاوز المصادقة لنقاط النهاية العامة
  • pr_cors() — ضبط الوصول عبر النطاقات من المتصفح
  • التحقق من المدخلات قبل أي عملية في قاعدة البيانات أو الملفات
  • Sys.getenv() للأسرار — لا تضعوا المفاتيح بصورة ثابتة أبدًا

الأسئلة الشائعة

هل درس «المصادقة وأمان API» مجاني؟

نعم — نص درس «المصادقة وأمان API» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة R Academy، انتقل إلى CoddyKit PRO. تتضمن دورة R Academy 4 دروس في المجموع.

ماذا ستتعلم في «المصادقة وأمان API»؟

أضف التحقق من مفاتيح API وترويسات CORS ومرشحات تحديد معدل الطلبات تتمرن على R Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ R Academy؟

لا تُشترط خبرة سابقة. R Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 3 من أصل 4.

كم من الوقت يستغرق درس «المصادقة وأمان API»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس R Academy هذا؟

نعم. كل درس في R Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. مقدمة إلى Plumber وREST
  2. إنشاء نقاط نهاية GET وPOST
  3. المصادقة وأمان API
  4. نشر Plumber APIs في بيئة الإنتاج
← العودة إلى R Academy