برنامه نویسی 426 بازدید

در بخش قبلی این مطلب در مورد کتابخانه React Native Navigation صحبت کردیم. در بخش دوم و پایانی این سری مقالات به بررسی روش‌های احراز هویت کاربر به کمک این کتابخانه خواهیم پرداخت. برای مطالعه بخش قبلی به لینک زیر مراجعه کنید:

کار خود را از جایی که در بخش اول باقی مانده بود از سر می‌گیریم و اینک می‌خواهیم با استفاده از AWS یک بخش واقعی ثبت نام و ورود کاربر به اپلیکیشن بسازیم. بدین منظور از AWS Amplify برای اتصال به AWS و از Amazon Cognito برای مدیریت کاربران استفاده می‌کنیم. اگر کد بخش قبلی را نوشته‌اید، می‌توانید شروع به کار روی آن بکنید، اما اگر آن کد را ندارید می‌توانید از این ریپو (+) استفاده کنید.

ایجاد سرویس Auth

از root پروژه ری‌اکت نیتیو آغاز می‌کنیم و یک پروژه جدید AWS را طوری مقداردهی می‌کنیم که بتوانیم احراز هویت را اضافه کنیم. به این منظور باید AWS Mobile CLI را نصب و پیکربندی کنیم:

npm i -g awsmobile-cli
awsmobile configure

زمانی که CLI را نصب و پیکربندی کردید، یک پروژه جدید AWS را مقداردهی کنید:

awsmobile init

این دستور چند کار به شرح زیر انجام می‌دهد:

  1. یک پروژه جدید Mobile Hub در حساب AWS ما ایجاد می‌کند.
  2. چند وابستگی را به صورت aws-amplify و aws-amplify-react-native درون پروژه نصب می‌کند.
  3. فایل‌های پیکربندی محلی با اسامی awsmobile.js و aws-exports.js اضافه می‌کند که امکان ویرایش محلی پیکربندی از طریق cli و ارسال تغییرات به پروژه Mobile Hub را در کنسول AWS فراهم می‌سازد.

سپس باید یک وابستگی نیتیو به پروژه React Native خود اضافه کنیم:

react-native link amazon-cognito-identity-js

اینک باید بخش ثبت نام کاربر را به پروژه AWS خود اضافه کنیم:

awsmobile user-signin enable

و آن را به کنسول AWS ارسال کنیم:

awsmobile user-signin enable

اکنون باید کارکرد ثبت نام کاربر ما فعال و آماده استفاده باشد. کل پروژه Mobile Hub را می‌توان در حساب AWS با اجرای دستور awsmobile console از خط فرمان مشاهده کرد. همچنین می‌توانید از کنسول Amazon Cognito بازدید کنید تا پیکربندی آن را ببینید.

نوشتن اپلیکیشن ری‌اکت نیتیو

اکنون که سرویس ایجاد شده است، باید اپلیکیشن را به‌روزرسانی کنیم تا از آن استفاده کند. ابتدا باید فایل index.js را به‌روزرسانی کنیم تا از پیکربندی موجود در فایل aws-exports.js استفاده کرده و با AWS Amplify کار کند.

فایل index.js

// index.js
import {Navigation} from 'react-native-navigation';
import {registerScreens} from './src/screens';

import Amplify from 'aws-amplify'
import config from './aws-exports'
Amplify.configure(config)

registerScreens();

Navigation.events().registerAppLaunchedListener(() => {
  Navigation.setRoot({
    root: {
      component: {
        name: 'Initializing'
      }
    },
  });
});

در فایل فوق کتابخانه Amplify و همچنین پیکربندی AWS را از aws-exports.js ایمپورت می‌کنیم و تابع Amplify.configure را فراخوانی کرده و پیکربندی را ارسال می‌کنیم. بدین ترتیب پروژه ری‌اکت نیتیو راه‌اندازی شده و امکان آغاز فراخوانی سرویس AWS را با استفاده از Amplify از هر کجا درون اپلیکیشن فراهم می‌سازد.

