یک برنامه‌ی Authentication ساده با فلاتر و پارس‌سرور

مقدمه

در این نوشته قرار است تا یک برنامه‌ی Authentication با استفاده از فریم‌ورکِ فلاتر بنویسیم که داده‌هایش را روی دیتابیس mongoDB در بک‌اندِ پارس‌سرور ذخیره می‌کند. در اینجا بک‌اند مورد استفاده‌مان را از سایت back4app گرفته‌ایم. توجه کنید الزامی ندارد حتماً از این سایت استفاده کنیم و می‌توانیم بک‌اند مورد نظرمان را روی هر زیرساختی که می‌خواهیم، بالا بیاوریم.

این برنامه‌ی Authentication ما، شامل صفحات «ایجاد حساب کاربری»، «ورود»، «بازیابی رمز عبور» و «خانه» است. چنانچه کاربر از قبل وارد برنامه شده باشد، بدون نیاز به واردکردن مشخصات، مستقیماً به صفحه‌ی خانه هدایت می‌شود و در غیر این صورت، ابتدا به صفحه‌ی ورود می‌رود تا مشخصاتش را وارد کند، سپس وارد صفحه‌ی خانه می‌شود.

پیشنیاز

پیشنیاز فهمیدن این نوشته، آن است که آشنایی مختصری با فریم‌ورک فلاتر و زبان دارت داشته باشیم. هم‌چنین آشنایی با معماری client-serverای به درک بهتر ماجرا کمک می‌کند. به علاوه برای شروع، باید یک پروژه‌ی جدید فلاتر (به عنوان کلاینت) ایجاد کرده باشیم تا بتوانیم درس‌نامه را روی آن ادامه دهیم.

در نهایت

کد فلاتری که در پایان این نوشته به آن می‌رسیم، در این مخزن آمده است.


ایجاد بک‌اندِ پارس‌سرور در سایت back4app

همانطور که گفتیم برای ساختن برنامه‌ی Authentication از معماری client-serverای استفاده می‌کنیم. کلاینتمان، پروژه‌ی فلاتری‌ست که در پیشنیاز به آن اشاره کردیم و سرورمان، بک‌اند پارس‌سروری‌ست که در ادامه قرار است ایجاد کنیم.

برای ساختن بک‌اند پارس‌سرور در داشبورد سایت back4app، روی گزینه‌ی Build new app کلیک می‌کنیم:

محیط اولیه‌ی داشبورد سایت back4app پس از ثبت‌نام
محیط اولیه‌ی داشبورد سایت back4app پس از ثبت‌نام

سپس در صفحه‌ی ایجاد شده، نام بک‌اند و نوع دیتابیس آن را تعیین می‌کنیم. به طور پیش‌فرض، دیتابیس بر روی mongoDB است و نیاز نیست تغییرش دهیم. اسم بک‌اند را هم flutter_parse انتخاب می‌کنیم:

پس از ساخت بک‌اند، در داشبورد سایت back4app، یک بک‌اند جدید با نام flutter_parse به صورت زیر به مجموعه‌ی بک‌اند‌های شما اضافه خواهد شد:

نصب parse_server_sdk_flutter

برای ارتباط پروژه‌ی فلاترمان با پارس‌سرور، از SDKای که خود پارس‌سرور برای فریم‌ورک فلاتر آماده کرده، استفاده می‌کنیم. منظور از SDK، مجموعه‌ای از تابع‌ها و ابزارهای مختلف است که همگی در یک بسته‌ی آماده جمع شده‌اند. پارس‌سرور برای دسترسی مستقیم از فلاتر، مجموعه‌ای از این تابع‌ها و ابزارهای مختلف را به زبان دارت آماده کرده که در این پروژه از آن‌ها استفاده می‌کنیم.

برای معرفی این مجموعه از توابع و ابزارها به پروژه‌ی فلاترمان، در فایل pubspec.yaml و در قسمت dependencies، آخرین نسخه از parse_server_sdk_flutter را اضافه می‌کنیم. در زمان نوشته‌شدنِ این متن، نسخه‌ی ۳.۰.۰ آخرین نسخه بود:

dependencies:
  flutter:
    sdk: flutter
  parse_server_sdk_flutter: ^3.0.0

سپس باید دستور flutter pub get را در ترمینال وارد کنیم تا SDK ی اضافه‌شده روی پروژه نصب شود. برای این کار حتماً باید از فیلترشکن یا شکن استفاده کنیم. پس از این کار می‌توانیم مشابه سایر پکیج‌ها، SDK ی پارس‌سرور را داخل فایل‌های پروژه‌ی فلاترمان به صورت زیر فراخوانی کنیم:

