• トップ
  • ブログ一覧
  • 【第3回】Responder + Firestore でモダンかつサーバーレスなブログシステムを作ってみた【管理者ページ整備】
  • 【第3回】Responder + Firestore でモダンかつサーバーレスなブログシステムを作ってみた【管理者ページ整備】

    メディアチームメディアチーム
    2020.07.22

    IT技術

    ~第3回~モダンなフレームワークの使い方を学びながらブログシステムを構築

    連載「Python Responder + Firestore で、モダンかつサーバーレスなブログシステムを作ってみる」第3回目です。

    前回は、「Firebase のセットアップ」と「認証機能の基盤」を作成しました。

    featureImg2020.07.20【第2回】Responder + Firestore でモダンかつサーバーレスなブログシステムを作ってみた【Firebase設定と認証機能実装】第2回~モダンなフレームワークの使い方を学びながらブログシステムを構築~本記事は、「Python Responder ...

    今回は、認証機能の整備ということで、「クッキー管理」と「ログアウト機能」を追加していきます。

    第2回目で作成したログイン機能はちゃんと機能していますが、とても不便な部分があります。

    それは、「管理者ページに POST でしか入れない」ことです。

    本来ならば、一度ログインすれば、GET でアクセスしても、ログインを介さずにアクセスできます。

    そういった機能は、Cookie を使って構築していきましょう。

    Responder では、Cookie の「セット」はresp.set_cookie() 、「取得」はreq.cookies です。

    したがって、以下の仕様にしたいと思います。

    1. ログイン成功時に Cookie をセット
    2. GET でのアクセス時に、Cookie にログインユーザがいれば、管理者ページを表示

    コード

    1# contorollers.py内
    2
    3COOKIE_EXPIRES = 5  # days later
    4
    5
    6@api.route('/admin')
    7class Admin:
    8    async def on_get(self, req, resp):
    9        # [new] ログインしてなければ
    10        if req.cookies.get('session') is None:
    11            api.redirect(resp, '/login')
    12
    13        # [new] ログイン済み
    14        else:
    15            resp.html = api.template('admin.html',
    16                                     title='管理者ページ',
    17                                     token=req.cookies.get('token'),
    18                                     name=req.cookies.get('username'))
    19
    20    async def on_post(self, req, resp):
    21        # POSTデータを取得
    22        data = await req.media()
    23        email = data['email']
    24        password = data['password']
    25
    26        # 認証
    27        res = _login(email, password)
    28
    29        if 'error' not in res:
    30            # [new] クッキーにログイン情報をセット
    31            expires = datetime.now() + timedelta(COOKIE_EXPIRES)
    32            resp.set_cookie(key='session', value=session, expires=expires)
    33            resp.set_cookie(key='username', value=res['displayName'], expires=expires)
    34            resp.set_cookie(key='email', value=email, expires=expires)
    35
    36            # 認証成功ならば管理者ページへ
    37            resp.html = api.template('admin.html',
    38                                     title='管理者ページ',
    39                                     name=res['displayName'])
    40        else:
    41            # 認証失敗ならばエラーメッセージをログイン画面に渡してリダイレクト
    42            api.redirect(resp, '/login?error={}'.format(res['error']['errors'][0]['message']))

    これで、ログインをしていれば、管理者ページに GET でログインできます。

    一定時間後に Cookie の自動破棄をする」仕様にしたい場合は、どうすればいいのでしょう?

    そんな時は、expires=**, max_age=** で変更します。

    expires は「日付」、max-age は「破棄までの秒数」を指定します。

    今回は、5日間としました。

    ログアウト機能

    次に、ログアウト機能を「/logout」に作成します。

    実装内容はとても単純で、Cookie を破棄すれば OK です。

    1# controllers.py内
    2@api.route('/logout')
    3def logout(req, resp):
    4    # クッキーのログイン情報を破棄してリダイレクト
    5    resp.set_cookie(key='session', value='', expires=0, max_age=0)
    6    resp.set_cookie(key='username', value='', expires=0, max_age=0)
    7    resp.set_cookie(key='email', value='', expires=0, max_age=0)
    8
    9    api.redirect(resp, '/login')

    実際に、ログイン後に「/logout」にアクセスしてみてください。

    その後「/admin」にGETでアクセスしても、ログイン画面に戻されるはずです。

    管理者ページを整える

    最後に、管理者ページを軽く整えておきましょう。

    管理者ページでは、「投稿の編集や追加」「プロフィールの編集」などができます。

    注意

    あなたの好みのデザインを使って構いません。

    また、今回作ったデザインに仮データは入っていますが、これはいずれ消します

    1<!--
    2templates/admin.html
    3管理者ページ
    4-->
    5
    6{% extends "layout.html" %}
    7{% block content %}
    8
    9<br>
    10<h1>My Blog Name | 管理者ページ</h1>
    11<p>こんにちは,{{ name }} さん</p>
    12
    13<div class="main-container">
    14    <div class="admin-main-menu">
    15        <h2>投稿一覧</h2>
    16        <table>
    17            <tr>
    18                <th style="width: 5%;">#</th>
    19                <th style="width: 40%;">タイトル</th>
    20                <th style="width: 10%;">作成者</th>
    21                <th style="width: 10%;">スラッグ</th>
    22                <th style="width: 10%;">カテゴリ</th>
    23                <th style="width: 10%;">タグ</th>
    24                <th style="width: 15%;">最終更新日</th>
    25            </tr>
    26            <tr>
    27                <td>0</td>
    28                <td>テスト投稿</td>
    29                <td>rightcode</td>
    30                <td>test-post</td>
    31                <td>Test</td>
    32                <td>post</td>
    33                <td>2020.06.03</td>
    34            </tr>
    35            <tr>
    36                <td>1</td>
    37                <td>ブログを作りました!</td>
    38                <td>rightcode</td>
    39                <td>create-blog</td>
    40                <td>未分類</td>
    41                <td></td>
    42                <td>2020.06.03</td>
    43            </tr>
    44        </table>
    45    </div>
    46    <div class="admin-side-menu">
    47        <h2>Menu</h2>
    48        <ul>
    49            <li><a href="/admin/profile">プロフィール確認・編集</a></li>
    50            <li><a href="/admin/new">新規追加</a></li>
    51            <li><a href="/admin">投稿一覧</a></li>
    52            <li><a href="/logout">ログアウト</a></li>
    53        </ul>
    54    </div>
    55</div>
    56
    57{% endblock %}

    CSS 追記

    さらに、CSSも追記します。

    1.main-container{
    2    display: flex;
    3}
    4.admin-main-menu{
    5    width: 80%;
    6}
    7.admin-main-menu table{
    8    width: 95%;
    9    border-collapse:collapse;
    10    margin:auto;
    11}
    12.admin-main-menu  td,th{
    13    padding:10px;
    14}
    15.admin-main-menu  th{
    16    color:#fff;
    17    background: #657ccb;
    18    border-right: 1px solid #416092;
    19}
    20.admin-main-menu  td{
    21    text-align: center;
    22    border-bottom:1px solid #c8d6ee;
    23}
    24
    25.admin-side-menu{
    26    width: 20%;
    27}
    28.admin-side-menu a{
    29    text-decoration: none;
    30    color: #1e366a;
    31}
    32.admin-side-menu a:hover{
    33    opacity: 0.7;
    34}
    35.admin-side-menu h2{
    36    color: #1e366a;
    37    margin-top: 1.5em;
    38    margin-bottom: 0;
    39}
    40.admin-side-menu ul{
    41    color: #1e366a;
    42    border-top: solid #1e366a 1px;
    43    border-bottom: solid #1e366a 1px;
    44    padding: 2.5em 0 0.5em 1.5em;
    45    margin-top: 0.5em;
    46}
    47
    48.admin-side-menu ul, li{
    49    line-height: 1.5;
    50    padding: 0.5em 1.5em;
    51}

    完成!

    管理者ページを簡単にデザイン

    サイドメニューのリンクは、後ほどコーディングしていきます。

    もちろん、今はまだ動作しません。

    第4回へつづく!

    今回は、「認証機能の整備」と「管理者ページ整備」を行いました。

    まだあんまりブログっぽくないですね…。

    次回からは、いよいよ「ブログ記事とデータベース周りの整備」を行っていきます!

    具体的には、「カテゴリの追加」「記事の追加」などを実装していきます。

    お楽しみに!

    次回の記事はこちら

    featureImg2020.07.30【第4回】Responder + Firestore でモダンかつサーバーレスなブログシステムを作ってみる【モデルの構築】第4回~モダンなフレームワークの使い方を学びながらブログシステムを構築~連載「Python Responder + F...

    第1回はこちら

    featureImg2020.07.17【第1回】Responder + Firestore でモダンかつサーバーレスなブログシステムを作ってみた【初期セットアップ編】モダンなフレームワークの使い方を学びながらブログシステムを構築今回より、また新たに Python WebAPI 関連の...

    こちらの記事もオススメ!

    featureImg2020.07.17ライトコード的「やってみた!」シリーズ「やってみた!」を集めました!(株)ライトコードが今まで作ってきた「やってみた!」記事を集めてみました!※作成日が新し...

    featureImg2020.07.30Python 特集実装編※最新記事順Responder + Firestore でモダンかつサーバーレスなブログシステムを作ってみた!P...

    ライトコードでは、エンジニアを積極採用中!

    ライトコードでは、エンジニアを積極採用しています!社長と一杯しながらお話しする機会もご用意しております。そのほかカジュアル面談等もございますので、くわしくは採用情報をご確認ください。

    採用情報へ

    メディアチーム
    メディアチーム
    Show more...

    おすすめ記事

    エンジニア大募集中!

    ライトコードでは、エンジニアを積極採用中です。

    特に、WEBエンジニアとモバイルエンジニアは是非ご応募お待ちしております!

    また、フリーランスエンジニア様も大募集中です。

    background