فایل SignUp.js

در فایل SignUp.js تابع signUp را به‌روزرسانی می‌کنیم تا ثبت نام کاربر جدید را مدیریت کرده و یک تابع confirmSignUp جدید برای MFA بسازیم.

// SignUp.js
import React, { Fragment } from 'react'
import {
  View,
  Button,
  TextInput,
  StyleSheet
} from 'react-native'
import {Navigation} from 'react-native-navigation';

import { Auth } from 'aws-amplify'

const initialState = {
  username: '', password: '', email: '', phone_number: '', authenticationCode: '', showConfirmationForm: false
}

export default class SignUp extends React.Component {
  state = initialState
  onChangeText = (key, val) => {
    this.setState({ [key]: val })
  }
  signUp = async () => {
    const { username, password, email, phone_number } = this.state
    try {
      const success = await Auth.signUp({ username, password, attributes: { email, phone_number }})
      console.log('user successfully signed up!: ', success)
      this.setState({ showConfirmationForm: true })
    } catch (err) {
      console.log('error signing up: ', err)
    }
  }
  confirmSignUp = async () => {
    const { username, authenticationCode } = this.state
    try {
      await Auth.confirmSignUp(username, authenticationCode)
      console.log('successully signed up!')
      alert('User signed up successfully!')
      this.setState({ ...initialState })
    } catch (err) {
      console.log('error confirming signing up: ', err)
    }
  }
  render() {
    return (
      <View style={styles.container}>
        {
          !this.state.showConfirmationForm && (
            <Fragment>
              <TextInput
                style={styles.input}
                placeholder='Username'
                autoCapitalize="none"
                placeholderTextColor='white'
                onChangeText={val => this.onChangeText('username', val)}
              />
              <TextInput
                style={styles.input}
                placeholder='Password'
                secureTextEntry={true}
                autoCapitalize="none"
                placeholderTextColor='white'
                onChangeText={val => this.onChangeText('password', val)}
              />
              <TextInput
                style={styles.input}
                placeholder='Email'
                autoCapitalize="none"
                placeholderTextColor='white'
                onChangeText={val => this.onChangeText('email', val)}
              />
              <TextInput
                style={styles.input}
                placeholder='Phone Number'
                autoCapitalize="none"
                placeholderTextColor='white'
                onChangeText={val => this.onChangeText('phone_number', val)}
              />
              <Button
                title='Sign Up'
                onPress={this.signUp}
              />
            </Fragment>
          )
        }
        {
          this.state.showConfirmationForm && (
            <Fragment>
              <TextInput
                style={styles.input}
                placeholder='Authentication code'
                autoCapitalize="none"
                placeholderTextColor='white'
                onChangeText={val => this.onChangeText('authenticationCode', val)}
              />
              <Button
                title='Confirm Sign Up'
                onPress={this.confirmSignUp}
              />
            </Fragment>
          )
        }
      </View>
    )
  }
}

const styles = StyleSheet.create({
  input: {
    width: 350,
    height: 55,
    backgroundColor: '#42A5F5',
    margin: 10,
    padding: 8,
    color: 'white',
    borderRadius: 14,
  },
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center'
  }
})

در این فایل SignUp.js  دو فرم ابتدایی داریم که یکی برای ثبت نام کاربر جدید و دیگری برای تأیید ثبت نام با استفاده از MFA است. فرم تأیید ثبت نام به کاربر امکان می‌دهد که کد MFA خود را برای شناسایی این که این کد را دریافت کرده است وارد کند. ما این دو فرم را بر اساس مقدار بولی this.state.showConfirmationForm نمایش داده یا پنهان می‌کنیم که مقدار آن در متدهای کلاس signUp و confirmSignUp تعیین می‌شود.

