logo أكاديمية أكسبورت للتطوير والبرمجة logo-alt أكاديمية أكسبورت للتطوير والبرمجة
تسجيل الدخول  أو  تسجيل حساب
  • الرئيسية
  • دروس برمجية
    • HTML
    • CSS
    • ANGULAR
    • IONIC / MOBILE
    • YII 2.0
    • Odoo /epen ERP
    • مواضيع متنوعة
  • مفاهيم برمجية
  • من نحـن
  • اتصل بنا

ربط صفحة login مع api

ionic login with jwt

بعد الانتهاء من هدا الدرس سيصبح بامكانك تسجيل الدخول من الموقع (مشروع Yii المحلي) عبر المتصفح وبامكانك تسجيل الدخول أيضا من خلال تطبيق ionic

Mobile development الصفحة الرئيسية

في الدروس السابقة قمنا بانشاء صفحة login بالتطبيق ثم قمنا بعد بالتوجه نحو جهة ال server وأنشئنا الكونترولر UserController الدي يقوم بمعالجة بيانات تسجيل الدخول وتوليد token  وقمنا بتجربة ارسال البيانات عن طريق POSTMAN ونجحنا بمعالجة البيانات .

الأن سنعمل قليلا على التطبيق أي بجهة الكلاينت Client وسوف نوجه التطبيق نحو الخادم ونرسل اليه بيانات الدخول ليقوم هو بدوره بارسال ال token ونحن نحفظه بالداكرة الداخلية للتطبيق localstorage كما وضحنا بالدرس الماضي 

محتوى الدرس

- انشاء دالة submitted بصفحة login.ts التي ستقوم بالتقاط البيانات المدخلة وتحويلها الى ملف الخدمة authentication.ts

- انشاء دالة login بملف الخدمة authentication.ts التي ستقوم بالاتصال بالخادم (API) وترسل له البيانات وتنتظر الرد

 

تفاصيل الدرس

أول شيء سنتوجه الى صفحة login.ts من أجل انشاء دالة submitted  

onSubmit(dataForm: any) {
    this._submitted = true;  //handler مقبض يعلن عن انه تم الضغط على زر الدخول
    let data:any = { // بناء كائن يمثل بيانات تسجيل الدخول ثم ارسالها الى ملف الخدمة
        username: dataForm.username,
        password: dataForm.password,
    }

    let loading = this.loadingCtrl.create({  // انشاء نافدة انتظار
      content: 'Please wait...'
    });    
    loading.present();

    this.authenticationProvider.login(data)
      .subscribe(
          result => {
            let response:any = result;  
            setTimeout(() => {  // غلق نافدة الانتظار
              loading.dismiss();
            }, 500);
            this.authenticationProvider.saveToken(response.access_token).then( // دالة ننشئها بملف الخدمة وضيفتها حفظ الرمز توكن
              res=>{
                
                this.navCtrl.setRoot(ProfilePage); // بعد حفظ التوكن نقوم بتوجيه المستخدم الى صفحة البروفايل
            }); 
          },
          error => {
            setTimeout(() => {  // غلق نافدة الانتظار
              loading.dismiss();
            }, 500);

            if(error.status==422){
              this.errorMessage = 'Incorrect username or password.';
              console.log(error);
            }

          }
    );
  }

قم بعمل import الى اللوازم التي نحتاجها وهي

- صفحة profile

- ملف الخدمة المسؤول عن authentication

- مكتبة تدير نوافد الانتظار loading 

 

import { ProfilePage } from '../profile/profile'; //+
import { AuthenticationProvider } from '../../providers/authentication/authentication';
import {LoadingController } from 'ionic-angular';
constructor(
   //....   
     public authenticationProvider: AuthenticationProvider,
     public loadingCtrl: LoadingController,
   //....
  ) {
  //....
}

 

ليصبح ملف login.ts كاملا بالشكل التالي .

import { Component } from '@angular/core';
import { NavController, NavParams, LoadingController } from 'ionic-angular';
import { AuthenticationProvider } from '../../providers/authentication/authentication';
import { FormControl, FormGroup, FormBuilder, Validators } from '@angular/forms'; 
import { ProfilePage } from '../profile/profile'; //+
import { HomePage } from '../home/home';
import { RegisterPage } from '../register/register';

/**
 * Generated class for the LoginPage page.
 *
 * See https://ionicframework.com/docs/components/#navigation for more info on
 * Ionic pages and navigation.
 */

