Cognitoユーザー認証によるS3 のAccess制御をAmplifyとReactとDropzoneを使って実装する。(その3)

Web Applicationを実装します。「Reactを使ってStaticなWeb Hostingをする。」と同じように、まずは、Reactのひな型を作ります。
create-react-app upload
cd upload
npm install -save aws-amplify aws-amplify-react

前回作成、または、変更したFileを参考に、S3の設定を追加しながら、作成したひな形にCopyします。詳細な説明は、「Cognitoユーザー認証をAmplifyとReactを使って実装する。(その3)」に戻って確認してください。

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import AppWithAuth from './AppWithAuth';
import * as serviceWorker from './serviceWorker';

//Import Amplify Configure function
import { configureAmplify } from './services'

configureAmplify();

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

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: http://bit.ly/CRA-PWA
serviceWorker.unregister();

services.jsでは、S3の設定を追加します。また、SetS3Config()というfunctionを定義します。BucketやS3のAccess Levelを変更した後、AmplifyのStorage.Configure()をCallして、Amplifyの設定を変更する必要があるためです。

import Amplify from '@aws-amplify/core';
import Auth from '@aws-amplify/auth';
import Storage from '@aws-amplify/storage';

export function configureAmplify() {
  Amplify.configure(
  {
    Auth: {
      region: process.env.REACT_APP_region,
      userPoolId: process.env.REACT_APP_userPoolId,
      userPoolWebClientId: process.env.REACT_APP_userPoolWebClientId,
      identityPoolId: process.env.REACT_APP_identityPoolId,
    },
    Storage: {
      AWSS3: {
        bucket: process.env.REACT_APP_bucket_name,
        region: process.env.REACT_APP_region,
      }
    }

  } );
}

//Configure Storage with S3 bucket information
export function SetS3Config(bucket, level){
  Auth.configure({
    region:  process.env.REACT_APP_region,
    identityPoolId: process.env.REACT_APP_identityPoolId,
  });
  Storage.configure({ 
    bucket: bucket,
    level: level,
  });
}

projectのroot directoryの “.env”にS3の設定を追加した、5つの情報を設定ます。
REACT_APP_region=ap-northeast-1
REACT_APP_userPoolId=ap-northeast-1yourPoolID
REACT_APP_userPoolWebClientId=yourWebClientId
REACT_APP_identityPoolId=ap-northeast-1:yourIdentityPoolId
REACT_APP_bucket_name=yourBucketName

AppWithAuth.js、MyVerifyContact.js、MyConfirmSignUp.jsは変更ありません。

import React from 'react';
import { Authenticator, ConfirmSignIn, RequireNewPassword, ConfirmSignUp, VerifyContact, ForgotPassword, TOTPSetup } from 'aws-amplify-react';
import App from "./App";
import MyVerifyContact from "./MyVerifyContact"
import MyConfirmSignUp from "./MyConfirmSignUp"

const signUpConfig = {
  hideAllDefaults: true,
  signUpFields: [
    {
      label: 'Username',
      key: 'username',
      required: true,
      placeholder: 'Username',
      displayOrder: 1
    },
    {
      label: 'Password',
      key: 'password',
      required: true,
      placeholder: 'Password',
      type: 'password',
      displayOrder: 2
    }
  ]
}

function AppWithAuth() {

  function handleAuthStateChange(state, data) {
    if (state === 'confirmSignIn') {
        /* Do something when the user has signed-in */
    }
  }

  return (
    <Authenticator signUpConfig={signUpConfig} hide={[ConfirmSignIn, RequireNewPassword, VerifyContact, ConfirmSignUp, ForgotPassword, TOTPSetup]} onStateChange={handleAuthStateChange}>
      <MyVerifyContact override={VerifyContact} />
      <MyConfirmSignUp override={ConfirmSignUp} />
      <App />
    </Authenticator>
  )
}

export default AppWithAuth;
import { AuthPiece } from 'aws-amplify-react';