import 'package:parse_server_sdk_flutter/parse_server_sdk.dart';

اتصال پروژه‌ی فلاتر به بک‌اند پارس‌سرور

برای ارتباط پروژه‌ی فلاتر با بک‌اندِ پارس‌سرور، احتیاج داریم این بک‌اند را به پروژه‌ی فلاترمان بشناسانیم. برای این کار باید مشخصات پارس‌سرور را به دست آوریم. برای دیدن این مشخصات، داخل داشبورد سایت back4app، روی گزینه‌ی Server Setting از بک‌اندِ flutter_parse که در قسمت‌های قبلی ساختیم، کلیک می‌کنیم:

بعد از آن در بخش Core Setting بر روی گزینه‌ی Setting کلیک می‌کنیم:

سپس در صفحه‌ی زیر، AppId و ClientId را یادداشت می‌کنیم:

حالا در پروژه‌ی فلاتر و در همان تابع main، تابع initialize از کلاس Parse را فراخوانی می‌کنیم. برای فراخوانی این تابع احتیاج به سه مقدار AppId و ClientId و ServerUrl داریم. دو مقدار AppId و ClientId را که همین چند لحظه پیش به دست آوردیم، مقدار ServerUrl را هم برابر https://parseapi.back4app.com قرار می‌دهیم:

import 'package:parse_server_sdk_flutter/parse_server_sdk.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  final keyApplicationId = 'FAEpooWsdL1NRHxbolOAxa39xl6Y9MsdC2dw4paI';
  final keyClientKey = 'mjrkLjcWBwQIc9FbeuF93LZf3sh7EWhhJ0oQAY1o';
  final keyParseServerUrl = 'https://parseapi.back4app.com';

  await Parse().initialize(keyApplicationId, keyParseServerUrl,
      clientKey: keyClientKey, debug: true);

  runApp(MyApp());
}

تبریک می‌گویم! حالا می‌توانید به راحتی از SDKی پارس‌سرور استفاده کنید و مستقیماً با بک‌اندِ parse_flutter ارتباط برقرار کنید!


اولین صفحه؟

پس از تعیین‌کردن تنظیمات اولیه‌ی ارتباط با بک‌اند، شروع به کدزنی می‌کنیم. می‌دانیم اولین صفحه، با توجه به این تعیین می‌شود که آیا کاربر از قبل وارد برنامه شده بوده یا نه.

برای راحتی کار، در SDKی پارس‌سرور کلاسی وجود دارد که با آن می‌توانیم عملیات‌های مربوط به کاربر فعلی را مدیریت کنیم. این کلاس ParseUser است که در ادامه قرار است بیشتر با آن آشنا شویم.

با استفاده از این کلاس و کمک‌گرفتن از مفهوم Future و FutureBuilder در فلاتر، می‌توانیم تشخیص دهیم آیا کاربر از قبل وارد شده است یا نه:

Future<bool> hasUserLogged() async {
  //Get current user if exist
  ParseUser currentUser = await ParseUser.currentUser() as ParseUser;
  if (currentUser == null) {
    return false;
  }
  //Checks whether the user's session token is valid
  final ParseResponse? parseResponse =
      await ParseUser.getCurrentUserFromServer(
          currentUser.get<String>('sessionToken')!);

  if (!parseResponse!.success) {
    //Invalid session. Logout
    await currentUser.logout();
    return false;
  } else {
    return true;
  }
}

در تابع hasUserLogged ابتدا کاربر فعلی (ParseUser.currentUser) را صدا می‌زنیم تا ببینیم آیا از قبل بر روی حافظه‌ی لوکال دستگاه کاربری ذخیره وجود داشته یا نه. توجه کنید پارس‌سرور بدون این که ما در جریان باشیم، بر روی حافظه‌ی دستگاه تغییراتی را انجام می‌دهد و اطلاعاتی را ذخیره می‌کند.

در مرحله‌ی بعد، نشست (session) کاربر را چک می‌کنیم تا ببینیم اگر نشست کاربر منقضی شده بود، به صفحه‌ی ورود برویم. توجه کنید که در اینجا، اطلاعات را از سرور دریافت می‌کنیم و به همین خاطر، به جای تابع currentUser که در مرحله‌ی قبل استفاده کردیم، از تابع getCurrentUserFromServer استفاده می‌کنیم.

تکه‌کد بالا منطق کد بود. ظاهری که بر روی صفحه نمایش داده می‌شود در تابع build از کلاس MyApp تعیین می‌‌شود.

