تمرين - إضافة مصادقة المستخدم

مكتمل

يحتاج تطبيق الويب بقائمة التسوق خاصتك إلى مصادقة المستخدم. في هذا التمرين، ستنفذ تسجيل الدخول والخروج في تطبيقك، وعرض حالة تسجيل دخول المستخدم الحالية.

في هذا التمرين، ستكمل الخطوات التالية:

  1. تثبيت واجهة سطر أوامر Static Web Apps للتطوير المحلي.
  2. تشغيل التطبيق واجهة برمجة التطبيقات محليًا مع محاكاة المصادقة المحلية.
  3. إضافة أزرار تسجيل الدخول للعديد من موفري مصادقة.
  4. إضافة زر تسجيل الخروج إذا سجل المستخدم الدخول.
  5. عرض حالة تسجيل دخول المستخدم.
  6. اختبار سير عمل المصادقة محليًا.
  7. توزيع التطبيق المحدث.

الاستعداد للتنمية المحلية

تعد واجهة سطر أوامر Static Web Apps، المعروف أيضًا باسم واجهة سطر أوامر SWA، أداة تطوير محلية تتيح لك تشغيل تطبيق الويب وواجهة برمجة التطبيقات خاصتك محليًا ومحاكاة خوادم المصادقة والتخويل.

  1. افتح وحدة طرفية على جهاز الكمبيوتر الخاص بك.

  2. ثبت SWA CLI عبر تشغيل الأمر التالي.

    npm install -g @azure/static-web-apps-cli
    

تشغيل التطبيق محليًا

شغّل الآن التطبيق وواجهة برمجة التطبيقات محليًا باستخدام خادم التطوير. بهذه الطريقة ستتمكن من رؤية تغييراتك واختبارها، أثناء تنفيذك لها في التعليمات البرمجية.

  1. افتح المشروع في تعليمة Visual Studio.

  2. في Visual Studio Code، افتح لوحة الأوامر بالضغط على F1.

  3. اكتب "Terminal: Create New Integrated Terminal" وحددها.

  4. انتقل إلى مجلد إطار عمل الواجهة الأمامية المفضل، كما يلي:

    cd angular-app
    
    cd react-app
    
    cd svelte-app
    
    cd vue-app
    
  5. شغَّل تطبيق عميل الواجهة الأمامية باستخدام خادم تطوير.

    npm start
    
    npm start
    
    npm run dev
    
    npm run serve
    

    اترك هذا الخادم قيد التشغيل في الخلفية. والآن شغّل واجهة برمجة التطبيقات ومُحاكي خادم المصادقة باستخدام SWA CLI.

  6. في Visual Studio Code، افتح لوحة الأوامر بالضغط على F1.

  7. اكتب "Terminal: Create New Integrated Terminal" وحددها.

  8. شغل CLI SWA عن طريق تشغيل الأمر التالي:

    swa start http://localhost:4200 --api-location ./api
    
    swa start http://localhost:3000 --api-location ./api
    
    swa start http://localhost:5000 --api-location ./api
    
    swa start http://localhost:8080 --api-location ./api
    
  9. استعرض إلى http://localhost:4280.

يختلف المنفذ الأخير الذي يستخدمه واجهة سطر أوامر SWA عن المنفذ الذي رأيته من قبل، لأنه يستخدم وكيلًا عكسيًا لإعادة توجيه الطلبات إلى المكونات الثلاثة المختلفة:

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

Screenshot of the Static Web Apps CLI architecture.

الآن دع التطبيق يعمل بينما تُعدل التعليمات البرمجية.

احصل على حالة تسجيل دخول المستخدم

