🌞

React Authentication với Amazon Cognito - Phần 1

Sửa bài viết này

Trong demo chúng ta sẽ sử dụng

  • Create React App
  • Glamor
  • React Router
  • Amazon Cognito để authentication
  • AWS amplify để tương tác với AWS Services

Setup

Khởi tạo project và các thư viện sẽ sử dụng

create-react-app react-auth
cd react-auth

npm i react-router-dom glamor --save

Cài AWSMobile CLI

npm i -g awsmobile-cli

Khởi tạo config AWS IAM

awsmobile configure
awsmobile init

Nó sẽ tạo project Mobile Hub và file aws-exports.js trong thư mục src. Tiếp theo, thêm user-signin và deploy các config mới

awsmobile user-signin enable
awsmobile push

awsmobile user-signin enable sẽ bật Amazon Congito trong project với các thiết đặt mặc định, bao gồm 2 factor authentication với SMS (sẽ thêm TOTP sau). Nếu muôn can thiệp các thiệt đặt, vào trực tiếp Amazon Cognito để chỉnh

Màn hình đăng ký

Để tương tác với Amazon Cognito, chúng ta sẽ sử các hàm trong class Auth từ thư viện aws-amplify:

signUp - tạo user mới

signUp(username: string, password: string, attributes?: object)

confirmSignUp - để xác nhận đăng ký thành công

confirmSignUp(username: string, authenticationCode: string)

signIn - đăng nhập

signIn(username: string, password: string)

confirmSignIn - xác nhận đăng nhập

confirmSignIn(user: object, authenticationCode: string)

Trong file root của project, thường là index.js

// một số import khác
// 
import config from './aws-exports'
import Amplify from 'aws-amplify'

Amplify.configure(config)

ReactDOM.render(<App />, document.getElementById('root'))
registerServiceWorker();

Screen SignUp.js

import React from 'react'
import { css } from 'glamor'

class SignUp extends React.Component {
  state = {
    username: '',
    password: '',
    email: '',
    phone_number: '',
    authCode: ''
  }
  render() {
    return (
      <div {...css(styles.container)}>
        <h2>SignUp</h2>
      </div>
    )
  }
}
const styles = {
  container: {
    display: 'flex',
    flexDirection: 'column',
    alignItems: 'center'
  }
}

Flow sẽ như thế này, sau khi user cung cấp các thông tin trong form signup, chúng ta gọi đến phương thức signUp, user sẽ nhận được một mã code để verify quá SMS, user điền mã code này vào form verify, chúng ta verify cái mã code này bằng phương thức 'confirmSignUp'

import React from 'react'
import { css } from 'glamor'

class SignUp extends React.Component {
  state = {
    username: '',
    password: '',
    email: '',
    phone_number: '',
    authCode: ''
  }
  onChange = (key, value) => {
    this.setState({ [key]: value })
  }
  render() {
    return (
      <div {...css(styles.container)}>
        <h2>Sign Up</h2>
        <input
          {...css(styles.input)}
          placeholder='Username'
          onChange={evt => this.onChange('username', evt.target.value)}
        />
        <input
          {...css(styles.input)}
          placeholder='Password'
          type='password'
          onChange={evt => this.onChange('password', evt.target.value)}
        />
        <input
          {...css(styles.input)}
          placeholder='Email'
          onChange={evt => this.onChange('email', evt.target.value)}
        />
        <input
          {...css(styles.input)}
          placeholder='Phone Number'
          onChange={evt => this.onChange('phone_number', evt.target.value)}
        />
        <div {...css(styles.button)}>
          <span>Sign Up</span>
        </div>
        
        <input
          {...css(styles.input)}
          placeholder='Authentication Code'
          onChange={evt => this.onChange('authCode', evt.target.value)}
        />
        <div {...css(styles.button)}>
          <span>Confirm Sign Up</span>
        </div>
        
      </div>
    )
  }
}

let styles = {
  container: {
    display: 'flex',
    flexDirection: 'column',
    alignItems: 'center'
  },
  button: {
    width: '170px',
    padding: '10px 0px',
    backgroundColor: '#ddd',
    cursor: 'pointer',
    borderRadius: '3px',
    ':hover': {
      backgroundColor: '#ededed'
    }
  },
  input: {
    height: 40,
    marginBottom: '10px',
    border: 'none',
    outline: 'none',
    borderBottom: '2px solid #4CAF50',
    fontSize: '16px',
    '::placeholder': {
      color: 'rgba(0, 0, 0, .3)'
    }
  }
}

export default SignUp

Xong cái UI, giờ ta sử dụng 2 phương thức class Auth

// previous imports omitted

  import { Auth } from 'aws-amplify'

  // previously shown code omitted
  signUp = () => {
    const { username, password, email, phone_number } = this.state
    Auth.signUp({
      username,
      password,
      attributes: {
        email,
        phone_number
      }
    })
    .then(() => console.log('successful sign up!'))
    .catch(err => console.log('error signing up: ', err))
  }
  confirmSignUp = () => {
    Auth.confirmSignUp(this.state.username, this.state.authCode)
    .then(console.log('successful confirm sign up!'))
    .catch(err => console.log('error confirming signing up: ', err))
  }
  render() {
    // 
    // here we need to update the buttons to attach class methods to onClick event
    <div {...css(styles.button)} onClick={this.signUp}>
      <span>Sign Up</span>
    </div>

    <input
      {...css(styles.input)}
      placeholder='Authentication Code'
      onChange={evt => this.onChange('authCode', evt.target.value)}
    />
    <div {...css(styles.button)} onClick={this.confirmSignUp}>
      <span>Confirm Sign Up</span>
    </div>
  }

Cuối cùng import và sử dụng component trong App.js

import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';

import SignUp from './SignUp'

class App extends Component {
  render() {
    return (
      <div className="App">
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <h1 className="App-title">Welcome to React</h1>
        </header>
        <SignUp />
      </div>
    );
  }
}

export default App;

Các thông tin của user sẽ được lại trong 'Manage your User Pools', vào Amazon Coginito dashboard, chọn ứng dụng đã setup, chọn mục 'Users and Settings'

Sign In

Sign in thì cũng tương tự như signup, chúng ta sử dụng Auth.signIn(username, password), trả về object nếu thành công, sau đó nó sẽ gửi SMS tới user với code xác nhận lần nữa, verify bằng confirmSignIn

signIn() {
  Auth.signIn(this.state.username, this.state.password)
    .then(user => this.setState({ user }))
    .catch(err => console.log('error signing in! :', err))
}
confirmSignIn() {
  Auth.confirmSignIn(this.state.user, this.state.authCode)
    .then(userData => {
      console.log('userdata: ', userData)
    })
    .catch(err => console.log('error confirming sign in!: ', err))
}

User data nằm trong cục dữ liệu trả về sau khi gọi hàm confirmSignIn

Có rất nhiều cách để lấy thông tin user đang đăng nhập, có thể dùng Auth.currentAuthenticatedUser() là dễ nhất, toàn bộ API có thể tham khảo ở đây

Kết thúc phần 1 ở đây, phần 2 tiếp tục với Routing và TOTP để có thể làm Google Authenticator.


Bài dịch từ tác giả Nader Dabit trên HackerNoon

Initializing...