フロントエンド環境を構築
開発用サイトを Django 側に登録します。
ここでの開発用サイトは localhost:3000 を指します。ユーザ登録時、ユーザに送信されるメール本文の中に使用されますので、フロントエンド環境を設定する前に済ませておきます。ちなみに、( 本番環境なら your-domain.com のように変更する必要があります )
project/settings.py の EMAIL_FILE_PATH と DEFAULT_FROM_EMAIL の内容がメール本文に反映されます。
EMAIL_FILE_PATH = ‘tmp/emails’
DEFAULT_FROM_EMAIL = ‘admin@mydomin.com’
※ メールログの例:
Content-Type: text/plain; charset=”utf-8″
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Subject: Please Confirm Your E-mail Address
From: admin@mydomin.com << project/settings.py の DEFAULT_FROM_EMAIL
To: user@your-domain.com << 登録メールアドレス
Date: Tue, 08 Oct 2019 23:07:55 -0000
Message-ID: <157057607508.47435.10310212505214298311@macadmin>
Hello from example.com! << project/settings.py の SITE_ID のドメイン
You’re receiving this e-mail because user testuser has given yours as an e-mail address to connect their account.
To confirm this is correct, go to example.com/account/confirm-email/MQ:1iHyaB:fqDiwW_LQoeVDGjXWRYyM4nFvPE/
Thank you from example.com!
example.com
- 1Django Admin サイトにログインします。
http://localhost:8000/admin/sites/site/add
- 2localhost:3000 を登録します。
※ デフォルトで example.com ドメインが入っていますが、削除しないでください。
- 3追加されたサイト名をクリックします。
若しくは、サイト名にマウスオーバーしてブラウザ左下のステータスメッセージでサイトIDが確認できます。確認できたらサイト名をクリックしなくて結構です。
http://127.0.0.1/admin/sites/site/2/change/ - 4URL 入力欄からサイト ID を確認します。
ここではサイト ID = 2です。( サイト ID は環境によって異なります )
- 5サイト ID を Django 環境に反映します。
project/settings.py を開き、SITE_ID = 1 を 上記で確認したサイト ID に変更します。ここでは最終的には SITE_ID = 2 になります。
Create-react-app ツールを使用して React アプリを作成します。
try🐶everything email-auth$ npx create-react-app frontend ... try🐶everything email-auth$ cd frontend/ try🐶everything frontend$ yarn start
http://localhost:3000 にアクセス出来るか確認します。問題なければ Ctrl+C で React 開発サーバを閉じておきます。
フロントエンド用ソースをコピペします。
※ reactjs-auth-django-rest を利用しますが、そのままではエラーが発生するため使えません。したがって、以下の手順で修正していきます。
- 1reactjs-auth-django-rest からフロントエンドソースをコピペします。
try🐶everything email-auth$ git clone https://github.com/ZachLiuGIS/reactjs-auth-django-rest try🐶everything email-auth$ cp -r reactjs-auth-django-rest/react_frontend/src/* frontend/src/
- 2必要なパッケージをインストールします。
try🐶everything src$ npm i prop-types react-router-dom react-redux bootstrap redux redux-form redux-form-validators redux-logger redux-notifications redux-thunk react-redux history axios
- 3const 文の位置を調整します。
yarn start コマンドで React 開発サーバを起動すると、下記のようなエラーが発生します。
エラー:
Failed to compile.
./src/actions/authActions.js
Line 8:1: Import in body of module; reorder to top import/first
Line 9:1: Import in body of module; reorder to top import/first
Line 10:1: Import in body of module; reorder to top import/first
Line 11:1: Import in body of module; reorder to top import/first
Search for the keywords to learn more about each error.対処:
actions/authActions.js ファイルを開き、const { notifSend } = notifActions; 文を import 文の下に移動しておきます。vi actions/authActions.js
import axios from “axios”;
import { SubmissionError } from ‘redux-form’;
import history from “../utils/historyUtils”;
import { actions as notifActions } from ‘redux-notifications’;
import { AuthTypes } from “../constants/actionTypes”;
import { AuthUrls } from “../constants/urls”;
import store from “../store”;
import { getUserToken } from “../utils/authUtils”;
const { notifSend } = notifActions; << ここに移動! - 4switch 文を修正します。
reducers/authReducer.js ファイルを開き、
default:
を追記します。vi reducers/authReducer.js
import { AuthTypes } from “../constants/actionTypes”;
export default function(state = {}, action) {
switch(action.type) {
case AuthTypes.LOGIN:
return { …state, authenticated: true, token: action.payload};
case AuthTypes.LOGOUT:
return { …state, authenticated: false, token: null};
case AuthTypes.USER_PROFILE:
return { …state, user: action.payload};
default: << 追加!
}
return state;
} - 5history の書き方を修正します。
utils/historyUtils.js ファイルを下記のように修正します。
vi utils/historyUtils.js
// import createHistory from “history/createBrowserHistory”;
// export default createHistory();
↓↓↓
import { createBrowserHistory } from ‘history’
export default createBrowserHistory(); - 6Notifs 設定を修正します。
エラー:
Could not find “store” in either the context or props of “Connect(Notifs)”. Either wrap the root component in a , or explicitly pass “store” as a prop to “Connect(Notifs)”.対処:
components/auth/App.js ファイルを修正します。vi components/auth/App.js
import React, { Component } from “react”;
import { Notifs } from “redux-notifications”;
import store from “../store”; << 追加!
import Header from “./Header”;
import MainContent from “./MainContent”;
export default class App extends Component {
render() {
return (
<div className=”container”>
<Notifs store={store} /> << 修正!
<Header />
<MainContent />
</div>
)
}
}これで、問題なく起動できると思います!
- 7no-unused-vars
エラー:
./src/components/auth/UserProfileEdit.js
Line 4:10: ‘required’ is defined but never used no-unused-vars対処:
該当行をコメントアウトするか削除します。import React, { Component } from "react"; import { reduxForm, Field, propTypes } from "redux-form"; import { connect } from "react-redux"; // import { required } from "redux-form-validators"
ユーザを登録
http://localhost:3000/signup から登録できます。
すると、アカウントを有効化するためのメールが送信されます。
有効な SMTP 設定をすれば、登録メールに送られますが、ここでは開発用の設定をしているためtmp/emails/ の下にメールログだけが保存されます。( ▼ )
メール本文のリンク ( ↑赤い線 ) をコピーしてブラウザの URL 入力欄にペーストします。
これで、メール認証でユーザ登録ができました。
以下は、ユーザ認証には直接関係ありませんが、登録ユーザのプロフィールをアップデートするための設定です。
UserProfile 項目を修正します。( 任意 )
components/auth/UserProfile.js を修正します。( Line 27〜29 )
import React, { Component } from "react"; import PropTypes from "prop-types"; import { connect } from "react-redux"; import { Link } from "react-router-dom"; import { getUserProfile } from "../../actions/authActions"; class UserProfile extends Component { static propTypes = { getUserProfile: PropTypes.func.isRequired, user: PropTypes.object }; componentWillMount() { this.props.getUserProfile(); } renderUser() { const user = this.props.user; console.log(user); if (user) { return ( <div className="mx-2"> <h4>Username: {user.username}</h4> <h4>First Name: {user.first_name}</h4> <h4>Last Name: {user.last_name}</h4> <h4>E-mail: {user.email}</h4> <h4>Company: {user.company}</h4> <h4>Department: {user.department}</h4> <h4>Current Position: {user.current_position}</h4> <hr /> <h4>About Myself:</h4> <p>{user.about}</p> </div> ); } return null; } render() { return ( <div> {this.renderUser()} <hr /> <Link className="btn btn-primary mr-2" to="/profile_edit"> Update Profile </Link> <Link className="btn btn-primary" to="/change_password"> Change Password </Link> </div> ); } } function mapStateToProps(state) { return { user: state.auth.user }; } export default connect( mapStateToProps, { getUserProfile } )(UserProfile);
components/auth/UserProfileEdit.js を修正します。 ( Line 56〜81 )
import React, { Component } from "react"; import { reduxForm, Field, propTypes } from "redux-form"; import { connect } from "react-redux"; import { renderField, renderTextAreaField, renderError } from "../../utils/renderUtils"; import { updateUserProfile } from "../../actions/authActions"; class Login extends Component { static propTypes = { ...propTypes }; render() { const { handleSubmit, error } = this.props; return ( <div className="row justify-content-center"> <form className="col col-sm-4 card mt-5 p-2" onSubmit={handleSubmit} > <h4 className="text-md-center">Edit Profile</h4> <hr /> <fieldset className="form-group"> <Field name="username" label="Username" component={renderField} type="text" /> </fieldset> <fieldset className="form-group"> <Field name="first_name" label="First Name" component={renderField} type="text" /> </fieldset> <fieldset className="form-group"> <Field name="last_name" label="Last Name" component={renderField} type="text" /> </fieldset> <fieldset className="form-group"> <Field name="company" label="Company" component={renderField} type="text" /> </fieldset> <fieldset className="form-group"> <Field name="department" label="Department" component={renderField} type="text" /> </fieldset> <fieldset className="form-group"> <Field name="current_position" label="Current Position" component={renderField} type="text" /> </fieldset> <fieldset className="form-group"> <Field name="about" label="About Yourself" component={renderTextAreaField} type="text" /> </fieldset> <fieldset className="form-group"> {renderError(error)} <button action="submit" className="btn btn-primary"> Save </button> </fieldset> </form> </div> ); } } function mapStateToProps(state) { return { initialValues: state.auth.user }; } export default connect(mapStateToProps)( reduxForm({ form: "update_user_profile", onSubmit: updateUserProfile })(Login) );
UserProfile をアップデートしてみます。
下記のリンクへアクセスし、変更した項目でアップデートできるか確認します。
http://localhost:3000/profile
http://localhost:3000/profile_edit
また、http://localhost:8000/api/user と http://localhost:8000/admin でも確認できます。
問題なく修正できれば OK です。
あとがき
※ やり残したこと ( メモ ):
・機能追加:ソーシャルログイン ( facebook / twitterなど )
※ 2019/12/18追記:興味のある方はご参考にどうぞ!▼
Twitter ソーシャルログイン機能を実装する〜Reactjs + Django〜
・登録時、Confirm Email フィールドを追加
・パスワードをリセットする際、登録されたメールアドレスかをチェック
コメント