في البداية أنت بحاجة إلى الوصول إلى حالة تسجيل دخول المستخدم عن طريق إجراء استعلام /.auth/me في العميل.

  1. إنشاء الملف angular-app/src/app/core/models/user-info.ts وأضف التعليمات البرمجية التالية لتمثيل الواجهة لمعلومات المستخدم.

    export interface UserInfo {
      identityProvider: string;
      userId: string;
      userDetails: string;
      userRoles: string[];
    }
    
  2. حرر الملف angular-app/src/app/core/components/nav.component.ts وأضف هذا الأسلوب في الفئة NavComponent.

    async getUserInfo() {
      try {
        const response = await fetch('/.auth/me');
        const payload = await response.json();
        const { clientPrincipal } = payload;
        return clientPrincipal;
      } catch (error) {
        console.error('No profile could be found');
        return undefined;
      }
    }
    
  3. أنشئ خاصية فئة جديدة userInfo، وخزّن نتيجة الدالة غير المتزامنة getUserInfo() عند تهيئة المكوّن. نفّذ الواجهة OnInit وحدّث عبارات الاستيراد لاستيراد OnInit وUserInfo. تُحضر هذه التعليمات البرمجية معلومات المستخدم عند تهيئة المكوّن.

    import { Component, OnInit } from '@angular/core';
    import { UserInfo } from '../model/user-info';
    
    export class NavComponent implements OnInit {
      userInfo: UserInfo;
    
      async ngOnInit() {
        this.userInfo = await this.getUserInfo();
      }
      // ...
    }
    
  1. حرر الملف react-app/src/components/NavBar.js، وأضف التعليمات البرمجية التالية في الجزء العلوي من الدالة. تُحضر هذه التعليمات البرمجية معلومات المستخدم عند تحميل المكوّن وتخزينه في الحالة.

    import React, { useState, useEffect } from 'react';
    import { NavLink } from 'react-router-dom';
    
    const NavBar = (props) => {
      const [userInfo, setUserInfo] = useState();
    
      useEffect(() => {
        (async () => {
          setUserInfo(await getUserInfo());
        })();
      }, []);
    
      async function getUserInfo() {
        try {
          const response = await fetch('/.auth/me');
          const payload = await response.json();
          const { clientPrincipal } = payload;
          return clientPrincipal;
        } catch (error) {
          console.error('No profile could be found');
          return undefined;
        }
      }
    
      return (
      // ...
    
  1. حرر الملف svelte-app/src/components/NavBar.svelte وأضف التعليمات البرمجية التالية في جزء البرنامج النصي. تُحضر هذه التعليمات البرمجية معلومات المستخدم عند تحميل المكوّن.

    import { onMount } from 'svelte';
    
    let userInfo = undefined;
    
    onMount(async () => (userInfo = await getUserInfo()));
    
    async function getUserInfo() {
      try {
        const response = await fetch('/.auth/me');
        const payload = await response.json();
        const { clientPrincipal } = payload;
        return clientPrincipal;
      } catch (error) {
        console.error('No profile could be found');
        return undefined;
      }
    }
    
  1. حرر الملف vue-app/src/components/nav-bar.vue وأضف userInfo إلى كائن البيانات.

     data() {
       return {
         userInfo: {
           type: Object,
           default() {},
         },
       };
     },
    
  2. أضف الأسلوب getUserInfo() إلى قسم methods.

    methods: {
      async getUserInfo() {
        try {
          const response = await fetch('/.auth/me');
          const payload = await response.json();
          const { clientPrincipal } = payload;
          return clientPrincipal;
        } catch (error) {
          console.error('No profile could be found');
          return undefined;
        }
      },
    },
    
  3. أضف خُطاف دورة الحياة createdإلى المكوّن.

    async created() {
      this.userInfo = await this.getUserInfo();
    },
    

    عند إنشاء المكون، تُجلب معلومات المستخدم تلقائيًا.

إضافة أزرار تسجيل الدخول وتسجيل الخروج

ستُصبح معلومات المستخدم undefined في حالة عدم تسجيل الدخول، ولن تكون التغييرات مرئية في الوقت الحالي. حان الوقت لإضافة أزرار تسجيل الدخول لمُقدمي الخدمات المختلفين.

  1. حرر الملف angular-app/src/app/core/components/nav.component.ts لإضافة قائمة موفرين في الفئة NavComponent.

    providers = ['twitter', 'github', 'aad'];
    
  2. أضف الخاصية redirectأدناه، لتسجيل عنوان URL الحالي لإعادة التوجيه بعد تسجيل الدخول.

    redirect = window.location.pathname;
    
  3. أضف التعليمات البرمجية التالية إلى القالب بعد العنصر الأول </nav> لعرض أزرار تسجيل الدخول والخروج.

    <nav class="menu auth">
      <p class="menu-label">Auth</p>
      <div class="menu-list auth">
        <ng-container *ngIf="!userInfo; else logout">
          <ng-container *ngFor="let provider of providers">
            <a href="/.auth/login/{{provider}}?post_login_redirect_uri={{redirect}}">{{provider}}</a>
          </ng-container>
        </ng-container>
        <ng-template #logout>
          <a href="/.auth/logout?post_logout_redirect_uri={{redirect}}">Logout</a>
        </ng-template>
      </div>
    </nav>
    

    في حالة عدم تسجيل دخول المستخدم، فإنك ستعرض زر تسجيل الدخول لكل مُزود. يرتبط كل زر بـ /.auth/login/<AUTH_PROVIDER> ويعين عنوان URL لإعادة التوجيه إلى الصفحة الحالية.

    بخلاف ذلك، إذا سجّل المستخدم الدخول بالفعل، فسيعرض زر تسجيل الخروج ذلك الرابط إلى /.auth/logout، كما سيُعيّن عنوان URL لإعادة التوجيه للصفحة الحالية.

ينبغي أن تشاهد هذا الآن في مستعرضك.

Screenshot of the Angular web app with login buttons.

  1. حرر الملف react-app/src/components/NavBar.js لإضافة قائمة بالموفرين في الجزء العلوي من الدالة.

    const providers = ['twitter', 'github', 'aad'];
    
  2. أضف المتغير التالي redirect أسفل المتغير الأول لالتقاط URL الحالي لإعادة التوجيه بعد تسجيل الدخول.

    const redirect = window.location.pathname;
    
  3. أضف التعليمات البرمجية التالية إلى قالب JSX بعد العنصر الأول </nav> لعرض أزرار تسجيل الدخول والخروج.

    <nav className="menu auth">
      <p className="menu-label">Auth</p>
      <div className="menu-list auth">
        {!userInfo &&
          providers.map((provider) => (
            <a key={provider} href={`/.auth/login/${provider}?post_login_redirect_uri=${redirect}`}>
              {provider}
            </a>
          ))}
        {userInfo && <a href={`/.auth/logout?post_logout_redirect_uri=${redirect}`}>Logout</a>}
      </div>
    </nav>
    

    في حالة عدم تسجيل دخول المستخدم، فإنك ستعرض زر تسجيل الدخول لكل مُزود. يرتبط كل زر بـ /.auth/login/<AUTH_PROVIDER> ويعين عنوان URL لإعادة التوجيه إلى الصفحة الحالية.

    بخلاف ذلك، إذا كان المستخدم قد سجل الدخول بالفعل، فستعرض زر تسجيل الخروج الذي يرتبط بـ /.auth/logout كما ستُعيّن عنوان URL لإعادة التوجيه للصفحة الحالية.

ينبغي أن تشاهد هذا الآن في مستعرضك.

Screenshot of the React web app with login buttons.

  1. حرر الملف svelte-app/src/components/NavBar.svelte لإضافة قائمة بالموفرين في الجزء العلوي من البرنامج النصي.

    const providers = ['twitter', 'github', 'aad'];
    
  2. أضف المتغير التالي redirect أسفل المتغير الأول لالتقاط URL الحالي لإعادة التوجيه بعد تسجيل الدخول.

    const redirect = window.location.pathname;
    
  3. أضف التعليمات البرمجية التالية إلى القالب بعد العنصر الأول </nav> لعرض أزرار تسجيل الدخول والخروج.

     <nav class="menu auth">
       <p class="menu-label">Auth</p>
       <div class="menu-list auth">
         {#if !userInfo}
           {#each providers as provider (provider)}
             <a href={`/.auth/login/${provider}?post_login_redirect_uri=${redirect}`}>
               {provider}
             </a>
           {/each}
         {/if}
         {#if userInfo}
           <a href={`/.auth/logout?post_logout_redirect_uri=${redirect}`}>
             Logout
           </a>
         {/if}
       </div>
     </nav>
    

    في حالة عدم تسجيل دخول المستخدم، فإنك ستعرض زر تسجيل الدخول لكل مُزود. يرتبط كل زر بـ /.auth/login/<AUTH_PROVIDER> ويعين عنوان URL لإعادة التوجيه إلى الصفحة الحالية.

    بخلاف ذلك، إذا كان المستخدم قد سجل الدخول بالفعل، فستعرض زر تسجيل الخروج الذي يرتبط بـ /.auth/logout كما ستُعيّن عنوان URL لإعادة التوجيه للصفحة الحالية.

ينبغي أن تشاهد هذا الآن في مستعرضك.

Screenshot of the Svelte web app with login buttons.

  1. حرر الملف vue-app/src/components/nav-bar.vue وأضف قائمة موفرين إلى كائن البيانات.

     providers: ['twitter', 'github', 'aad'],
    
  2. أضف الخاصية redirectأدناه، لتسجيل عنوان URL الحالي لإعادة التوجيه بعد تسجيل الدخول.

     redirect: window.location.pathname,
    
  3. أضف التعليمات البرمجية التالية إلى القالب بعد العنصر الأول </nav> لعرض أزرار تسجيل الدخول والخروج.

    <nav class="menu auth">
      <p class="menu-label">Auth</p>
      <div class="menu-list auth">
        <template v-if="!userInfo">
          <template v-for="provider in providers">
            <a :key="provider" :href="`/.auth/login/${provider}?post_login_redirect_uri=${redirect}`">
              {{ provider }}
            </a>
          </template>
        </template>
        <a v-if="userInfo" :href="`/.auth/login/${provider}?post_login_redirect_uri=${redirect}`"> Logout </a>
      </div>
    </nav>
    

    في حالة عدم تسجيل دخول المستخدم، فإنك ستعرض زر تسجيل الدخول لكل مُزود. يرتبط كل زر بـ /.auth/login/<AUTH_PROVIDER> ويعين عنوان URL لإعادة التوجيه إلى الصفحة الحالية.

    بخلاف ذلك، إذا كان المستخدم قد سجل الدخول بالفعل، فستعرض زر تسجيل الخروج الذي يرتبط بـ /.auth/logout كما ستُعيّن عنوان URL لإعادة التوجيه للصفحة الحالية.

ينبغي أن تشاهد هذا الآن في مستعرضك.

Screenshot of the Vue web app with login buttons.

عرض حالة تسجيل دخول المستخدم

قبل اختبار سير عمل المصادقة، لنعرض تفاصيل المستخدم عن المستخدم الذي سجَّل الدخول.

حرر الملف angular-app/src/app/core/components/nav.component.ts، وأضف هذه التعليمات البرمجية في الجزء السفلي من القالب بعد وسم الإغلاق الأخير </nav>.

<div class="user" *ngIf="userInfo">
  <p>Welcome</p>
  <p>{{ userInfo?.userDetails }}</p>
  <p>{{ userInfo?.identityProvider }}</p>
</div>

إشعار

يمكن أن تكون الخاصية userDetails أو عنوان بريد إلكتروني، اعتمادًا على الهوية المقدمة المستخدمة لتسجيل الدخول.

يجب أن يبدو ملفك المكتمل الآن كما يلي:

import { Component, OnInit } from '@angular/core';
import { UserInfo } from '../model/user-info';

@Component({
  selector: 'app-nav',
  template: `
    <nav class="menu">
      <p class="menu-label">Menu</p>
      <ul class="menu-list">
        <a routerLink="/products" routerLinkActive="router-link-active">
          <span>Products</span>
        </a>
        <a routerLink="/about" routerLinkActive="router-link-active">
          <span>About</span>
        </a>
      </ul>
    </nav>
    <nav class="menu auth">
      <p class="menu-label">Auth</p>
      <div class="menu-list auth">
        <ng-container *ngIf="!userInfo; else logout">
          <ng-container *ngFor="let provider of providers">
            <a href="/.auth/login/{{ provider }}?post_login_redirect_uri={{ redirect }}">{{ provider }}</a>
          </ng-container>
        </ng-container>
        <ng-template #logout>
          <a href="/.auth/logout?post_logout_redirect_uri={{ redirect }}">Logout</a>
        </ng-template>
      </div>
    </nav>
    <div class="user" *ngIf="userInfo">
      <p>Welcome</p>
      <p>{{ userInfo?.userDetails }}</p>
      <p>{{ userInfo?.identityProvider }}</p>
    </div>
  `,
})
export class NavComponent implements OnInit {
  providers = ['twitter', 'github', 'aad'];
  redirect = window.location.pathname;
  userInfo: UserInfo;

  async ngOnInit() {
    this.userInfo = await this.getUserInfo();
  }

  async getUserInfo() {
    try {
      const response = await fetch('/.auth/me');
      const payload = await response.json();
      const { clientPrincipal } = payload;
      return clientPrincipal;
    } catch (error) {
      console.error('No profile could be found');
      return undefined;
    }
  }
}

حرر الملف react-app/src/components/NavBar.js، وأضف هذه التعليمات البرمجية في الجزء السفلي من قالب JSX بعد وسم الإغلاق الأخير </nav> لعرض حالة تسجيل الدخول.

{
  userInfo && (
    <div>
      <div className="user">
        <p>Welcome</p>
        <p>{userInfo && userInfo.userDetails}</p>
        <p>{userInfo && userInfo.identityProvider}</p>
      </div>
    </div>
  )
}

إشعار

يمكن أن تكون الخاصية userDetails أو عنوان بريد إلكتروني، اعتمادًا على الهوية المقدمة المستخدمة لتسجيل الدخول.

يجب أن يبدو ملفك المكتمل الآن كما يلي:

import React, { useState, useEffect } from 'react';
import { NavLink } from 'react-router-dom';

const NavBar = (props) => {
  const providers = ['twitter', 'github', 'aad'];
  const redirect = window.location.pathname;
  const [userInfo, setUserInfo] = useState();

  useEffect(() => {
    (async () => {
      setUserInfo(await getUserInfo());
    })();
  }, []);

  async function getUserInfo() {
    try {
      const response = await fetch('/.auth/me');
      const payload = await response.json();
      const { clientPrincipal } = payload;
      return clientPrincipal;
    } catch (error) {
      console.error('No profile could be found');
      return undefined;
    }
  }

  return (
    <div className="column is-2">
      <nav className="menu">
        <p className="menu-label">Menu</p>
        <ul className="menu-list">
          <NavLink to="/products" activeClassName="active-link">
            Products
          </NavLink>
          <NavLink to="/about" activeClassName="active-link">
            About
          </NavLink>
        </ul>
        {props.children}
      </nav>
      <nav className="menu auth">
        <p className="menu-label">Auth</p>
        <div className="menu-list auth">
          {!userInfo &&
            providers.map((provider) => (
              <a key={provider} href={`/.auth/login/${provider}?post_login_redirect_uri=${redirect}`}>
                {provider}
              </a>
            ))}
          {userInfo && <a href={`/.auth/logout?post_logout_redirect_uri=${redirect}`}>Logout</a>}
        </div>
      </nav>
      {userInfo && (
        <div>
          <div className="user">
            <p>Welcome</p>
            <p>{userInfo && userInfo.userDetails}</p>
            <p>{userInfo && userInfo.identityProvider}</p>
          </div>
        </div>
      )}
    </div>
  );
};

export default NavBar;

حرر الملف svelte-app/src/components/NavBar.svelte، وأضف هذه التعليمات البرمجية في الجزء السفلي من القالب بعد وسم الإغلاق الأخير </nav> لعرض حالة تسجيل الدخول.

{#if userInfo}
<div class="user">
  <p>Welcome</p>
  <p>{userInfo && userInfo.userDetails}</p>
  <p>{userInfo && userInfo.identityProvider}</p>
</div>
{/if}

إشعار

يمكن أن تكون الخاصية userDetails أو عنوان بريد إلكتروني، اعتمادًا على الهوية المقدمة المستخدمة لتسجيل الدخول.

يجب أن يبدو ملفك المكتمل الآن كما يلي:

<script>
  import { onMount } from 'svelte';
  import { Link } from 'svelte-routing';

  const providers = ['twitter', 'github', 'aad'];
  const redirect = window.location.pathname;
  let userInfo = undefined;

  onMount(async () => (userInfo = await getUserInfo()));

  async function getUserInfo() {
    try {
      const response = await fetch('/.auth/me');
      const payload = await response.json();
      const { clientPrincipal } = payload;
      return clientPrincipal;
    } catch (error) {
      console.error('No profile could be found');
      return undefined;
    }
  }

  function getProps({ href, isPartiallyCurrent, isCurrent }) {
    const isActive = href === '/' ? isCurrent : isPartiallyCurrent || isCurrent;

    // The object returned here is spread on the anchor element's attributes
    if (isActive) {
      return { class: 'router-link-active' };
    }
    return {};
  }
</script>

<div class="column is-2">
  <nav class="menu">
    <p class="menu-label">Menu</p>
    <ul class="menu-list">
      <Link to="/products" {getProps}>Products</Link>
      <Link to="/about" {getProps}>About</Link>
    </ul>
  </nav>
  <nav class="menu auth">
    <p class="menu-label">Auth</p>
    <div class="menu-list auth">
      {#if !userInfo}
        {#each providers as provider (provider)}
          <a href={`/.auth/login/${provider}?post_login_redirect_uri=${redirect}`}>
            {provider}
          </a>
        {/each}
      {/if}
      {#if userInfo}
        <a href={`/.auth/logout?post_logout_redirect_uri=${redirect}`}>
          Logout
        </a>
      {/if}
    </div>
  </nav>
  {#if userInfo}
    <div class="user">
      <p>Welcome</p>
      <p>{userInfo && userInfo.userDetails}</p>
      <p>{userInfo && userInfo.identityProvider}</p>
    </div>
  {/if}
</div>

حرر الملف vue-app/src/components/nav-bar.vue، وأضف هذه التعليمات البرمجية في الجزء السفلي من القالب بعد وسم الإغلاق الأخير </nav> لعرض حالة تسجيل الدخول:

<div class="user" v-if="userInfo">
  <p>Welcome</p>
  <p>{{ userInfo.userDetails }}</p>
  <p>{{ userInfo.identityProvider }}</p>
</div>

إشعار

يمكن أن تكون الخاصية userDetails أو عنوان بريد إلكتروني، اعتمادًا على الهوية المقدمة المستخدمة لتسجيل الدخول.

يجب أن يبدو ملفك المكتمل الآن كما يلي:

<script>
  export default {
    name: 'NavBar',
    data() {
      return {
        userInfo: {
          type: Object,
          default() {},
        },
        providers: ['twitter', 'github', 'aad'],
        redirect: window.location.pathname,
      };
    },
    methods: {
      async getUserInfo() {
        try {
          const response = await fetch('/.auth/me');
          const payload = await response.json();
          const { clientPrincipal } = payload;
          return clientPrincipal;
        } catch (error) {
          console.error('No profile could be found');
          return undefined;
        }
      },
    },
    async created() {
      this.userInfo = await this.getUserInfo();
    },
  };
</script>

<template>
  <div column is-2>
    <nav class="menu">
      <p class="menu-label">Menu</p>
      <ul class="menu-list">
        <router-link to="/products">Products</router-link>
        <router-link to="/about">About</router-link>
      </ul>
    </nav>
    <nav class="menu auth">
      <p class="menu-label">Auth</p>
      <div class="menu-list auth">
        <template v-if="!userInfo">
          <template v-for="provider in providers">
            <a :key="provider" :href="`/.auth/login/${provider}?post_login_redirect_uri=${redirect}`">{{ provider }}</a>
          </template>
        </template>
        <a v-if="userInfo" :href="`/.auth/logout?post_logout_redirect_uri=${redirect}`">Logout</a>
      </div>
    </nav>
    <div class="user" v-if="userInfo">
      <p>Welcome</p>
      <p>{{ userInfo.userDetails }}</p>
      <p>{{ userInfo.identityProvider }}</p>
    </div>
  </div>
</template>

اختبار المصادقة محليًا

كل شيء في مكانه الصحيح الآن. والخطوة الأخيرة هي اختبار ما إذا كان كل شيء يعمل على النحو المتوقع.

  1. في تطبيق الويب خاصتك، حدد أحد مزودي الهوية لتسجيل الدخول.

  2. سيُعاد توجيهك إلى هذه الصفحة:

    Screenshot showing SWA CLI fake authentication screen.

    هذه شاشة مصادقة وهمية مقدمة من واجهة سطر أوامر SWA، تسمح لك باختبار المصادقة محليًا من خلال تزويد تفاصيل المستخدم بنفسك.

  3. أدخل mslearn باسم المستخدم و 1234 لمعرف المستخدم.

  4. حدد تسجيل الدخول.

    بعد تسجيل الدخول، يُعاد توجيهك إلى الصفحة السابقة. يمكنك أن ترى أزرار تسجيل الدخول قد استبدلت بزر تسجيل الخروج. يمكنك أيضًا رؤية اسم المستخدم والمزود المحدد خاصتك أسفل زر تسجيل الخروج.

    الآن بعد أن فحصت من أن كل شيء يعمل على النحو المتوقع محليًا، حان الوقت لتوزيع تغييراتك.

  5. يمكنك إيقاف تشغيل التطبيق واجهة برمجة التطبيقات عن طريق الضغط على Ctrl-C في كلا الـ terminals.

وزع تغييراتك

  1. في Visual Studio Code، افتح لوحة الأوامر بالضغط على F1.

  2. اكتب Git: Commit All وحدده.

  3. أدخل Add authentication كرسالة تثبيت، ثم اضغط Enter.

  4. افتح لوحة الأوامر بالضغط على F1.

  5. أدخل Git:Pull ثم حددها، ثم اضغط Enter.

بعد دفع تغييراتك، انتظر حتى تشغيل عملية الإنشاء والتوزيع. يجب أن تكون التغييرات مرئية على تطبيقك الموزع بعد ذلك.

الخطوات التالية

يدعم تطبيقك الآن مصادقة المستخدم وخطوتك التالية هي تقييد بعض أجزاء التطبيق للمستخدمين غير المصادق عليهم.