SilverStripへの登録の追加とPrivelegesの制御


今日、我々は我々の前の記事で始めた基本的な本レビュープラットホームに基本的な特徴を加えています.最後に我々は本、著者を追加し、このsilverstripベースのアプリケーションでモデルを確認します.我々は、多少退屈な方法で、レビューを追加する機能を持っていたが、1つだけのユーザーがそうすることができます.今日、我々は我々のアプリケーションに登録ページを追加する方法を参照してください多くの部分を取ることができますし、彼らがアクセスできるコンテンツを制御します.

And as previous, if you want to check out the code for this page, you can find it here: https://github.com/andersbjorkland/devto-book-reviewers/tree/registration



登録ページ
silverstripでユーザを扱うためのモデルがすでに存在します.これはメンバークラスによって表され、CMSでパッケージから出てきます.新しいメンバーを作成するための登録ページを作成します.
必要なのは
  • 登録フォームをフォームに登録し、フォームの送信を処理するRegisterController.
  • 登録フォームを表示するテンプレート.
  • 登録ページへのルート.
  • かなり簡単、右の音?さて、誰かがこれを書いていると言いましょう、彼はそれが単純であると思いましたので、いくつかのエラーを鉄にしなければなりませんでした.我々がここですることはエラーフリーです(そして、我々は意味をなす方法でそれをします).

    不思議なregistercontroller
    不思議なことは少し双曲線かもしれませんが、簡単なコントローラから始めて、きちんとした機能を追加します.コントローラの主な目的は、フォームの提出を提供し、処理することです.ちょっと見ましょう.
    /app/src/controller/registerControllerPHP
    <?php
    
    namespace App\Controller;
    
    use App\Form\ValidatedAliasField;
    use App\Form\ValidatedEmailField;
    use App\Form\ValidatedPasswordField;
    use SilverStripe\CMS\Controllers\ContentController;
    use SilverStripe\Forms\FieldList;
    use SilverStripe\Forms\Form;
    use SilverStripe\Forms\FormAction;
    use SilverStripe\Forms\RequiredFields;
    use SilverStripe\Security\Member; // Will be used later when we do register a new member.
    
    class RegistrationController extends ContentController
    {   
        private static $allowed_actions = [
            'registerForm'
        ];
    
        public function registerForm()
        {
            $fields = new FieldList(
                ValidatedAliasField::create( 'alias', 'Alias')->addExtraClass('text'),
                ValidatedEmailField::create('email', 'Email'),
                ValidatedPasswordField::create('password', 'Password'),
            );
    
            $actions = new FieldList(
                FormAction::create(
                    'doRegister',   // methodName
                    'Register'      // Label
                )
            );
    
            $required = new RequiredFields('alias', 'email', 'password');
    
            $form = new Form($this, 'RegisterForm', $fields, $actions, $required);
    
            return $form;
        }
    
        public function doRegister($data, Form $form)
        {
            // To be detailed later
        }
    }
    
    
    我々が見ることができるように、コントローラはかなり簡単です.という方法があるregisterForm これはフォームを返し、$registerForm . 私たちは、新しいPage -それを表示するためにこのコントローラとテンプレートへのエントリーの我々のポイントになるでしょう.
    提供されるフォームは、3つのフィールドを持つフィールドリストで構成されます.最初のフィールドはValidatedAliasField , 二つ目はValidatedEmailField , そして3番目はValidatedPasswordField . これらのフィールドは、さまざまな検証規則で作成するカスタムフィールドです.フォームへの登録ボタンを添付しますdoRegister メソッドをクリックします.我々が得る前にdoRegister メソッドは、カスタムフィールドに対応する必要があります.

    カスタムフィールド
    検証規則を使用すると、エイリアスとメールアドレスが一意であることを制御できます.また、パスワードを少なくとも8文字にする必要があります.次のようにします.
    /app/src/form/validatedaliasfields.PHP
    <?php 
    
    namespace App\Form;
    
    use SilverStripe\Forms\TextField;
    use SilverStripe\Security\Member;
    
    class ValidatedAliasField extends TextField
    {
        public function validate($validator)
        {
            $alias = $this->Value();
            $member = Member::get()->filter(['FirstName' => $alias])->first();
    
            if ($member) {
                $validator->validationError(
                    $this->name,
                    'Alias is already in use',
                    'validation'
                );
                return false;
            }
            return true;
        }
    }
    
    /app/src/form/validatedEmailField.PHP
    <?php 
    
    namespace App\Form;
    
    use SilverStripe\Forms\EmailField;
    use SilverStripe\Security\Member;
    
    class ValidatedEmailField extends EmailField
    {
        public function validate($validator)
        {
            $email = $this->Value();
            $member = Member::get()->filter(['Email' => $email])->first();
    
            if ($member) {
                $validator->validationError(
                    $this->name,
                    'Email is already in use',
                    'validation'
                );
                return false;
            }
            return true;
        }
    }
    
    
    /app/src/form/validatedPasswordフィールド.PHP
    <?php 
    
    namespace App\Form;
    
    use SilverStripe\Forms\PasswordField;
    
    class ValidatedPasswordField extends PasswordField
    {
        public function validate($validator)
        {
            $value = $this->Value();
            if (strlen($value) < 6) {
                $validator->validationError(
                    $this->name,
                    'Password must be at least 6 characters long',
                    'validation'
                );
                return false;
            }
            return true;
        }
    }
    
    これらのクラスから見えているかもしれないように、我々はちょうど我々が検証したいどんな分野でも広げています.我々は、オーバーライドする必要がありますvalidate() メソッドと独自の検証規則を適用します.エイリアスとメールの両方については、値が既に使用中かどうかチェックする必要があります.ユーザーがそれを見つけたなら、妥当性検査は失敗します.パスワードについては、長さが6文字以上であるかどうかをチェックする必要があります.我々のコントローラでフォームデータを受け取るとき、我々はvalidationResult() フォームの提出が有効かどうかをチェックするメソッドです.以下で読んでください.そうすれば、我々は新しいメンバーを作成するとき、我々にそれをします.

    新しいメンバーの作成
    それで、我々はフォームを提出しました、そして、我々はその内容を捕えて、それをデータベースに格納する何かを必要とします.
    更新します.アプリケーション/src/controller/regitiontionController.PHP
    <?php
    
    namespace App\Controller;
    
    use App\Form\ValidatedAliasField;
    use App\Form\ValidatedEmailField;
    use App\Form\ValidatedPasswordField;
    use SilverStripe\CMS\Controllers\ContentController;
    use SilverStripe\Forms\FieldList;
    use SilverStripe\Forms\Form;
    use SilverStripe\Forms\FormAction;
    use SilverStripe\Forms\RequiredFields;
    use SilverStripe\Security\Member; // Yay, this comes in handy now!
    
    class RegistrationController extends ContentController
    {   
        private static $allowed_actions = [
            'registerForm'
        ];
    
    
        public function registerForm()
        {
            // ...
        }
    
        public function doRegister($data, Form $form)
        {
            // Make sure we have all the data we need
            $alias = $data['alias'] ?? null;
            $email = $data['email'] ?? null;
            $password = $data['password'] ?? null;
    
            /* 
             * Check if the fields clear their validation rules.
             * If there are errors, then the form will be updated with the errors
             * so the user may correct them.
             */
            $validationResults = $form->validationResult();
    
            if ($validationResults->isValid()) {
                $member = Member::create();
                $member->FirstName = $alias;
                $member->Email = $email;
                $member->Password = $password;
                $member->write();
    
                $form->sessionMessage('Registration successful', 'good');
            }
    
            return $this->redirectBack();
        }
    }
    
    このメソッドはフォームデータを受け取り、有効かどうかをチェックします.もしあれば、新しいメンバーを作成し、データベースに書き込みます.それがそうでないならば、それはユーザーをRegistrationページに向け直します.

    Something to note for the security-conscious developer is that it appears as we simply set a plain password to the Member. This is not a good practice, as it is not secure. It's a good thing then that the Member-class hashes the password before writing it to the database (with onBeforeWrite()). Read more about passwords and security on the official documentations on SilverStripe.


    これまでのところ良い.我々は、フォームとそのフィールドを作成している.我々は、フォームを提供し、その提出を処理するコントローラを持っています.でも!我々はそれをまだ見る方法がない.

    登録ページの作成
    我々は、フォームを提供するページとルートが必要です.また、$ registerForm変数(またはフォームに役立つコントローラメソッド)にフックするテンプレートも必要です.
    これが計画です.
  • RegistrationControllerを指すRegisterPageを作成します.
  • 登録フォームを含むテンプレートを作成します.
  • RegisterPageのインスタンスを作成し、そのルートとタイトルを指定します.
  • ページのサブクラスとしてRegisterPageを作成する
    /app/src/page/registerpagePHP
    <?php
    
    namespace App\Page;
    
    use App\Controller\RegistrationController;
    use Page;
    
    class RegistrationPage extends Page
    {
        public function getControllerName()
        {
            return RegistrationController::class;
        }
    }
    
    
    これはページタイプの新しいモデルです(実際には、それはsitetreeです、しかし、それは点のそばにあります).このクラスの新しいインスタンスを作成するたびに、SilverStripはその名前空間に対応するテンプレートを探します.だから、1つを作成しましょう.
    テンプレートレイアウトの作成
    /etc/simple/template/app/page/layout/registrationpage.SS
    <% include SideBar %>
    <div class="content-container unit size3of4 lastUnit">
        <article>
            <h1>$Title</h1>
            <div class="content">$Content</div>
        </article>
        $registerForm
    </div>
    

    A note on the theme: If you have created a copy of simple and are working on that one instead, remember to change the name of the theme to "whatever-you-have-called-it" in app\_config\theme.yml. Then you need to run composer vendor-expose to copy/expose any public assets to the public folder.


    レジストリページをインスタンス化する
    現在登録ページがほとんどあります.管理インターフェイスを使用して作成しますが、その前にデータベースを更新する必要があります.ブラウザで、localhost:8000/dev/buildさあ訪問localhost:8000/admin . ログインするとき、デフォルトで「ページ」タブが表示されます.をクリックしましょうAdd new . ステップ1では「トップレベル」にします.ステップ2で我々は選択Registration Page . これは我々がコード化したタイプです.次に我々はCreate . これによりページを編集できます.以下を加えましょう
    ページ名
    登録
    URLセグメント
    登録
    ナビゲーションラベル
    登録
    内容
    新規ユーザ登録
    それから、我々はクリックすることができますSave . ローディング後はPublish . 我々は、現在、ほとんど登録されたユーザーを我々のサイトに受け入れる準備ができています.

    新しいユーザへの優先順位の追加
    だから我々のユーザーが登録することができますが、推測?管理インターフェイスにアクセスできません.我々は彼らのレビューを行うことができるし、おそらく他の人々のレビューを参照してくださいすることができます.だからこれは計画です.
  • 我々は、“Reviewers”と呼ばれる新しいグループを作成します.
  • 私たちは、私たちのコントローラーでそのグループに新しいメンバーを加えます.
  • 我々のモデルを更新しますAuthor , Book , Review ) 新しいグループがアクセスできるようにする.

  • 新しいグループの作成
    SilverStripの管理インターフェイスのパワーで、このグループを作成しましょう.サイドバーメニューでSecurity . 次に、Groups 右上隅のタブ.ボタンをクリックするAdd Group . タブの下にMembers , グループ名を入力しましょうReviewers . 次に、タブに切り替えるPermissions . 我々は、アクセス許可'アクセス'レビュー'セクションを追加します.次にCreate .

    メンバーをレビューグループに追加する
    我々は今、レビューを追加するには、アクセスprivelegesとグループがあります.メンバーが登録するときにメンバーがこのprivelegeを取得することを確認しましょう.我々は、更新することによってこれを行うdoRegister メソッドでRegistrationController :
    /app/src/controller/regitiontionControllerPHP
    //...
        public function doRegister($data, Form $form)
        {
            $alias = $data['alias'] ?? null;
            $email = $data['email'] ?? null;
            $password = $data['password'] ?? null;
    
            $validationResults = $form->validationResult();
    
            if ($validationResults->isValid()) {
                $member = Member::create();
                $member->FirstName = $alias;
                $member->Email = $email;
                $member->Password = $password;
                $member->write();
    
                // HERE IS OUR UPDATE 👇
                $member->addToGroupByCode("reviewers");
                $member->write();
    
                $form->sessionMessage('Registration successful', 'good');
            }
    
            return $this->redirectBack();
        }
    //...
    

    It may look clunky having to write the member twice. We do this so we have a database-ID for the member that can be associated to the group Reviewers.



    モデルとパーミッション
    今、私たちは、新しいグループを持つユーザーが彼らにアクセスするのを許すために、我々のモデルを更新する必要があります.メソッドを追加することでこれを行いますcanView , canEdit , canCreate and canDelete 我々のモデルに.本質的には、我々は、CMSのレビューセクションを表示するためのアクセスを持っているユーザーがそれぞれのモデルにアクセスすることを保証しています.
    /app/src/model/authorPHP
    <?php
    
    namespace App\Model;
    
    use App\Admin\ReviewAdmin;  // 👈 Remember to include this
    use SilverStripe\ORM\DataObject;
    use SilverStripe\Security\Permission; // 👈 and this
    
    class Author extends DataObject
    {
       // ...
    
        public function canView($member = null) 
        {
            return Permission::check('CMS_ACCESS_' . ReviewAdmin::class, 'any', $member);
        }
    
        public function canEdit($member = null) 
        {
            return Permission::check('CMS_ACCESS_' . ReviewAdmin::class, 'any', $member);
        }
    
        public function canDelete($member = null) 
        {
            return Permission::check('CMS_ACCESS_' . ReviewAdmin::class, 'any', $member);
        }
    
        public function canCreate($member = null, $context = []) 
        {
            return Permission::check('CMS_ACCESS_' . ReviewAdmin::class, 'any', $member);
        }
    }
    
    /app/src/model/bookPHP
    <?php
    
    namespace App\Model;
    
    use App\Admin\ReviewAdmin; // 👈 Remember to include this
    use SilverStripe\ORM\DataObject;
    use SilverStripe\Security\Permission; // 👈 and this
    
    class Book extends DataObject
    {
        // ...
    
        public function canView($member = null) 
        {
            return Permission::check('CMS_ACCESS_' . ReviewAdmin::class, 'any', $member);
        }
    
        public function canEdit($member = null) 
        {
            return Permission::check('CMS_ACCESS_' . ReviewAdmin::class, 'any', $member);
        }
    
        public function canDelete($member = null) 
        {
            return Permission::check('CMS_ACCESS_' . ReviewAdmin::class, 'any', $member);
        }
    
        public function canCreate($member = null, $context = []) 
        {
            return Permission::check('CMS_ACCESS_' . ReviewAdmin::class, 'any', $member);
        }   
    }
    
    /app/src/model/reviewPHP
    <?php
    
    namespace App\Model;
    
    use App\Admin\ReviewAdmin; // 👈 Remember to include this
    use SilverStripe\ORM\DataObject;
    use SilverStripe\Security\Member;
    use SilverStripe\Security\Permission; // 👈 and this
    use SilverStripe\Security\Security;
    
    class Review extends DataObject
    {
        // ...
    
        public function canView($member = null) 
        {
            return Permission::check('CMS_ACCESS_' . ReviewAdmin::class, 'any', $member);
        }
    
        public function canEdit($member = null) 
        {
            $reviewer = $this->Member()->ID;
            $currentUser = Security::getCurrentUser()->ID;
            if ($reviewer === $currentUser) {
                return true;
            } else {
                return false;
            }
        }
    
        public function canDelete($member = null) 
        {
            $reviewer = $this->Member()->ID;
            $currentUser = Security::getCurrentUser()->ID;
            if ($reviewer === $currentUser) {
                return true;
            } else {
                return false;
            }
        }
    
        public function canCreate($member = null, $context = []) 
        {
            return Permission::check('CMS_ACCESS_' . ReviewAdmin::class, 'any', $member);
        }
    
    }
    
    私たちはReview モデルは、Author and Book . 私たちは他のレビューを見て私たちのレビューが、著者だけが編集または削除することができます.私たちのモデルを更新してデータベースを更新する必要があります.私たちは` localhost : 8000/dev/build 'を訪れます.

    登録とレビュー!
    それを包んで、我々は登録システムを含むために我々の本レビュープラットホームを広げました.ユーザーがサインアップすることができますし、その砂丘のレビューを開始!


    次は何ですか.
    執筆レビューはまだ非常に快適ではない.私たちが次にこのプロジェクトを再訪するとき、私たちはどのようにそれをよりよくすることができるかについて見ます.
    私たちが出発する前に注意するいくつかのこと:現在登録されているときにユーザーが既にログインしているかどうかチェックはありません.RegisterControllerでこれをチェックできました.もう一つは、ナビゲーションページにログインリンクを追加することです.我々は、我々のユーザーが/admin ページ.
    何かを学ぶか、何かを追加するか?自由にコメントを残してください.