Vue-Laravel-SPA icon indicating copy to clipboard operation
Vue-Laravel-SPA copied to clipboard

New User Registration

Open Wasca opened this issue 6 years ago • 9 comments

Do you have any examples on how to create a public New User Registration page?

This is a great little project and you have a login page for it but no user registration form.

I've created a registration form but I don't know how to use axios to submit the form and save a new user to the users table. I'm not using the customers tables like in your video, I'm just using the default users table to add new registrations.

I have the login process working as per your video series, just need to get the registration process working

Any help would be appreciated.

This is my api.php file

<?php

use Illuminate\Http\Request;

/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/

Route::group(['prefix' => 'auth'], function ($router) {

    Route::post('login', 'Auth\AuthController@login');
    Route::post('logout', 'Auth\AuthController@logout');
    Route::post('refresh', 'Auth\AuthController@refresh');
    Route::post('register', 'Auth\RegisterController@register');
    Route::post('me', 'Auth\AuthController@me');

});

This is my RegisterController.php

<?php

namespace App\Http\Controllers\Auth;

use App\User;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

class RegisterController extends Controller
{
    /*
    |--------------------------------------------------------------------------
    | Register Controller
    |--------------------------------------------------------------------------
    |
    | This controller handles the registration of new users as well as their
    | validation and creation. By default this controller uses a trait to
    | provide this functionality without requiring any additional code.
    |
    */

    use RegistersUsers;

    /**
     * Where to redirect users after registration.
     *
     * @var string
     */
    protected $redirectTo = '/login';

    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        //$this->middleware('guest');
        $this->middleware('auth:api', ['except' => ['register']]);
    }

    /**
     * Get a validator for an incoming registration request.
     *
     * @param  array  $data
     * @return \Illuminate\Contracts\Validation\Validator
     */
    protected function validator(array $data)
    {
        return Validator::make($data, [
            'name' => 'required|string|max:255',
            'email' => 'required|string|email|max:255|unique:users',
            'password' => 'required|string|min:6|confirmed',
        ]);
    }

    /**
     * Create a new user instance after a valid registration.
     *
     * @param  array  $data
     * @return \App\User
     */
    protected function register(Request $request)
    {
        $user = User::create($request->only(["name", "email", "password"]));
        
        return response()->json([
            "user" => $user
        ], 200);
    }

    /**
     * Override the default Laravel Guard here
     */
    public function guard(){
        return \Auth::Guard('api');
    }
}

This is my User.php file

<?php

namespace App;

use Tymon\JWTAuth\Contracts\JWTSubject;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable implements JWTSubject
{
    use Notifiable;
    protected $guarded = [];

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name', 'email', 'password',
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password', 'remember_token',
    ];
    
    /**
     * Get the identifier that will be stored in the subject claim of the JWT.
     *
     * @return mixed
     */
    public function getJWTIdentifier()
    {
        return $this->getKey();
    }

    /**
     * Return a key value array, containing any custom claims to be added to the JWT.
     *
     * @return array
     */
    public function getJWTCustomClaims()
    {
        return [];
    }
}

This is the script in my register.vue file that has the registration form.

<script>
import validate from 'validate.js'

export default {
  name: 'register',
  metaInfo: {
    title: 'Registration'
  },
  data() {
    return {
      form: {
        name: '',
        email: '',
        password: ''
      },
      errors: null
    }
  },
  methods: {
    register() {
      this.errors = null;

      const contraints = this.getContraints();

      const errors = validate(this.$data.form, contraints);

      if (errors) {
        this.errors = errors;
        return;
      }
      //Post New User Registration to the API
      axios.post('/api/auth/register', this.$data.form, {
      })
        .then((response) => {
          this.$router.push('/login');
        })
    },
    getContraints() {
      return {
        name: {
          presence: true,
          length: {
            minimum: 3,
            message: "must be at least 3 characters long"
          }
        },
        email: {
          presence: true,
          email: true,
        },
        password: {
          presence: true,
          length: {
            password: true,
            minimum: 6,
            message: "must be at least 6 characters long"
          }
        }
      }
    }
  }
}
</script>

This is the error I'm seeing when I submit my registration form

bluebird.min.js:29 Unhandled rejection TypeError: Cannot read property 'status' of undefined

and it points to this code

// Send to login page if user accesses a page that needs authentication and they are not logged in.
axios.interceptors.response.use(null, function (error) {
  if (error.resposne.status == 401) {
    store.commit('logout');
    router.push('/login');
  }
  return Promise.reject(error);
});

Wasca avatar Jul 03 '18 04:07 Wasca

DOH!!!!

Got it working. I decided to test using Postman just to make sure I could create a user.

I found that in my RegisterController.php file I was missing this

use Illuminate\Foundation\Auth\RegistersUsers;

Wasca avatar Jul 03 '18 07:07 Wasca

Just found out my new users are not having their password hashed before it is saved to the Data base. Got to work that out now.

Wasca avatar Jul 03 '18 07:07 Wasca

Great got that sorted also

I ended up doing this.