@Component({
  selector: 'page-login',
  templateUrl: 'login.html',
})
export class LoginPage {

  public _loginForm:FormGroup;
  public _submitted:boolean = false;
  public errorMessage:string=null;

  constructor(
    public navCtrl: NavController,
    public navParams: NavParams,
    public authenticationProvider: AuthenticationProvider,
    public _formBuilder:FormBuilder,
    public loadingCtrl: LoadingController,

    ) {
      this.createForm(); // تمهيد حقول فورم تسجيل الدخول مباشرة بعد اقلاع الصفحة
  }

  ionViewDidLoad() {
    console.log('ionViewDidLoad LoginPage');
  }


  public createForm(){
    this._loginForm = this._formBuilder.group({
      username: ['', Validators.required],
      password: ['', Validators.compose([Validators.required, Validators.minLength(4)])],
    });
}


  homePage(){ // في اعلى صفحة تسجيل الدخول ستجد زر يوجهك نحو الصفحة الرئيسية
    this.navCtrl.push(HomePage); 
  }

  registerPage(){ // الزر الدي يوجهك نحو صفحة تسجيل الدخول
    this.navCtrl.push(RegisterPage); 
  }

  onSubmit(dataForm: any) {
    this._submitted = true;  //handler مقبض يعلن عن انه تم الضغط على زر الدخول
    let data:any = { // بناء كائن يمثل بيانات تسجيل الدخول ثم ارسالها الى ملف الخدمة
        username: dataForm.username,
        password: dataForm.password,
    }

    let loading = this.loadingCtrl.create({  // انشاء نافدة انتظار
      content: 'Please wait...'
    });    
    loading.present();

    this.authenticationProvider.login(data)
      .subscribe(
          result => {
            let response:any = result;  
            setTimeout(() => {  // غلق نافدة الانتظار
              loading.dismiss();
            }, 500);
            this.authenticationProvider.saveToken(response.access_token).then( // دالة ننشئها بملف الخدمة وضيفتها حفظ الرمز توكن
              res=>{
                
                this.navCtrl.push(ProfilePage); // بعد حفظ التوكن نقوم بتوجيه المستخدم الى صفحة البروفايل
            }); 
          },
          error => {
            setTimeout(() => {  // غلق نافدة الانتظار
              loading.dismiss();
            }, 500);

            if(error.status==422){
              this.errorMessage = 'Incorrect username or password.';
              console.log(error);
            }

          }
    );
  }

}

 

بقيت خطوة واحدة وهي انشاء  دالتين login  و داالة حفظ ال token  بملف الخدمة authentication.ts 

 

تقوم دالة login بالربط بين الخادم والتطبيق  حيث تقوم باستقبال البيانات من مكون الصفحة و تمررها الى الخادم وتلتقط رد الخادم على طلبها ثم تحول النتائج الى مكون الصفحة الى  دالة submitted 

تقوم دالة saveToken بحفظ ال token بالداكرة الداخلية للتطبيق من اجل استعماله لاحقا من أجل منح التصريح authorization للصفحات الامنة

لانشاء دالة login و saveToken نتوجه الى ملف الخدمة AuthenticationProvider الموجود بالمسار src/providers/authentication/authentication.ts

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders} from '@angular/common/http';
import { map } from 'rxjs/operators';
import { Storage } from '@ionic/storage';  

@Injectable()
export class AuthenticationProvider {

   public baseUrl = 'http://yii-application/api/v1';
  //public baseUrl = 'http://localhost/yii-application/api/v1';
  
  constructor(
            public httpClient: HttpClient,         
            public storage : Storage,
    ) { }


  // دالة الاتصال بالخادم  التي تربط الخادم بالتطبيق
  login(data:any){  
    // بيانات الهيدر يمكنك تمرير ماتشاء بالهيدر الى الخادم
    const httpOptions = {  
      headers: new HttpHeaders({
          'charset':  'UTF-8',
      })
    };

    let url:string = this.baseUrl+'/user/login';
    return this.httpClient
      .post(url,data ,httpOptions)             // عملية post
      .pipe(
          map((response) => {
                return response;                  // تحويل النتيجة الى المكون
          })
    );
  }

  // دالة حفظ كود توكن
  saveToken(token: string): Promise<any> {
    return this.storage.set('token',token);
  }
 


}

 

