یک تجربه ورود به سیستم ایجاد کنید که از کلیدهای عبور استفاده کند و در عین حال کاربران فعلی با رمز عبور را نیز در خود جای دهد.
این راهنما نحوه استفاده از قابلیت تکمیل خودکار فرم را توضیح میدهد تا کاربران بتوانند در کنار رمزهای عبور، با کلیدهای عبور نیز وارد سیستم شوند. استفاده از قابلیت تکمیل خودکار فرم، یک تجربه ورود یکپارچه ایجاد میکند و گذار از رمزهای عبور به روش احراز هویت امنتر و کاربرپسندتر با کلید عبور را سادهتر میکند.
بیاموزید که چگونه رابط کاربری شرطی WebAuthn را برای پشتیبانی از کاربران با رمز عبور و کلید عبور با حداقل اصطکاک در فرمهای ورود به سیستم موجود خود پیادهسازی کنید.
چرا از قابلیت تکمیل خودکار فرم برای ورود با رمز عبور استفاده کنیم؟
کلیدهای عبور به کاربران اجازه میدهند با استفاده از اثر انگشت، چهره یا پین دستگاه خود وارد وبسایتها شوند.
اگر همه کاربران رمز عبور داشتند، فرآیند احراز هویت میتوانست تنها با یک دکمه ورود انجام شود. با لمس این دکمه، کاربر میتوانست مستقیماً حساب کاربری را با قفل صفحه تأیید کرده و وارد سیستم شود.
با این حال، گذار از رمزهای عبور به کلیدهای عبور چالشهایی را به همراه دارد. وبسایتها باید در این دوره از کاربران رمز عبور و کلید عبور پشتیبانی کنند. انتظار از کاربران برای به خاطر سپردن اینکه کدام سایتها از کلیدهای عبور استفاده میکنند و درخواست از آنها برای انتخاب روش ورود از قبل، یک تجربه کاربری ضعیف ایجاد میکند.
کلیدهای عبور نیز یک فناوری جدید هستند و توضیح واضح آنها میتواند دشوار باشد. استفاده از رابط کاربری آشنای تکمیل خودکار به رفع چالش انتقال و نیاز به آشنایی کاربر کمک میکند.
استفاده از رابط کاربری شرطی
برای پشتیبانی مؤثر از کاربران با رمز عبور و کلید عبور، کلیدهای عبور را در پیشنهادات تکمیل خودکار فرم خود بگنجانید. این رویکرد از رابط کاربری شرطی ، یکی از ویژگیهای استاندارد WebAuthn ، استفاده میکند.
وقتی کاربر روی فیلد ورودی نام کاربری تمرکز میکند، یک کادر محاورهای تکمیل خودکار ظاهر میشود که کلیدهای عبور ذخیره شده را در کنار رمزهای عبور ذخیره شده پیشنهاد میدهد. کاربر میتواند کلید عبور یا رمز عبور را انتخاب کند و در صورت انتخاب کلید عبور، با استفاده از قفل صفحه دستگاه، وارد سیستم شود.
این به کاربران اجازه میدهد تا با فرم ورود موجود، اما با مزیت امنیتی اضافه شدهی کلیدهای عبور ( در صورت وجود) وارد وبسایت شما شوند.
نحوهی احراز هویت با کلید عبور
برای احراز هویت با کلید عبور، از API وباوثن (WebAuthn) استفاده میکنید.
چهار جزء در جریان احراز هویت با کلید عبور عبارتند از:
- Backend : جزئیات حساب کاربری، از جمله کلید عمومی را ذخیره میکند.
- فرانتاند (Frontend) : با مرورگر ارتباط برقرار میکند و دادههای لازم را از بکاند دریافت میکند.
- مرورگر : جاوا اسکریپت شما را اجرا میکند و با WebAuthn API تعامل دارد.
- ارائهدهندهی کلید عبور : کلید عبور را ایجاد و ذخیره میکند. این معمولاً یک مدیر رمز عبور مانند مدیر رمز عبور گوگل یا یک کلید امنیتی است.