class MyVerifyContact extends AuthPiece {
  constructor(props) {
    super(props);
    this._validAuthStates = ["verifyContact"];
    this.state = {}
  }

  static getDerivedStateFromProps(props, state) {
    if(props.authState === "verifyContact") {
      props.onStateChange('signedIn');
      return props;
    } else {
      return null;
    }
  }

  showComponent(theme) {
    return null;
  }

}

export default MyVerifyContact;
import React from 'react';

import { I18n } from 'aws-amplify';
import { AuthPiece } from 'aws-amplify-react';

import {
  FormSection,
  SectionHeader,
  SectionBody,
  SectionFooter,
  Button
} from 'aws-amplify-react';

class MyConfirmSignUp extends AuthPiece {
  constructor(props) {
    super(props);
    this._validAuthStates = ["confirmSignUp"];
    this.gotoSignIn = this.gotoSignIn.bind(this);
  }

  gotoSignIn() {
    super.changeState('signIn');
  }

  showComponent(theme) {
    return (
      <FormSection theme={theme}>
        <SectionHeader theme={theme}>{I18n.get('Please contact your administrator to grant your account.')}</SectionHeader>
        <SectionBody theme={theme}>
        </SectionBody>
        <SectionFooter theme={theme}>
          <Button onClick={this.gotoSignIn} theme={theme}>
            {I18n.get('Goto SignIn')}
          </Button>
        </SectionFooter>
      </FormSection>
    );

  }

}

export default MyConfirmSignUp;

最後にApp.jsを編集して、S3へUploadできるようにします。

import React, { useState, createRef }  from 'react';
import logo from './logo.svg';
import Storage from "@aws-amplify/storage";
import { SetS3Config } from "./services";
import './App.css';

function App(props) {

  const [uploadFile, setUploadFile] = useState({});
  const [response, setResponse] = useState("");
  const uploadRef = createRef();
  const onInputClick = () => {
    if(uploadRef.current) {
      uploadRef.current.value = null;
      uploadRef.current.click();
    }
    setResponse("");
  }

  function uploadFileToS3() {
    SetS3Config(process.env.REACT_APP_bucket_name, "protected");
    Storage.put(`upload/${uploadFile.name}`,
                uploadFile,
                { contentType: uploadFile.type })
      .then(result => {
        console.log(result);
        setUploadFile({});
        setResponse("File is uploaded!");
      })
      .catch(err => {
        console.log(err);
        setResponse(`File is not uploaded: ${err}`);
      });
  };

  function InputUploadFile(props) {
    return(
      <div  align="center">
        <input
          type="file"
          style={{ display: "none" }}
          accept="image/tif, image/tiff"
          ref={uploadRef}
          onChange={(e) => setUploadFile(e.target.files[0])}
        />
        <input value={uploadFile.name} placeholder="Select file" />
        <button onClick={onInputClick}> Browse </button>
        <button onClick={uploadFileToS3}> Upload File </button>

        {!!response && <div>{response}</div>}
      </div>
    )
  }

  if(props.authState === 'signedIn') {
    return (
      <div className="App">
        <InputUploadFile />

        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <p>
            Edit <code>src/App.js</code> and save to reload.
          </p>
          <a
            className="App-link"
            href="https://reactjs.org"
            target="_blank"
            rel="noopener noreferrer"
          >
            Learn React
          </a>
        </header>
      </div>
    );
  } else if(props.authState === 'confirmSignUp') {
    return (
      <div className="Your account is not granted">
        <header className="App-header">
          Your account is not granted.
        </header>
      </div>
    );
  } else if(props.authState === 'signIn') {
    return (
      <div className="Welcome to the world">
        <InputUploadFile />

        <header className="App-header">
          Welcome to the world.
        </header>
      </div>
    );
  } else {
    return (
      <div className="Login failed">
        <header className="App-header">
          Login failed.
        </header>
      </div>
    );
  }
}

export default App;

npm startからの説明は次回。

コメントを残す