protected function register(Request $request)
    {
        $user = User::create([
            'name' => $request['name'],
            'email' => $request['email'],
            'password' => Hash::make($request['password']),
        ]);
        
    }

Also needed to add this to the top of the RegisterController.php

use Illuminate\Support\Facades\Hash;

Wasca avatar Jul 03 '18 07:07 Wasca

Still getting this error if I try and register the same user twice. This is obviously because the email address needs to be unique.

bluebird.min.js:29 Unhandled rejection TypeError: Cannot read property 'status' of undefined

and points to this code

// Send to login page if user accesses a page that needs authentication and they are not logged in.
axios.interceptors.response.use(null, function (error) {
  if (error.resposne.status == 401) {
    store.commit('logout');
    router.push('/login');
  }
  return Promise.reject(error);
});

For some reason my error messages don't seem to be getting handled correctly. Any ideas on where I can start?

Wasca avatar Jul 03 '18 07:07 Wasca

Garrrr!

Found the problem. I spelled response wrong!

I'm making progress, now I'm getting this error

bluebird.min.js:29 Unhandled rejection Error: Request failed with status code 500

How do I handle the Rejection error?

Wasca avatar Jul 03 '18 07:07 Wasca

Hi Afik

This I have registration working however I don't know how to handle the error message when I try to register a new client using the same email address. here is what I'm seeing in the console. the email address [email protected] is already in the users table which is why I'm getting the failed status. I just want to be able to use that status to display a message in form. Can you help me out?

Mark Wass SYSTEMS ADMINISTRATOR http://www.optuma.com p: +61 7 3117 0663 ext 303 s: markdwass e: [email protected] PO BOX 5528 Brendale 4500 QLD, AUSTRALIA www.optuma.com https://twitter.com/Optuma https://www.facebook.com/Optuma/ https://www.linkedin.com/company/optuma https://www.instagram.com/optuma/ https://stocktwits.com/optuma This message is confidential. It may also be privileged or otherwise protected by work product immunity or other legal rules. If you have received it by mistake, please let us know by e-mail reply and delete it from your system; you may not copy this message or disclose its contents to anyone. The integrity and security of this message cannot be guaranteed on the Internet.

On Tue, Jul 3, 2018 at 7:18 PM, Golam Mahmud Rafi [email protected] wrote:

Hi, you can use the bcrypt helper function like this $password = bcrypt('secret'); Hope it'll solve your issue.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/AfikDeri/Vue-Laravel-SPA/issues/4#issuecomment-402070904, or mute the thread https://github.com/notifications/unsubscribe-auth/AA1C-I48vMjIfhdM3oN06a0jJzI0amwmks5uCzbVgaJpZM4VAST_ .

Wasca avatar Jul 04 '18 00:07 Wasca

Thank you for that, Great work so far.

Some notes for your code so far so you can keep working on it:

  • The RegisterController doesn't need a middleware nor a constructor, the only method you have access from the outside is register().
  • The register() method should be public.
  • you can move the validations to a dedicated RegisterRequest.php file.
  • you should add a .catch() statement to your axios call so you can show the validation errors in case you have any.
  • you can replace the Hash::make('password') with the Laravel helper function bcrypt('password') and then you don't need to use ...\Hash
  • since you have only one method to handle registration you might want to move it to the AuthController and remove the RegisterController entirely.

Keep up the good work 👍

AfikDeri avatar Jul 07 '18 12:07 AfikDeri

`protected function validator(array $data) { return Validator::make($data, [ 'name' => 'required|string|max:255', 'email' => 'required|string|email|max:255|unique:users', 'password' => 'required|string|min:6|confirmed', ]); }

/**
 * Create a new user instance after a valid registration.
 *
 * @param  array  $data
 * @return \App\User
 */
protected function register(Request $request)
 {
    $user = User::create([
        'name' => $request['name'],
        'email' => $request['email'],
        'password' => Hash::make($request['password']),
    ]);
    
}`

you need to access your validator

`protected function register(array $data) { $user = User::create([ 'name' => $data['name'], 'email' => $data['email'], 'password' => Hash::make($data['password']), ]);

}`

carlosiv avatar Jul 07 '18 13:07 carlosiv

This is why I prefer to have a dedicated RegisterRequest file that can handle validations.

  1. php artisan make:request RegisterRequest
  2. inside the app/Http/Requests/RegisterRequest.php file:
/**
 * Determine if the user is authorized to make this request.
 *
 * @return bool
 */
public function authorize()
{
    return true;
}

/**
 * Get the validation rules that apply to the request.
 *
 * @return array
 */
public function rules()
{
    return [
        'name' => 'required|string|max:255',
        'email' => 'required|string|email|max:255|unique:users',
        'password' => 'required|string|min:6|confirmed',
    ];
}
  1. accept it as a parameter in your register() method:
use App\Http\Requests\RegisterRequest;

public function register(RegisterRequest $request) { ... }

It will redirect back with the validation errors in case you have any (or enter the method if the validation passed)

AfikDeri avatar Jul 07 '18 13:07 AfikDeri