متدهایی که برای ثبت نام و تأیید ثبت نام از AWS Amplify استفاده می‌کنیم، به ترتیب Auth.signUp و Auth.confirmSignUp نام دارند.

فایل SignIn.js

این فایل برای به‌روزرسانی تابع signIn جهت مدیریت ثبت نام کاربر و ایجاد تابع جدید confirmSignIn برای MFA استفاده می‌شود.

// SignIn.js
import React, { Fragment } from 'react'
import {
  View,
  Text,
  StyleSheet,
  TextInput,
  Button
} from 'react-native'

import { goHome } from './navigation'
import { Auth } from 'aws-amplify'

export default class SignIn extends React.Component {
  state = {
    username: '', password: '', user: {}, authenticationCode: '', showConfirmationForm: false
  }
  onChangeText = (key, value) => {
    this.setState({ [key]: value })
  }
  signIn = async () => {
    const { username, password } = this.state
    try {
       const user = await Auth.signIn(username, password)
       console.log('user successfully signed in!', user)
       this.setState({ user, showConfirmationForm: true })
    } catch (err) {
      console.log('error:', err)
    }
  }
  confirmSignIn = async () => {
    const { user, authenticationCode } = this.state
    try {
       await Auth.confirmSignIn(user, authenticationCode)
       console.log('user successfully signed in!', user)
       goHome()
    } catch (err) {
      console.log('error:', err)
    }
  }
  render() {
    return (
      <View style={styles.container}>
        {
          !this.state.showConfirmationForm && (
            <Fragment>
              <TextInput
                style={styles.input}
                placeholder='Username'
                autoCapitalize="none"
                autoCorrect={false}
                placeholderTextColor='white'
                onChangeText={val => this.onChangeText('username', val)}
              />
              <TextInput
                style={styles.input}
                placeholder='Password'
                autoCapitalize="none"
                secureTextEntry={true}
                placeholderTextColor='white'
                onChangeText={val => this.onChangeText('password', val)}
              />
              <Button
                title='Sign In'
                onPress={this.signIn}
              />
            </Fragment>
          )
        }
        {
          this.state.showConfirmationForm && (
            <Fragment>
              <TextInput
                style={styles.input}
                placeholder='Authentication Code'
                autoCapitalize="none"
                placeholderTextColor='white'
                onChangeText={val => this.onChangeText('authenticationCode', val)}
              />
              <Button
                title='Confirm Sign In'
                onPress={this.confirmSignIn}
              />
            </Fragment>
          )
        }        
      </View>
    )
  }
}

const styles = StyleSheet.create({
  input: {
    width: 350,
    fontSize: 18,
    fontWeight: '500',
    height: 55,
    backgroundColor: '#42A5F5',
    margin: 10,
    color: 'white',
    padding: 8,
    borderRadius: 14
  },
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center'
  }
})

فایل SignIn.js