الان انتهينا وكل شيء جاهز . ولكن قد يصادفك خطأ عند التشغيل فربما لن تعمل معك النتائج  فعندما تجرب الدخول بالبيانات التي استعملتها في postman ستلاحظ وجود خطأ في ال inspector يقول

{name: "Internal Server Error", message: "An internal server error occurred.", code: 0, status: 500}
code: 0
message: "An internal server error occurred."
name: "Internal Server Error"
status: 500

من اجل استعراض كود الخطأ يجب عليك التأكد من تنشيط تعليمة debug mode ودلك عن طريق الملف api/index.php في بداية الملف قم بتفعيل التعليمة التالية

defined('YII_DEBUG') or define('YII_DEBUG', true); // يجب تفعيل هده التعليمة حتى تتمكن من استعراض الاخطاء بالمتصفح

بعد دلك سيعرض لك سبب الخطأ  .

هدا الخطأ سببه هو ان الخادم قد تلقى بيانات على شكل POST   .الى هنا كل شيء جيد .ولكنه لم يتمكن من تحليلها ولم يفهمها  لأن العميل أرسل  البيانات من نوع JSON .لدلك لم يتمكن الخادم من معالجتها .وعندما مرر بيانات فارغة الى الموديل وقع الخطأ .

 

 

وسبب دلك هو انه يجب أن تفهم أن تطبيقات ionic  تقوم بارسال البيانات الى الخادم على شكل json  بشكل افتراضي .  بالتالي الخادم أدرك انه يوجد استقبال لبيانات دات نمط POST ولكنها لم تأتي كمصفوفة مثلما نفعل في صفحات الويب العادية وانما استقبلها على شكل json ولكن الخادم غير معد لفهم وتحليل طلبات  بها بيانات json .

لدلك  نحن أمام أحد الحلين

  1. اما أن نغير شكل البيانات التي سيقووووم العميل بارسالها (التطبيق) الى النمط الدي يفهمه الخادم (طلب كلاسيكي مرفق بمصفوفة POST) ونتخلى عن ارسال الطلب بال json  وبهدا عندما يستقبل الخادم البيانات يتمكن من تحليلها وكأنها بيانات قادمة من متصفح أو ماشابه دلك
  2. واما أن نعد الخادم نفسه ونخبره بأن هده البيانات التي سيرسلها العميل هي من نوع json  فادا وجدتها على هدا الشكل فقم بمعالجتها. أي أننا نعطي تصريح للخادم بان يعالج البيانات على شكل json

 

سنتطرق الى الحلين معا ولكن الحل المفضل هو الحل الثاني بالطبع .

وقبل دلك لابد من فهم معنى بيانات الهيدر  Header

 

ماهو الهيدر Header

هو وسيلة تخاطب مخفية تعبر عن معلومات تفيد كلاً من العميل والخادم . يمكن ان نقول انها مصفوفة تمرر من خلالها مجموعة من المعلومات البرمجية بين الخادم والعميل

تنقسم بيانات الهيدر الى مصفوفتين وهي :

Header Requests: هي المعلومات التي يتم إرسالها من العميل (التطبيق أو المتصفح ..) إلى الخادم (Server).

Header Responses  : هي المعلومات التي يتم إرسالها من الخادم إلى العميل.

 

الحل الأول

نستطيع ان نحدد نوعية الطلب الدي نريد ارساله  من العميل الى الخادم من خلال  ال headers . مثلما وضحنا أن headers هي وسيلة تخاطب بين الخادم والعميل تحتوى على بيانات request/response

حيث سنرسل البيانات على شكل multipart/form-data أو  application / x-www-form-urlencoded

  const httpOptions = {
      headers: new HttpHeaders({
          'Content-Type':  'multipart/form-data',
          'charset':  'UTF-8',
      })
    };

 

application / x-www-form-urlencoded :هدا النوع من المحتوى ليس بالحل الجيد لإرسال كميات كبيرة من البيانات من نوع binary (بياناتbinary هي بيانات غير أبجدية non-alphanumeric) أو ارسال نص يحتوي على أحرف غير ASCII.

multipart / form-data هدا النوع من المحتوى يستخدم في ال forms التي تحتوي على ملفات أو بيانات غير ASCII وبيانات ثنائية binary.

 

الحل الثاني 

