DjangoMacBook PromacOSPythonReact メール認証ユーザ登録

メール認証方式のユーザ登録機能を実装する〜Reactjs + Django 環境|macOS〜

squirrel-mail-auth Django
スポンサーリンク

フロントエンド環境を構築

開発用サイトを Django 側に登録します。

ここでの開発用サイトは localhost:3000 を指します。ユーザ登録時、ユーザに送信されるメール本文の中に使用されますので、フロントエンド環境を設定する前に済ませておきます。ちなみに、( 本番環境なら your-domain.com のように変更する必要があります )

project/settings.pyEMAIL_FILE_PATHDEFAULT_FROM_EMAIL の内容がメール本文に反映されます。
EMAIL_FILE_PATH = ‘tmp/emails’
DEFAULT_FROM_EMAIL = ‘admin@mydomin.com’

※ メールログの例:

vi tmp/emails/20191009-080755-4357263656.log  <<  project/settings.py の EMAIL_FILE_PATH

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
サイトを登録
  • Django Admin サイトにログインします。

    http://localhost:8000/admin/sites/site/add

  • 2
    localhost:3000 を登録します。
    django-add-site

    ※ デフォルトで example.com ドメインが入っていますが、削除しないでください。

  • 3
    追加されたサイト名をクリックします。
    django-add-site-2

    若しくは、サイト名にマウスオーバーしてブラウザ左下のステータスメッセージでサイトIDが確認できます。確認できたらサイト名をクリックしなくて結構です。
    http://127.0.0.1/admin/sites/site/2/change/

  • 4
    URL 入力欄からサイト ID を確認します。

    ここではサイト ID = です。( サイト ID は環境によって異なります )

    django-add-site-3
  • 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 を利用しますが、そのままではエラーが発生するため使えません。したがって、以下の手順で修正していきます。

Reactjs 環境
  • reactjs-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
  • 3
    const 文の位置を調整します。

    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; << ここに移動!
  • 4
    switch 文を修正します。

    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;
    }

     

  • 5
    history の書き方を修正します。

    utils/historyUtils.js ファイルを下記のように修正します。

    vi utils/historyUtils.js

    // import createHistory from “history/createBrowserHistory”;
    // export default createHistory();
    ↓↓↓
    import { createBrowserHistory } from ‘history’
    export default createBrowserHistory();
  • 6
    Notifs 設定を修正します。

    エラー:
    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>
      )
     }
    }

    これで、問題なく起動できると思います!

  • 7
    no-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 から登録できます。

django-react-sign-up
▲ ユーザを登録します
django-react-sign-up-done
▲ メールで確認リンクが送られます

すると、アカウントを有効化するためのメールが送信されます。
有効な SMTP 設定をすれば、登録メールに送られますが、ここでは開発用の設定をしているためtmp/emails/ の下にメールログだけが保存されます。( ▼ )

django-react-confirm-mail
▲ ドメインは追加したサイト ( localhost:3000 ) に変更されています。

メール本文のリンク ( 赤い線 ) をコピーしてブラウザの URL 入力欄にペーストします。

django-react-activate-account

これで、メール認証でユーザ登録ができました。

以下は、ユーザ認証には直接関係ありませんが、登録ユーザのプロフィールをアップデートするための設定です。

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/userhttp://localhost:8000/admin でも確認できます。

問題なく修正できれば OK です。

あとがき

※ やり残したこと ( メモ )
・機能追加:ソーシャルログイン ( facebook / twitterなど )

※ 2019/12/18追記興味のある方はご参考にどうぞ!▼
Twitter ソーシャルログイン機能を実装する〜Reactjs + Django〜

・登録時、Confirm Email フィールドを追加
・パスワードをリセットする際、登録されたメールアドレスかをチェック

コメント

タイトルとURLをコピーしました