فرآیند احراز هویت با استفاده از کلیدهای عبور از این جریان پیروی میکند:
- کاربر از صفحه ورود به سیستم بازدید میکند و بخش فرانتاند از بخش بکاند درخواست احراز هویت میکند.
- بخش بکاند، یک چالش WebAuthn مرتبط با حساب کاربری ایجاد و برمیگرداند.
- بخش frontend، تابع
navigator.credentials.get()را با چالش آغاز احراز هویت با استفاده از مرورگر فراخوانی میکند. - مرورگر ، در تعامل با ارائهدهندهی کلید عبور ، از کاربر میخواهد که یک کلید عبور انتخاب کند (اغلب با استفاده از یک کادر محاورهای تکمیل خودکار که با تمرکز روی فیلد ورود فعال میشود) و هویت خود را با استفاده از قفل صفحه دستگاه یا بیومتریک تأیید کند.
- پس از تأیید موفقیتآمیز کاربر، ارائهدهندهی کلید عبور، چالش را امضا میکند و مرورگر، اعتبارنامهی کلید عمومی حاصل (شامل امضا) را به frontend برمیگرداند.
- فرانتاند این اعتبارنامه را به بکاند ارسال میکند.
- بخش مدیریت، امضای اعتبارنامه را با کلید عمومی ذخیره شده کاربر تأیید میکند. اگر تأیید موفقیتآمیز باشد، بخش مدیریت، کاربر را وارد سیستم میکند.
با استفاده از رمز عبور از طریق تکمیل خودکار فرم، احراز هویت کنید
برای شروع احراز هویت با رمز عبور با استفاده از تکمیل خودکار فرم، هنگام بارگذاری صفحه ورود، یک فراخوانی مشروط WebAuthn get انجام دهید. این فراخوانی به navigator.credentials.get() شامل گزینه mediation: 'conditional' است.
یک درخواست مشروط به API مربوط به navigator.credentials.get() در WebAuthn ، رابط کاربری را بلافاصله نمایش نمیدهد. در عوض، در حالت انتظار منتظر میماند تا کاربر با درخواست تکمیل خودکار فیلد نام کاربری تعامل کند. اگر کاربر یک کلید عبور انتخاب کند، مرورگر promise در انتظار را با یک credential برای ورود کاربر حل میکند و از ارسال فرم سنتی صرف نظر میکند. اگر کاربر به جای آن یک رمز عبور انتخاب کند، promise حل نمیشود و جریان استاندارد ورود با رمز عبور continue.rm ادامه مییابد. در این صورت، مسئولیت ورود کاربر بر عهده صفحه است.
حاشیهنویسی فیلد ورودی فرم
برای فعال کردن تکمیل خودکار با رمز عبور، ویژگی autocomplete را به فیلد input نام کاربری فرم خود اضافه کنید. username و webauthn را به عنوان مقادیر جدا شده با فاصله وارد کنید.
<input type="text" name="username" autocomplete="username webauthn" autofocus>
افزودن autofocus به این فیلد، به طور خودکار هنگام بارگذاری صفحه، درخواست تکمیل خودکار را فعال میکند و بلافاصله رمزهای عبور و کلیدهای عبور موجود را نشان میدهد.
تشخیص ویژگی
قبل از فراخوانی یک فراخوانی مشروط WebAuthn API، بررسی کنید که آیا:
- مرورگر از WebAuthn با
PublicKeyCredentialپشتیبانی میکند.
- مرورگر از تشخیص قابلیت با استفاده از
PublicKeyCredential.getClientCapabilities()پشتیبانی میکند.
- مرورگر از رابط کاربری شرطی WebAuthn با
conditionalGetپشتیبانی میکند.
قطعه کد زیر نشان میدهد که چگونه میتوانید بررسی کنید که آیا مرورگر از این ویژگیها پشتیبانی میکند یا خیر:
if (window.PublicKeyCredential && PublicKeyCredential.getClientCapabilities) {
const capabilities = await PublicKeyCredential.getClientCapabilities();
// Check if conditional mediation is available.
if (capabilities.conditionalGet === true) {
// The browser supports conditional mediation.
}
}
دریافت اطلاعات از بکاند
بکاند شما باید چندین گزینه را برای فرانتاند فراهم کند تا فراخوانی navigator.credentials.get() آغاز شود. این گزینهها معمولاً به عنوان یک شیء JSON از یک نقطه پایانی روی سرور شما دریافت میشوند.
ویژگیهای کلیدی در شیء options عبارتند از:
-
challenge: یک چالش ایجاد شده توسط سرور در ArrayBuffer (معمولاً Base64URL کدگذاری شده برای انتقال JSON). این برای جلوگیری از حملات بازپخش ضروری است. سرور شما باید برای هر تلاش ورود به سیستم، یک چالش جدید ایجاد کند و پس از مدت کوتاهی یا در صورت عدم موفقیت تلاش، آن را نامعتبر کند. -
allowCredentials: آرایهای از توصیفکنندههای اعتبارنامه. یک آرایه خالی به آن ارسال کنید. این باعث میشود مرورگر تمام اعتبارنامههای مربوط بهrpIdمشخص شده را فهرست کند. userVerification: ترجیح شما برای تأیید کاربر، مانند الزام به قفل صفحه نمایش دستگاه، را مشخص میکند. مقدار پیشفرض و توصیهشده"preferred"است. مقادیر ممکن عبارتند از:-
"required": تأیید کاربر باید توسط تأییدکننده (مانند پین یا بیومتریک) انجام شود. اگر تأیید انجام نشود، عملیات با شکست مواجه میشود. -
"preferred": احراز هویتکننده تلاش میکند تا کاربر را تأیید کند، اما عملیات بدون آن نیز میتواند موفقیتآمیز باشد. -
"discouraged": تأییدکنندهی هویت باید در صورت امکان از تأیید کاربر خودداری کند.
-
rpId: شناسه طرف مورد اعتماد شما، که معمولاً دامنه وبسایت شما (مانندexample.com) است. این مقدار باید دقیقاً باrp.idاستفاده شده هنگام ایجاد اعتبارنامه رمز عبور مطابقت داشته باشد.
سرور شما باید این شیء options را بسازد. مقادیر ArrayBuffer (مانند challenge ) باید برای انتقال JSON با Base64URL کدگذاری شوند. در frontend، پس از تجزیه JSON، از PublicKeyCredential.parseRequestOptionsFromJSON() برای تبدیل شیء (شامل رمزگشایی رشتههای Base64URL) به فرمت مورد انتظار navigator.credentials.get() استفاده کنید.
قطعه کد زیر نشان میدهد که چگونه میتوانید اطلاعات مورد نیاز برای احراز هویت با کلید عبور را دریافت و رمزگشایی کنید.
// Fetch an encoded PubicKeyCredentialRequestOptions from the server.
const _options = await fetch('/webauthn/signinRequest');
// Deserialize and decode the PublicKeyCredentialRequestOptions.
const decoded_options = JSON.parse(_options);
const options = PublicKeyCredential.parseRequestOptionsFromJSON(decoded_options);
...
فراخوانی WebAuthn API با استفاده از پرچم conditional برای احراز هویت کاربر
پس از آمادهسازی شیء publicKeyCredentialRequestOptions (که در کد مثال زیر به عنوان options به آن اشاره شده است) ، برای شروع احراز هویت مشروط با کلید عبور، تابع navigator.credentials.get() را فراخوانی کنید.
// To abort a WebAuthn call, instantiate an AbortController.
const abortController = new AbortController();
// Invoke WebAuthn to authenticate with a passkey.
const credential = await navigator.credentials.get({
publicKey: options,
signal: abortController.signal,
// Specify 'conditional' to activate conditional UI
mediation: 'conditional'
});
پارامترهای کلیدی برای این فراخوانی:
-
publicKey: این باید شیءpublicKeyCredentialRequestOptions(که در مثال با نامoptionsشناخته میشود) باشد که از سرور مجازی خود دریافت و در مرحله قبل پردازش کردهاید. -
signal: ارسال یک signal ازAbortController(مانندabortController.signal) به شما امکان میدهد درخواستget()را به صورت برنامهنویسی لغو کنید. این زمانی مفید است که میخواهید یک فراخوانی WebAuthn دیگر را فراخوانی کنید. -
mediation: 'conditional': این پرچم حیاتی است که فراخوانی WebAuthn را مشروط میکند. این پرچم به مرورگر میگوید که منتظر تعامل کاربر با یک درخواست تکمیل خودکار بماند، نه اینکه بلافاصله یک کادر محاورهای modal را نشان دهد.
اعتبارنامه کلید عمومی بازگردانده شده را به سرور RP ارسال کنید
اگر کاربر یک رمز عبور انتخاب کند و هویت خود را با موفقیت تأیید کند (برای مثال، با استفاده از قفل صفحه نمایش دستگاه خود)، تابع navigator.credentials.get() اجرا میشود. این تابع یک شیء PublicKeyCredential را به فرانتاند شما برمیگرداند.
این promise میتواند به دلایل مختلف رد شود. شما باید این خطاها را در کد خود با بررسی ویژگی name از شیء Error مدیریت کنید:
-
NotAllowedError: کاربر عملیات را لغو کرد، یا هیچ رمز عبوری انتخاب نشده بود. -
AbortError: عملیات لغو شد، احتمالاً توسط کد شما با استفاده ازAbortController. - سایر استثنائات: خطای غیرمنتظرهای رخ داده است. مرورگر معمولاً یک کادر محاورهای خطا به کاربر نشان میدهد.
شیء PublicKeyCredential شامل چندین ویژگی است. ویژگیهای کلیدی مرتبط با احراز هویت عبارتند از:
-
id: شناسه کدگذاری شده base64url مربوط به اعتبارنامه رمز عبور احراز هویت شده. -
rawId: یک نسخه ArrayBuffer از شناسه اعتبارنامه. -
response.clientDataJSON: یک ArrayBuffer از دادههای کلاینت. این فیلد شامل اطلاعاتی مانند چالش و مبدایی است که سرور شما باید تأیید کند. -
response.authenticatorData: یک ArrayBuffer از دادههای احراز هویت. این فیلد شامل اطلاعاتی مانند شناسه RP است. -
response.signature: یک ArrayBuffer حاوی امضا. این مقدار هسته اصلی اعتبارنامه است و سرور شما باید این امضا را با استفاده از کلید عمومی ذخیره شده برای اعتبارنامه تأیید کند. -
response.userHandle: یک ArrayBuffer که شامل شناسه کاربری ارائه شده در هنگام ثبت رمز عبور است. -
authenticatorAttachment: نشان میدهد که آیا authenticator بخشی از دستگاه کلاینت (platform) یا خارجی (cross-platform) است. اگر کاربر با تلفن وارد سیستم شود، ممکن است یک پیوستcross-platformرخ دهد. در چنین مواردی، برای راحتی بیشتر در آینده، از آنها بخواهید که یک رمز عبور روی دستگاه فعلی ایجاد کنند . -
type: این فیلد همیشه روی"public-key"تنظیم میشود.
برای ارسال این شیء PublicKeyCredential به backend خود، ابتدا متد .toJSON() را فراخوانی کنید. این متد یک نسخه قابل سریالسازی JSON از اعتبارنامه ایجاد میکند که به درستی تبدیل ویژگیهای ArrayBuffer (مانند rawId ، clientDataJSON ، authenticatorData ، signature و userHandle ) را به رشتههای کدگذاری شده Base64URL مدیریت میکند. سپس، از JSON.stringify() برای تبدیل این شیء به یک رشته و ارسال آن در بدنه درخواست خود به سرور استفاده کنید.
...
// Encode and serialize the PublicKeyCredential.
const _result = credential.toJSON();
const result = JSON.stringify(_result);
// Encode and send the credential to the server for verification.
const response = await fetch('/webauthn/signinResponse', {
method: 'post',
credentials: 'same-origin',
body: result
});
امضا را تأیید کنید
وقتی سرور بکاند شما اعتبارنامه کلید عمومی را دریافت میکند، باید صحت آن را تأیید کند. این شامل موارد زیر است:
- تجزیه دادههای اعتبارنامه.
- جستجوی کلید عمومی ذخیره شده مرتبط با
idاعتبارنامه. - تأیید
signatureدریافتی در برابر کلید عمومی ذخیره شده. - اعتبارسنجی سایر دادهها، مانند چالش و مبدا.
ما توصیه میکنیم برای مدیریت ایمن این عملیات رمزنگاری، از یک کتابخانه FIDO/WebAuthn سمت سرور استفاده کنید. میتوانید کتابخانههای متنباز را در مخزن گیتهاب awesome-webauthn پیدا کنید .
اگر امضا و سایر ادعاها معتبر باشند، سرور میتواند کاربر را وارد سیستم کند. برای مراحل دقیق اعتبارسنجی سمت سرور، به احراز هویت با رمز عبور سمت سرور مراجعه کنید.
اگر اعتبارنامههای منطبق در backend یافت نشدند، سیگنال دهید
اگر سرور backend شما نتواند هنگام ورود به سیستم، اعتبارنامهای با شناسه منطبق پیدا کند، ممکن است کاربر قبلاً این کلید عبور را از سرور شما حذف کرده باشد اما از ارائهدهنده کلید عبور خود حذف نکرده باشد. اگر ارائهدهنده کلید عبور همچنان کلید عبوری را پیشنهاد دهد که دیگر با سایت شما کار نمیکند، این عدم تطابق میتواند منجر به یک تجربه کاربری گیجکننده شود. برای بهبود این وضعیت، باید به ارائهدهنده کلید عبور علامت دهید تا کلید عبور یتیم را حذف کند.
شما میتوانید از متد PublicKeyCredential.signalUnknownCredential() ، بخشی از Webauthn Signal API ، برای اطلاعرسانی به ارائهدهندهی کلید عبور مبنی بر حذف یا عدم وجود اعتبارنامهی مشخصشده استفاده کنید. اگر سرور شما (برای مثال، با یک کد وضعیت HTTP خاص مانند ۴۰۴) نشان دهد که شناسهی اعتبارنامهی ارائهشده ناشناخته است، این متد استاتیک را در سمت کلاینت فراخوانی کنید. شناسهی RP و شناسهی اعتبارنامهی ناشناخته را به این متد ارائه دهید. ارائهدهندهی کلید عبور، در صورت پشتیبانی از سیگنال، باید کلید عبور را حذف کند.
// Detect authentication failure due to lack of the credential
if (response.status === 404) {
// Feature detection
if (PublicKeyCredential.signalUnknownCredential) {
await PublicKeyCredential.signalUnknownCredential({
rpId: "example.com",
credentialId: "vI0qOggiE3OT01ZRWBYz5l4MEgU0c7PmAA" // base64url encoded credential ID
});
} else {
// Encourage the user to delete the passkey from the password manager nevertheless.
...
}
}
پس از احراز هویت
بسته به نحوه ورود کاربر، جریانهای مختلفی را برای دنبال کردن پیشنهاد میکنیم.
اگر کاربر بدون رمز عبور وارد سیستم شده باشد
اگر کاربر بدون رمز عبور وارد وبسایت شما شده باشد، ممکن است برای آن حساب یا روی دستگاه فعلی خود رمز عبور ثبت نکرده باشد. اکنون زمان مناسبی برای تشویق کاربر به ایجاد رمز عبور است. رویکردهای زیر را در نظر بگیرید:
- ارتقا رمزهای عبور به کلیدهای عبور : از ایجاد شرطی ، یک ویژگی WebAuthn که به مرورگر اجازه میدهد پس از ورود موفقیتآمیز رمز عبور، به طور خودکار یک کلید عبور برای کاربر ایجاد کند، استفاده کنید. این میتواند با سادهسازی فرآیند ایجاد، پذیرش کلید عبور را به طور قابل توجهی بهبود بخشد. نحوه کار و نحوه پیادهسازی آن را در [لینک] به کاربران کمک کنید تا کلیدهای عبور را به طور یکپارچهتری اتخاذ کنند.
- درخواست دستی برای ایجاد کلید عبور : کاربران را تشویق کنید تا یک کلید عبور ایجاد کنند. این میتواند پس از تکمیل یک فرآیند ورود به سیستم پیچیدهتر، مانند احراز هویت چند عاملی (MFA)، توسط کاربر مؤثر باشد. با این حال، از درخواستهای بیش از حد که میتواند برای تجربه کاربر مزاحم باشد، خودداری کنید.
برای اینکه ببینید چگونه میتوانید کاربران را به ایجاد کلید عبور تشویق کنید و سایر شیوههای خوب را بیاموزید، به مثالهای مربوط به «انتقال کلید عبور به کاربران» مراجعه کنید.
اگر کاربر با رمز عبور وارد سیستم شده باشد
پس از اینکه کاربر با موفقیت با رمز عبور وارد سیستم شد، شما فرصتهای متعددی برای بهبود تجربه کاربری و حفظ ثبات حساب کاربری او دارید.
پس از احراز هویت بین دستگاهی، ایجاد یک رمز عبور جدید را تشویق کنید.
اگر کاربری با استفاده از مکانیزم بین دستگاهی (مثلاً اسکن کد QR با تلفن خود) با کلید عبور وارد سیستم شود، ممکن است کلید عبوری که استفاده کرده است به صورت محلی در دستگاهی که با آن وارد سیستم میشود ذخیره نشده باشد. این اتفاق میتواند زمانی رخ دهد که:
- آنها یک کلید عبور دارند اما از ارائه دهنده کلید عبوری استفاده میکنند که از سیستم عامل یا مرورگر ورود به سیستم پشتیبانی نمیکند.
- آنها دسترسی به ارائه دهنده کلید عبور را در دستگاه ورود به سیستم از دست دادهاند، اما کلید عبور هنوز در دستگاه دیگری موجود است.
در این شرایط، از کاربر بخواهید که یک رمز عبور جدید روی دستگاه فعلی ایجاد کند. این کار میتواند آنها را از تکرار فرآیند ورود به سیستم بین دستگاهی در آینده نجات دهد. برای تعیین اینکه آیا کاربر با استفاده از یک رمز عبور بین دستگاهی وارد سیستم شده است یا خیر، ویژگی authenticatorAttachment مربوط به اعتبارنامه را بررسی کنید. اگر مقدار آن "cross-platform" باشد، نشاندهنده احراز هویت بین دستگاهی است. در این صورت، راحتی ایجاد یک رمز عبور جدید را توضیح دهید و آنها را در فرآیند ایجاد راهنمایی کنید.
همگامسازی جزئیات کلید عبور با ارائهدهنده خدمات با استفاده از سیگنالها
برای اطمینان از ثبات و تجربه کاربری بهتر، طرف اعتماد (RP) شما میتواند از API سیگنالهای WebAuthn برای ارسال بهروزرسانیها در مورد اعتبارنامهها و اطلاعات کاربر به ارائهدهنده کلید عبور استفاده کند.
برای مثال، برای اینکه فهرست ارائهدهندهی کلید عبور از کلیدهای عبور کاربر دقیق باشد، اعتبارنامهها را در backend همگامسازی کنید. میتوانید اعلام کنید که دیگر یک کلید عبور وجود ندارد تا ارائهدهندگان کلید عبور بتوانند کلیدهای عبور غیرضروری را حذف کنند.
به همین ترتیب، میتوانید در صورت بهروزرسانی نام کاربری یا نام نمایشی کاربر در سرویس خود، آن را علامت دهید تا اطلاعات کاربر که توسط ارائهدهنده رمز عبور نمایش داده میشود (مثلاً در پنجرههای انتخاب حساب) بهروز بماند.
برای کسب اطلاعات بیشتر در مورد شیوههای مناسب برای حفظ ثبات کلیدهای عبور، به بخش «حفظ ثبات کلیدهای عبور با اعتبارنامهها در سرور شما با استفاده از API سیگنال» مراجعه کنید.
عامل دوم را درخواست نکنید
کلیدهای عبور، محافظت داخلی و قدرتمندی در برابر تهدیدات رایج مانند فیشینگ ارائه میدهند. بنابراین، عامل احراز هویت دوم ارزش امنیتی قابل توجهی اضافه نمیکند. در عوض، یک مرحله غیرضروری را برای کاربران در هنگام ورود به سیستم ایجاد میکند.
چک لیست
- به کاربران اجازه دهید از طریق تکمیل خودکار فرم، با رمز عبور وارد سیستم شوند.
- وقتی اعتبارنامهی منطبق با کلید عبور در backend یافت نشد، سیگنال ارسال کنید.
- اگر کاربر پس از ورود به سیستم هنوز رمز عبوری ایجاد نکرده است، از او بخواهید که به صورت دستی رمز عبور ایجاد کند.
- پس از ورود کاربر با رمز عبور (و یک عامل دوم)، یک کلید عبور (ایجاد مشروط) به طور خودکار ایجاد میشود.
- اگر کاربر با کلید عبور بین دستگاهی وارد سیستم شده باشد، درخواست ایجاد کلید عبور محلی را میدهد.
- فهرست کلیدهای عبور موجود و جزئیات بهروز شده کاربر (نام کاربری، نام نمایشی) را پس از ورود به سیستم یا هنگام بروز تغییرات، به ارائهدهنده خدمات اطلاع دهید.