نقوم باعداد الخادم نفسه على معالجة البيانات التي يستقبلها بال json . والطريقة بسيطة ماعلينا سوى التوجه الى ملف الاعدادات api/config/main.php واضافة  تعليمة ال request بداخل مصفوفة components 

'components' => [
   // ....
   'request' => [
            'enableCsrfValidation' => false,
            'parsers' => [
                'application/json' => 'yii\web\JsonParser',                 // To enable parsing for JSON requests
                'X-Requested-With' => 'yii\httpclient\UrlEncodedParser',
                'multipart/form-data' => 'yii\web\MultipartFormDataParser',
            ]
        ],
   // ....
],

طبعا الحل الثاني هو الأنسب لأن الحل الأول ضعيف وقد تجد عدة مشاكل خصوصا عندما تود ارسال بيانات كبيرة أو غير أبجدية مخالفة لنمط ASCII 

 كما بيانات json اسرع بالقراءة والتحليل بالمقارنة مع بيانات application / x-www-form-urlencoded  أيضا  ال api يفضل ان يستقبل بيانات json لانه لو حدث واردت ادماج مشروعك بتطبيق اخر قد تجده لايدعم تقنية application / x-www-form-urlencoded  في حين أغلب  اللغات اليوم تدعم json 

 

بعد حفظ  كافة البيانات واضافة  request بملف اعدادات المشروع  (api/config/main.php) بالمصوفة component  .

قم بتشغيل مشروع ionic عبر التعليمة ionic serve --poll=2000 

قم بالتوجه نحو صفحة login

قم بفتح inspector عن طريق الزر F12 ثم توجه الى قسم network 

قم بملأ الحقول username +  password  

أكد تسجيل الدخول وتحقق من ارجاع كود token وتحويلك الى profile  كما هو مبين بالصورة

 

 

ادا  صادفتك رسالة تقول أن البيانات المدخلة غير صحيحة أو وجدت خطأ غريب ما .ضع مشكلتك بخانة التعليق لمساعدتك .أيضا بامكانك التحقق من الاتي

تأكد من فتح برنامج السرفر المحلي apache

تحقق من وجود اسم المسخدم وكلمة المرور صحيحة بقاعدة البيانات. وادا لم تعرف كيف تتحقق فما عليك سوى اتباع المسار التالي وتسجيل حساب جديد 

http://localhost/yii-application/frontend/web/index.php?r=site%2Fsignup
or
http://yii-application/frontend/web/index.php?r=site%2Fsignup

 

أو توجه نحو phpmyadmin => قاعدة البيانات المربوطة بالمشروع => نسخ هدا الـ query 

INSERT INTO `user` (`id`, `username`, `auth_key`, `password_hash`, `password_reset_token`, `email`, `status`, `created_at`, `updated_at`, `last_login_ip`, `last_login_at`, `access_token_expired_at`) VALUES (NULL, 'exportdeveloper', 'HlcASovqqZV0ZAaR1WrRynVP75Y_trdm', '$2y$13$xY/lBBFAYzmY7uKbw.mCGO7zzibPuEYzSDh8cw2Q0knTNqCREeiLO', NULL, 'contact@exportdeveloper.com', '10', '1548681108', '1549202800', '127.0.0.1', '2019-02-03 15:06:40', '2019-02-04 14:06:40')

ثم تدخل البيانات التالية بصفحة login

username : exportdeveloper
password : azeazeaze

كود المشروعين ionic + api سنضعه بالدرس المقبل .

 

ماهو تقييمك للدرس
تقييم الزوار للدرس
الدرس السابق : JWT Authentication with Ionic الدرس القادم : تحديث القائمة menu بعد تسجيل الدخول والتعرف على الأحداث
  • قم بتسجيل الدخول للتعليق : تسجيل الدخول أو تسجيل عضوية
الدروس المقبلة
  • تحديث القائمة menu بعد تسجيل الدخول والتعرف على الأحداث
    refresh side menu after login with events
  • ربط صفحة profile مع api وجلب البيانات من الخادم
    get data from api
  • تسجيل خروج المستخدم Logout
    ionic logout - destroy JWT Token
  • ربط صفحة register مع api
    ionic register user
ANGULAR
  • المستوى 101 من دورة angular
  • المستوى 102 من دورة angular
  • الدورة 103 من angular
Mobile Development
دورة تطوير تطبيق موبايل

sitemap - Exportdeveloper Academy © 2019 All rights reserved