احراز هویت کاربر با React Native Navigation — راهنمای کاربردی
در بخش قبلی این مطلب در مورد کتابخانه 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
این دستور چند کار به شرح زیر انجام میدهد:
- یک پروژه جدید Mobile Hub در حساب AWS ما ایجاد میکند.
- چند وابستگی را به صورت aws-amplify و aws-amplify-react-native درون پروژه نصب میکند.
- فایلهای پیکربندی محلی با اسامی 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
1// index.js
2import {Navigation} from 'react-native-navigation';
3import {registerScreens} from './src/screens';
4
5import Amplify from 'aws-amplify'
6import config from './aws-exports'
7Amplify.configure(config)
8
9registerScreens();
10
11Navigation.events().registerAppLaunchedListener(() => {
12 Navigation.setRoot({
13 root: {
14 component: {
15 name: 'Initializing'
16 }
17 },
18 });
19});
در فایل فوق کتابخانه Amplify و همچنین پیکربندی AWS را از aws-exports.js ایمپورت میکنیم و تابع Amplify.configure را فراخوانی کرده و پیکربندی را ارسال میکنیم. بدین ترتیب پروژه ریاکت نیتیو راهاندازی شده و امکان آغاز فراخوانی سرویس AWS را با استفاده از Amplify از هر کجا درون اپلیکیشن فراهم میسازد.
فایل SignUp.js
در فایل SignUp.js تابع signUp را بهروزرسانی میکنیم تا ثبت نام کاربر جدید را مدیریت کرده و یک تابع confirmSignUp جدید برای MFA بسازیم.
1// SignUp.js
2import React, { Fragment } from 'react'
3import {
4 View,
5 Button,
6 TextInput,
7 StyleSheet
8} from 'react-native'
9import {Navigation} from 'react-native-navigation';
10
11import { Auth } from 'aws-amplify'
12
13const initialState = {
14 username: '', password: '', email: '', phone_number: '', authenticationCode: '', showConfirmationForm: false
15}
16
17export default class SignUp extends React.Component {
18 state = initialState
19 onChangeText = (key, val) => {
20 this.setState({ [key]: val })
21 }
22 signUp = async () => {
23 const { username, password, email, phone_number } = this.state
24 try {
25 const success = await Auth.signUp({ username, password, attributes: { email, phone_number }})
26 console.log('user successfully signed up!: ', success)
27 this.setState({ showConfirmationForm: true })
28 } catch (err) {
29 console.log('error signing up: ', err)
30 }
31 }
32 confirmSignUp = async () => {
33 const { username, authenticationCode } = this.state
34 try {
35 await Auth.confirmSignUp(username, authenticationCode)
36 console.log('successully signed up!')
37 alert('User signed up successfully!')
38 this.setState({ ...initialState })
39 } catch (err) {
40 console.log('error confirming signing up: ', err)
41 }
42 }
43 render() {
44 return (
45 <View style={styles.container}>
46 {
47 !this.state.showConfirmationForm && (
48 <Fragment>
49 <TextInput
50 style={styles.input}
51 placeholder='Username'
52 autoCapitalize="none"
53 placeholderTextColor='white'
54 onChangeText={val => this.onChangeText('username', val)}
55 />
56 <TextInput
57 style={styles.input}
58 placeholder='Password'
59 secureTextEntry={true}
60 autoCapitalize="none"
61 placeholderTextColor='white'
62 onChangeText={val => this.onChangeText('password', val)}
63 />
64 <TextInput
65 style={styles.input}
66 placeholder='Email'
67 autoCapitalize="none"
68 placeholderTextColor='white'
69 onChangeText={val => this.onChangeText('email', val)}
70 />
71 <TextInput
72 style={styles.input}
73 placeholder='Phone Number'
74 autoCapitalize="none"
75 placeholderTextColor='white'
76 onChangeText={val => this.onChangeText('phone_number', val)}
77 />
78 <Button
79 title='Sign Up'
80 onPress={this.signUp}
81 />
82 </Fragment>
83 )
84 }
85 {
86 this.state.showConfirmationForm && (
87 <Fragment>
88 <TextInput
89 style={styles.input}
90 placeholder='Authentication code'
91 autoCapitalize="none"
92 placeholderTextColor='white'
93 onChangeText={val => this.onChangeText('authenticationCode', val)}
94 />
95 <Button
96 title='Confirm Sign Up'
97 onPress={this.confirmSignUp}
98 />
99 </Fragment>
100 )
101 }
102 </View>
103 )
104 }
105}
106
107const styles = StyleSheet.create({
108 input: {
109 width: 350,
110 height: 55,
111 backgroundColor: '#42A5F5',
112 margin: 10,
113 padding: 8,
114 color: 'white',
115 borderRadius: 14,
116 },
117 container: {
118 flex: 1,
119 justifyContent: 'center',
120 alignItems: 'center'
121 }
122})
در این فایل SignUp.js دو فرم ابتدایی داریم که یکی برای ثبت نام کاربر جدید و دیگری برای تأیید ثبت نام با استفاده از MFA است. فرم تأیید ثبت نام به کاربر امکان میدهد که کد MFA خود را برای شناسایی این که این کد را دریافت کرده است وارد کند. ما این دو فرم را بر اساس مقدار بولی this.state.showConfirmationForm نمایش داده یا پنهان میکنیم که مقدار آن در متدهای کلاس signUp و confirmSignUp تعیین میشود.
متدهایی که برای ثبت نام و تأیید ثبت نام از AWS Amplify استفاده میکنیم، به ترتیب Auth.signUp و Auth.confirmSignUp نام دارند.
فایل SignIn.js
این فایل برای بهروزرسانی تابع signIn جهت مدیریت ثبت نام کاربر و ایجاد تابع جدید confirmSignIn برای MFA استفاده میشود.
1// SignIn.js
2import React, { Fragment } from 'react'
3import {
4 View,
5 Text,
6 StyleSheet,
7 TextInput,
8 Button
9} from 'react-native'
10
11import { goHome } from './navigation'
12import { Auth } from 'aws-amplify'
13
14export default class SignIn extends React.Component {
15 state = {
16 username: '', password: '', user: {}, authenticationCode: '', showConfirmationForm: false
17 }
18 onChangeText = (key, value) => {
19 this.setState({ [key]: value })
20 }
21 signIn = async () => {
22 const { username, password } = this.state
23 try {
24 const user = await Auth.signIn(username, password)
25 console.log('user successfully signed in!', user)
26 this.setState({ user, showConfirmationForm: true })
27 } catch (err) {
28 console.log('error:', err)
29 }
30 }
31 confirmSignIn = async () => {
32 const { user, authenticationCode } = this.state
33 try {
34 await Auth.confirmSignIn(user, authenticationCode)
35 console.log('user successfully signed in!', user)
36 goHome()
37 } catch (err) {
38 console.log('error:', err)
39 }
40 }
41 render() {
42 return (
43 <View style={styles.container}>
44 {
45 !this.state.showConfirmationForm && (
46 <Fragment>
47 <TextInput
48 style={styles.input}
49 placeholder='Username'
50 autoCapitalize="none"
51 autoCorrect={false}
52 placeholderTextColor='white'
53 onChangeText={val => this.onChangeText('username', val)}
54 />
55 <TextInput
56 style={styles.input}
57 placeholder='Password'
58 autoCapitalize="none"
59 secureTextEntry={true}
60 placeholderTextColor='white'
61 onChangeText={val => this.onChangeText('password', val)}
62 />
63 <Button
64 title='Sign In'
65 onPress={this.signIn}
66 />
67 </Fragment>
68 )
69 }
70 {
71 this.state.showConfirmationForm && (
72 <Fragment>
73 <TextInput
74 style={styles.input}
75 placeholder='Authentication Code'
76 autoCapitalize="none"
77 placeholderTextColor='white'
78 onChangeText={val => this.onChangeText('authenticationCode', val)}
79 />
80 <Button
81 title='Confirm Sign In'
82 onPress={this.confirmSignIn}
83 />
84 </Fragment>
85 )
86 }
87 </View>
88 )
89 }
90}
91
92const styles = StyleSheet.create({
93 input: {
94 width: 350,
95 fontSize: 18,
96 fontWeight: '500',
97 height: 55,
98 backgroundColor: '#42A5F5',
99 margin: 10,
100 color: 'white',
101 padding: 8,
102 borderRadius: 14
103 },
104 container: {
105 flex: 1,
106 justifyContent: 'center',
107 alignItems: 'center'
108 }
109})
فایل SignIn.js
منطق این کامپوننت بسیار مشابه آن چیزی است که در SignUp.js دیدیم و تنها یک تفاوت وجود دارد. زمانی که Auth.signIn را فراخوانی میکنیم، مقدار بازگشتی از فراخوانی متد را در حالت (State) خود ذخیره میکنیم تا بعدتر در Auth.confirmSignIn استفاده کنیم. زمانی که (Auth.confirmSignIn(user, confirmationCode را فراخوانی میکنیم، این شیء کاربر را همراه با کد احراز هویت دریافتی از MFA به آن ارسال میکنیم.
فایل Initializing.js
زمانی که کاربر وارد حساب خود در اپلیکیشن شد، میتوانیم از طریق فراخوانی کردن Auth.currentAuthenticatedUser اطلاعاتی در مورد کاربر بازیابی کنیم. اگر یک کاربر ثبت نام کرده باشد، این تابع موفق خواهد بود و میتوانیم اپلیکیشن اصلی را بارگذاری کنیم. اگر این رویه ناموفق باشد، میتوانیم مسیریابیهای احراز هویت یعنی SignIn و SignUp را بارگذاری کنیم.
برای پیادهسازی این وضعیت باید کامپوننت Auth را از AWS Amplify ایمپورت کرده و متد چرخه عمر componentDidMount را بهروزرسانی کنیم تا کاربر را بررسی کند:
1// Initializing.js
2// previous imports excluded
3import { Auth } from 'aws-amplify'
4export default class Initialising extends React.Component {
5 async componentDidMount() {
6 try {
7 const user = await Auth.currentAuthenticatedUser()
8 console.log('user: ', user)
9 if (user) {
10 goHome()
11 } else {
12 goToAuth()
13 }
14 } catch (err) {
15 console.log('error: ', err)
16 goToAuth()
17 }
18 }
19// rest of class excluded
20}
برای مشاهده نسخه نهایی این کامپوننت به این لینک (+) مراجعه کنید.
فایل Home.js
آخرین کاری که باید انجام دهیم، بهروزرسانی دکمه SignOut است تا در زمان کلیک شدن، کاربر را عملاً از اپلیکیشن خارج کند. به این منظور میتوانیم دستگیره onPress را الحاق کنیم تا متد Auth.signOut را از AWS Amplify فراخوانی کند:
1// Home.js
2// previous imports excluded
3import { Auth } from 'aws-amplify'
4export default class Home extends React.Component {
5 // static options omitted
6 logout = async () => {
7 try {
8 await Auth.signOut()
9 goToAuth()
10 } catch (err) {
11 console.log('error signing out...: ', err)
12 }
13 }
14 // rest of class excluded
15}
برای مشاهده نسخه نهایی این کامپوننت به این صفحه (+) مراجعه کنید.
سخن پایانی
راهاندازی و اجرای احراز هویت کاربر به کمک ترکیبی از Amazon Cognito و AWS Amplify کار واقعاً سرراستی محسوب میشود. تکنیکهایی که در این راهنما استفاده کردیم، به همراه کتابخانه React Native Navigation کار میکنند و البته با ارائهدهندگان خدمات احراز هویت دیگر نیز به خوبی اجرا خواهند شد.
وقتی از ناوبری در ریاکت نیتیو صحبت میکنیم، دو کتابخانه بسیار کارآمد وجود دارند که یکی React Navigation و دیگری React Native Navigation است. کتابخانه React Navigation نگهداری بسیار خوبی دارد و کاملاً به بلوغ رسیده است. این کتابخانه تقریباً هر چیزی را که بخواهید انجام میدهد و تیم نگهداری آن کار فوقالعادهای در رسیدگی به مشکلات و تبدیل کردن به یک کتابخانه درجه یک انجام دادهاند.
React Native Navigation نیز گزینه مناسبی محسوب میشود و از سوی تیم توسعهدهنده به خوبی نگهداری شده است. React Native Navigation نسخه 2 اخیراً وارد فاز آلفا شده و ممکن است برخی قابلیتها هنوز عرضه نشده باشند که در این مورد میتوانید issue بدهید یا درخواست pull کنید.
اگر این مطلب برای شما مفید بوده است، آموزشهای زیر نیز به شما پیشنهاد میشوند:
- مجموعه آموزشهای JavaScript (جاوا اسکریپت)
- آموزش مقدماتی فریمورک React Native
- مجموعه آموزشهای برنامهنویسی
- ساخت یک اپلیکیشن چند پلتفرمی موبایل با React Native (بخش اول) — به زبان ساده
- ساخت اپلیکیشن ساده آب و هوا با React Native و Expo — از صفر تا صد
==