Client側のAmplifyをInstallします。環境は前回「Reactを使ってStaticなWeb Hostingをする。」で使用した環境に追加します。npm install --save aws-amplify aws-amplify-react
Client側のApplicationを作って行きます。ReactのWelcome画面にCognitoユーザー認証を追加します。
初めに読み込まれる、index.jsにAWS Amplifyの設定を入れて置く”services”というfileをimportする行を追加します。import { configureAmplify } from './services'
そのあとで、Amlifyをconfigureするために、configureAmplify();
を呼び出します。ReactDom.renderに渡すelementを<App />から<AppWithAuth />に変更し、ユーザー認証を追加した描画処理に変更します。ReactDOM.render(<AppWithAuth />, document.getElementById('root'));
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();
index.jsからimportされる”services”を準備します。”services”では、Amplifyの設定をしますが、実際の情報は環境変数に設定しておき、起動時に”.env”から読み込むようにしておきます。このようにすることで、環境が変わっても再buildすることなく、環境を変更することができるようになります。
import Amplify from '@aws-amplify/core';
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,
}
} );
}
“.env”で4つの情報を設定し、projectのroot directoryに置きます。REACT_APP_region=ap-northeast-1
REACT_APP_userPoolId=ap-northeast-1yourPoolID
REACT_APP_userPoolWebClientId=yourWebClientId
REACT_APP_identityPoolId=ap-northeast-1:yourIdentityPoolId
これらの情報は、Cognito User Poolを作成した時に生成されたUser ID、App Client IDと、Cognito Identity Poolを作成した時に生成されたIdentity Pool IDを設定します。これらは、Cognitoに接続するための情報ですが、URLのような物で隠す必要はありません。ボットによる攻撃を避けるためには、Cognito User Poolの作成の際に、Client Deviceの認証を追加するなど検討します。
次に、 ReactDom.renderから最初に描画されるelement、”AppWithAuth.js”を作成します。今回はEメールによる認証を行わないため、Login画面を簡素化しました。単純にusernameとpasswordだけを入力できるようにしています。
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;
Login画面を簡素化するために、Amplifyが提供している”VerifyContact”、”ConfirmSignUp”をoverrideしてCustomizeしています。Amplifyは手っ取り早くApplicationを作成できるのですが、こういったCustomizeをするのが簡単ではありません。
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”を編集して、Loginの状態を表示するようにします。
import React from 'react';
import logo from './logo.svg';
import './App.css';
function App(props) {
if(props.authState === 'signedIn') {
return (
<div className="App">
<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">
<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;
今回はLocal環境からnpm startしてみます。
AmplifyのLogin画面が表示されます。
次回は、ユーザー認証の方法について説明していきます。