در خط ۶۸ و ۷۱ با توجه به نتیجه‌ی عملیات تابع hasUserLogged، تصمیم می‌گیریم که آیا به صفحه‌ی خانه یا صفحه‌ی ورود برویم.

صفحه‌ی ورود

به طور پیش‌فرض برای وارد شدن احتیاج به نام‌کاربری و رمز‌عبور داریم. در صفحه‌ی ورود از این برنامه‌ی Authentication هم جایی برای وارد کردن این دو مشخصه وجود دارد. تابعی که وظیفه‌ی برقرارکردن ارتباط با بک‌اند برای بررسی صحت مشخصات را بر عهده دارد، تابع doUserLogin است:

void doUserLogin() async {
  final username = controllerUsername.text.trim();
  final password = controllerPassword.text.trim();

  final user = ParseUser(username, password, null);

  var response = await user.login();

  if (response.success) {
    navigateToUser();
  } else {
    Message.showError(
        context: context, message: response.error!.message, onPressed: () {});
  }
}

در این تابع، با استفاده از کلاس ParseUser (که پیش‌تر آن را معرفی کرده بودیم) یک آبجکتِ user می‌سازیم. آبجکت‌های این کلاس خود دارای تابع‌هایی از جمله login ،signUp ،logout و requestPasswordReset است که به ما در عملیات ورود، خروج و ساخت حساب کاربری کمک می‌کند. در اینجا هم برای ورود، نام‌کاربری و رمز عبور را از ورودی می‌گیریم و با کمک تابع user.login، با بک‌اند ارتباط برقرار می‌کنیم تا از صحت اطلاعات وارد شده مطمئن شویم. در صورت درست‌بودن اطلاعات به صفحه‌ی کاربر هدایت می‌شویم و در غیر این صورت پیغام خطا بر روی صفحه نمایان خواهد شد.

در صفحه‌ی ورود علاوه بر دکمه‌ی ورود، دکمه‌هایی برای رفتن به صفحات بازیابی رمز عبور و ایجاد حساب کاربری هم وجود دارد.

آبجکت همه‌کاره!

عملیات‌های ثبت‌نام و بازیابی رمز عبور را هم می‌توان به وسیله‌ی آبجکت user از کلاس ParseUser انجام داد. برای ثبت‌نام، پس از گرفتن نام‌کاربری، رمزعبور و ایمیل، با کمک تابع ParseUser.createUser می‌توان یک حساب کاربری جدید ایجاد کرد و پس از ایجاد حساب جدید، به وسیله‌ی تابع signUp، آن کاربر را ثبت‌نام کرد.

صفحه‌ی ورود
صفحه‌ی ورود

هم‌چنین در صفحه‌ی بازیابی رمز عبور با کمک تابع requestPasswordReset می‌توان درخواست بازیابی رمز عبور را به بک‌اند ارسال کرد و منتظر ماند تا ایمیل بازیابی برایمان ارسال شود.

صفحه‌ی بازیابی رمز عبور
صفحه‌ی بازیابی رمز عبور

در صفحه‌ی خانه نیز، برای نمایش نام‌کاربریِ کاربری که با آن وارد شده‌ایم، ابتدا به کمک تابع currentUser، کاربر فعلی را می‌گیریم:

currentUser = await ParseUser.currentUser() as ParseUser;

و سپس مشخصه‌ی username آن را استفاده می‌کنیم (currentUser.username).

صفحه‌ی خانه
صفحه‌ی خانه

برای خارج‌شدن از حسابِ کاربر فعلی هم از تابع logout از همان آبجکتِ user از کلاس ParseUser استفاده می‌کنیم. توجه کنید که حتما باید از تابع logout استفاده کنیم تا اطلاعاتی که به صورت لوکال بر روی دستگاهمان ذخیره شده به‌روز شوند:

var response = await currentUser.logout();

اگر از این تابع استفاده نمی‌کردیم و با زدن دکمه‌ی خروج صرفاً به صفحه‌ی ورود منتقل می‌شدیم، اطلاعات کاربر قبلی روی حافظه‌ی لوکالی که پارس‌سرور از آن استفاده می‌کند، ذخیره باقی می‌ماند.


منبع

این نوشته در اصل خلاصه‌ای از مطالب بیان شده در سایت back4app برای نحوه‌ی استفاده از SDKی فلاترِ پارس‌سرور است. می‌توانید محتوای اصلی را از اینجا، اینجا، اینجا، اینجا، اینجا و اینجا مشاهده کنید. کدهای استفاده شده در این نوشته نیز همان با کمی تغییر، کدهای به کار رفته در سایت back4app هستند.