عميل OAuth لـ Kotlin: التكامل مع المزودين عبر ktor-client و kotlinx-serialization

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

عميل OAuth لـ Kotlin: التكامل مع المزودين عبر ktor-client و kotlinx-serialization

\n\n

OAuth 2.0 هو بروتوكول تفويض قياسي يسمح للتطبيقات بالحصول على وصول محدود إلى موارد المستخدم دون نقل بيانات اعتماده. في نظام Kotlin البيئي، بفضل التوافق مع JVM والتعدد المنصات، يمكن تنفيذ عميل OAuth بكفاءة باستخدام المكتبات الحديثة. في هذه المقالة، سننظر في إنشاء عميل OAuth بلغة Kotlin باستخدام ktor-client لطلبات HTTP و kotlinx-serialization لمعالجة JSON.

\n\n

المكونات الأساسية لعميل OAuth

\n
    \n
  • عميل HTTP — ktor-client لإرسال الطلبات إلى خوادم التفويض والموارد.
  • \n
  • التسلسل — kotlinx-serialization لتحليل الردود إلى فئات البيانات.
  • \n
  • مخزن الرموز — في الذاكرة أو دائم (SharedPreferences، ملفات).
  • \n
  • مدير الحالات — معالجة authorization code، refresh token، حماية CSRF.
  • \n
\n\n

ربط التبعيات

\n

للعمل مع OAuth في Kotlin، أضف التبعيات التالية إلى build.gradle.kts (أو build.gradle):

\n
// build.gradle.kts\ndependencies {\n    implementation("io.ktor:ktor-client-core:2.3.12")\n    implementation("io.ktor:ktor-client-cio:2.3.12") // المحرك\n    implementation("io.ktor:ktor-client-content-negotiation:2.3.12")\n    implementation("io.ktor:ktor-serialization-kotlinx-json:2.3.12")\n    implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3")\n    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0")\n}
\n\n

الهندسة المعمارية الأساسية لعميل OAuth

\n

سنقسم المنطق إلى ثلاث طبقات:

\n
    \n
  • النماذج (DTO) — فئات بيانات للطلبات/الردود.
  • \n
  • الخدمة — فئة تدير تدفقات التفويض.
  • \n
  • العميل — غلاف حول ktor-client مع طرق لمنح مختلفة.
  • \n
\n\n

نماذج البيانات

\n
import kotlinx.serialization.SerialName\nimport kotlinx.serialization.Serializable\n\n@Serializable\ndata class TokenResponse(\n    @SerialName("access_token") val accessToken: String,\n    @SerialName("token_type") val tokenType: String = "Bearer",\n    @SerialName("expires_in") val expiresIn: Long? = null,\n    @SerialName("refresh_token") val refreshToken: String? = null,\n    @SerialName("scope") val scope: String? = null,\n    @SerialName("id_token") val idToken: String? = null // لـ OpenID Connect\n)\n\n@Serializable\ndata class OAuthError(\n    val error: String,\n    @SerialName("error_description") val errorDescription: String? = null\n)
\n\n

عميل OAuth2

\n
import io.ktor.client.*\nimport io.ktor.client.call.*\nimport io.ktor.client.plugins.contentnegotiation.*\nimport io.ktor.client.request.*\nimport io.ktor.client.statement.*\nimport io.ktor.http.*\nimport io.ktor.serialization.kotlinx.json.*\nimport kotlinx.serialization.json.Json\n\nclass OAuth2Client(\n    private val clientId: String,\n    private val clientSecret: String,\n    private val redirectUri: String,\n    private val tokenEndpoint: String,\n    private val authEndpoint: String\n) {\n    private val httpClient = HttpClient(CIO) {\n        install(ContentNegotiation) {\n            json(Json {\n                ignoreUnknownKeys = true\n                isLenient = true\n            })\n        }\n    }\n\n    // توليد URL لإعادة التوجيه إلى صفحة التفويض\n    fun getAuthorizationUrl(state: String, scope: String = "openid profile email"): String {\n        return "$authEndpoint?response_type=code" +\n                "&client_id=$clientId" +\n                "&redirect_uri=${java.net.URLEncoder.encode(redirectUri, "UTF-8")}" +\n                "&scope=${java.net.URLEncoder.encode(scope, "UTF-8")}                    

توصيات