2018-10-17に更新

Twitterを作る 第2回 認証

まずはユーザー登録。これがなければ何も話が進まない。
ひとまず下記の第3回までを見てさくっと動作確認とユーザーテーブル作成まで行う。

Python Django入門 (1)

Python Django入門 (3)

ログイン前トップページ

material-uiでさくっと作成。Twitterのトップ画面を見ると今回必要そうなコンテンツはこれだけ。
アカウント作成でsignupページヘ。

ユーザー登録ページ

こちらも同様にぱぱっと作成。
このページはユーザー登録とログインのサーバーへの通信が必要なのだが、
そのままだとCSRFでエラーになるのでensure_csrf_cookieを設定している。
また、後述するconfigライブラリを作成している。

ちなみにログインを押すとモーダルが出てくる。

configライブラリ

全体の共通機能として下記のようなファイルを作成した。

app/lib/config.js

const config = {
    defaultHeaders: {
        "X-CSRFToken": getCookie('csrftoken'),
        "Accept": "application/json",
    },
    url: (url) => {
        if (url.charAt(0) === '/') {
            url = url.substr(1);
        }
        return '/dumitter/' + url;
    },
}

module.exports = config;

現在さくらサーバーのそのままのURL(SSL)なので、
今後独自ドメインを使う場合全箇所の修正は大変になるためurl補正メソッドを作成。
(最初から独自ドメインなら絶対パスで良いのだが)

また、ajaxの際にCSRFのトークンを送信するため、共通のデフォルトヘッダを定義している。
(getCookieは検索すれば出てくる)

バリデーション & 登録処理

postするとjsonを返却するアクション。
resultがtrueなら成功でログイン済みなのでトップページへリダイレクト。
falseならjsonに各フィールド名のエラーメッセージが入っているのでmaterial-uiのTextFieldのerrorTextにセット。

バリデーションの処理は全部python側でやっている。
js側でもいいかと思ったのだが、パスワードの細かいバリデーションがdjango側に入っているのでそちらに統一した。
(設定ファイルで細かいパスワードのバリデーション方法を指定することができる)

本当はもっとちゃんとした書き方がありそうだが、この処理はここだけだしいいかと思いバリデーションもベタ書き。

from django.http.response import JsonResponse
from django.contrib.auth import authenticate, login as authLogin
from django.contrib.auth.models import User
from django.core.validators import validate_email
from django.contrib.auth.password_validation import validate_password
from django.db import IntegrityError
from django.core.exceptions import ValidationError
import re

def create(request):
    errors = {}

    if re.match(r'^[\da-zA-Z_]+$', request.POST['name']) is None:
        errors['name'] = '半角英数字で入力して下さい。'

    try:
        validate_email(request.POST['email'])
    except ValidationError as e:
        errors['email'] = e.messages

    try:
        validate_password(request.POST['password'])
    except ValidationError as e:
        errors['password'] = e.messages

    if len(errors) == 0:
        try:
            user = User.objects.create_user(
                username=request.POST['name'],
                email=request.POST['email'],
            )
        except IntegrityError as e:
            if 'email' in str(e):
                errors['email'] = 'そのメールアドレスは既に使用されています。'
            elif 'name' in str(e):
                errors['name'] = 'そのユーザー名は既に使用されています。'

    if len(errors) != 0:
        errors['result'] = False
        return JsonResponse(errors)

    user.set_password(request.POST['password'])
    user.save()

    return login(request)


def login(request):
    authed = authenticate(
        username=request.POST['name'],
        password=request.POST['password'],
    )
    result = {'result': True}

    if authed is not None:
        authLogin(request, authed)
    else:
        result['result'] = False

    return JsonResponse(result)

新規登録後は自動的にログインするが、通常のログインのプログラムと全く同じだったので関数を流用している。

ログイン後はトップページにリダイレクトするが、
ここではログインの場合別のテンプレートを表示するようにしている。

def index(request):
    if request.user.is_authenticated():
        template = 'main.html'
    else:
        template = 'index.html'
    return render(request, template)

React側

多分邪道かも知れないが下記のようなことを行っている。

const element = document.getElementById('auth-regist');
if (element != undefined) {
    ReactDOM.render(<AuthRegist />, element);
}

認証側はこれ以上ページを作るつもりはないので適当。
認証後はルーティングを使いたい。

これで認証が完成したので次は投稿を作っていく予定。

https://alphabrend.sakura.ne.jp/dumitter/

Twitterを作る 第3回 投稿


view_list [連載] Twitterを作る
第1回 Twitterを作る 第1回 概要
第2回 Twitterを作る 第2回 認証
第3回 Twitterを作る 第3回 投稿
第4回 Twitterを作る 第4回 コンポーネント構成考察
第5回 Twitterを作る 第5回 フォロー

だら@Crieit開発者

Crieitの開発者です。 主にLAMPで開発しているWebエンジニアです(在宅)。大体10年程。 記事でわかりにくいところがあればDMで質問していただくか、案件発注してください。 業務依頼、同業種の方からのコンタクトなどお気軽にご連絡ください。 業務経験有:PHP, MySQL, Laravel5, CakePHP3, JavaScript, RoR 趣味:Elixir, Phoenix, Node, Nuxt, Express, Vue等色々

Crieitは個人で開発中です。 興味がある方は是非記事の投稿をお願いします! どんな軽い内容でも嬉しいです。
なぜCrieitを作ろうと思ったか

また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!

こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください!

ボードとは?

関連記事

コメント