منطق این کامپوننت بسیار مشابه آن چیزی است که در SignUp.js دیدیم و تنها یک تفاوت وجود دارد. زمانی که Auth.signIn را فراخوانی می‌کنیم، مقدار بازگشتی از فراخوانی متد را در حالت (State) خود ذخیره می‌کنیم تا بعدتر در Auth.confirmSignIn استفاده کنیم. زمانی که (Auth.confirmSignIn(user, confirmationCode را فراخوانی می‌کنیم، این شیء کاربر را همراه با کد احراز هویت دریافتی از MFA به آن ارسال می‌کنیم.

فایل Initializing.js

زمانی که کاربر وارد حساب خود در اپلیکیشن شد، می‌توانیم از طریق فراخوانی کردن Auth.currentAuthenticatedUser اطلاعاتی در مورد کاربر بازیابی کنیم. اگر یک کاربر ثبت نام کرده باشد، این تابع موفق خواهد بود و می‌توانیم اپلیکیشن اصلی را بارگذاری کنیم. اگر این رویه ناموفق باشد، می‌توانیم مسیریابی‌های احراز هویت یعنی SignIn و SignUp را بارگذاری کنیم.

برای پیاده‌سازی این وضعیت باید کامپوننت Auth را از AWS Amplify ایمپورت کرده و متد چرخه عمر componentDidMount را به‌روزرسانی کنیم تا کاربر را بررسی کند:

// Initializing.js
// previous imports excluded
import { Auth } from 'aws-amplify'
export default class Initialising extends React.Component {
  async componentDidMount() {
    try {
      const user = await Auth.currentAuthenticatedUser()
      console.log('user: ', user)
      if (user) {
        goHome()
      } else {
        goToAuth()
      }
    } catch (err) {
      console.log('error: ', err)
      goToAuth()
    }
  }
// rest of class excluded
}

برای مشاهده نسخه نهایی این کامپوننت به این لینک (+) مراجعه کنید.

فایل Home.js

آخرین کاری که باید انجام دهیم، به‌روزرسانی دکمه SignOut است تا در زمان کلیک شدن، کاربر را عملاً از اپلیکیشن خارج کند. به این منظور می‌توانیم دستگیره onPress را الحاق کنیم تا متد Auth.signOut را از AWS Amplify فراخوانی کند:

// Home.js
// previous imports excluded
import { Auth } from 'aws-amplify'
export default class Home extends React.Component {
  // static options omitted
  logout = async () => {
    try {
      await Auth.signOut()
      goToAuth()
    } catch (err) {
      console.log('error signing out...: ', err)
    }
  }
  // rest of class excluded
}

برای مشاهده نسخه نهایی این کامپوننت به این صفحه (+) مراجعه کنید.

سخن پایانی

راه‌اندازی و اجرای احراز هویت کاربر به کمک ترکیبی از Amazon Cognito و AWS Amplify کار واقعاً سرراستی محسوب می‌شود. تکنیک‌هایی که در این راهنما استفاده کردیم، به همراه کتابخانه React Native Navigation کار می‌کنند و البته با ارائه‌دهندگان خدمات احراز هویت دیگر نیز به خوبی اجرا خواهند شد.

وقتی از ناوبری در ری‌اکت نیتیو صحبت می‌کنیم، دو کتابخانه بسیار کارآمد وجود دارند که یکی React Navigation و دیگری React Native Navigation است. کتابخانه React Navigation نگهداری بسیار خوبی دارد و کاملاً به بلوغ رسیده است. این کتابخانه تقریباً هر چیزی را که بخواهید انجام می‌دهد و تیم نگهداری آن کار فوق‌العاده‌ای در رسیدگی به مشکلات و تبدیل کردن به یک کتابخانه درجه یک انجام داده‌اند.

React Native Navigation نیز گزینه مناسبی محسوب می‌شود و از سوی تیم توسعه‌دهنده به خوبی نگهداری شده است. React Native Navigation نسخه 2 اخیراً وارد فاز آلفا شده و ممکن است برخی قابلیت‌ها هنوز عرضه نشده باشند که در این مورد می‌توانید issue بدهید یا درخواست pull کنید.

اگر این مطلب برای شما مفید بوده است، آموزش‌های زیر نیز به شما پیشنهاد می‌شوند:

==

اگر بازخوردی درباره این مطلب دارید یا پرسشی دارید که بدون پاسخ مانده است، آن را از طریق بخش نظرات مطرح کنید.

«میثم لطفی» دانش‌آموخته ریاضیات و شیفته فناوری به خصوص در حوزه رایانه است. وی در حال حاضر علاوه بر پیگیری علاقه‌مندی‌هایش در رشته‌های برنامه‌نویسی، کپی‌رایتینگ و محتوای چندرسانه‌ای، در زمینه نگارش مقالاتی با محوریت نرم‌افزار نیز با مجله فرادرس همکاری دارد.

آیا این مطلب برای شما مفید بود؟

نظر شما چیست؟

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *