Closed patrickgarsow-harvard closed 2 years ago
Hi @patrickgarsow-harvard
Below is an AuthController I'm using in a project (repo) that uses Sanctum that may be useful to you as an example. In the register method, we see the following code to create the new user (i.e. register them):
$user = User::create([
'name' => $request->name,
'email' => $request->email,
'password' => \Hash::make($request->password)
]);
You should be able to update this to include any additional field data you need.
Note that in this example I'm using a method called "mass assignment" to generate a new model - https://laravel.com/docs/9.x/eloquent#mass-assignment. This is slightly different than the approach shown in lecture, and requires you update the corresponding model so it has a fillable property with a list of all the fields that can be filled via mass assignment.
For example, imagine I wanted to also track city with my users. My creation code would look like this:
$user = User::create([
'name' => $request->name,
'email' => $request->email,
'password' => \Hash::make($request->password)
'city' => $request->city;
]);
And my User Model would have the fillable property updated to look like this:
protected $fillable = [
'name', 'email', 'password', 'city'
];
Of course, you'd also want to update your users migration to include a city field.
Here's the full AuthController.php:
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Str;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Auth;
use App\Models\User;
use Validator;
use Session;
class AuthController extends Controller
{
/**
* POST /auth
* When the client is first mounted, it pings this route to check its authentication status
*/
public function auth(Request $request)
{
$response = [
'success' => true,
'authenticated' => $request->user() ? true : false,
'user' => $request->user(),
];
return response($response, 200);
}
/**
* POST /login
*/
public function login(Request $request)
{
$validator = Validator::make($request->all(), [
'email' => 'required|email',
'password' => 'required'
]);
if ($validator->fails()) {
return response([
'success' => false,
'errors' => $validator->errors()->all()
], 200);
}
$authed = Auth::attempt([
'email' => $request->email,
'password' => $request->password
]);
if ($authed) {
$response = [
'success' => true,
'authenticated' => true,
'user' => User::where('email', $request->email)->first(),
];
} else {
$response = [
'success' => false,
'errors' => ['These credentials do not match our records'],
'test' => 'login-failed-bad-credentials'
];
}
return response($response, 200);
}
/**
* POST /register
*/
public function register(Request $request)
{
$validator = Validator::make($request->all(), [
'name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|min:8'
]);
if ($validator->fails()) {
return response([
'success' => false,
'errors' => $validator->errors()->all(),
'test' => 'registration-failed'
], 200);
}
$user = User::create([
'name' => $request->name,
'email' => $request->email,
'password' => \Hash::make($request->password)
]);
Auth::login($user);
$response = [
'success' => true,
'user' => $user,
];
return response($response, 200);
}
/**
* POST /logout
*/
public function logout(Request $request)
{
Session::flush();
return response([
'success' => true,
'authenticated' => false,
], 200);
}
/**
* GET /login-as/{user_id}
*/
public function loginAs(Request $request, $user_id)
{
if (!Str::contains(getRootDomain(), '.loc')) {
return response([
'success' => false,
'errors' => ['This functionality is only accessible when run from a .loc domain'],
], 200);
}
$user = User::find($user_id);
if (!$user) {
return response([
'success' => false,
'errors' => ['User ' . $user_id . ' not found'],
], 200);
} else {
Auth::login($user, $remember = true);
return response([
'success' => true,
'errors' => null,
'user' => $user,
], 200);
;
}
}
}
@susanBuck Thanks for the guidance. I have one more level of detail that I am trying to implement that makes my implementation more versatile but also makes the situation more complex. In the registration I want to collect "contact" information (ie First Name, Last Name, address, etc) but I don't want to store that in the users database but rather a contacts database. I know I can easily capture the data from the form field and connect the contact model to the controller and input the data calling out each field Contact::create([$request->FirstName, <etc>])
Then for login I would want to use the user's contact->primary_email()
and then authenticate through the users database with the password.
If I understand correctly this would all be managed with relationships within the models. Where I think I am struggling is in my understanding of Laravel when compared to CakePHP. In cake, once the relationship is established the data is immediately available as an object tagged to the referenced field (key) in the original object. I have been unable to get this to work as of yet in laravel. The screenshot below is a similar example I am working on now where an employee is referenced by a contact_id. I have setup the function in the model but as you can see in my props I cannot see the relational object.
Screenshot of props:
Model referencing the relationship between employees and contacts
public function contact()
{
return $this->hasOne(Contact::class, 'contact_id');
}
This would be the same for the users with the contacts but if I can't get this one working I feel ill-fated to get the authentication one working.
When you've established a relationship between two models, there's two ways data will be queried for the corresponding model:
If you access that data
For example, if you have a $user object and you attempt to access the contact data ($user->contact->first_name
), it will dynamically load the relationship for you so you have access to the data.
If you eager load the data
When querying for the user, you can include a with
method to eager load relationship data. For example:
$user = User::find(1)->with('contact');
In this scenario, if you were to just dump the user data (dump($user)
, you would see the contact info as well.
Whereas in scenario 1, if you dumped $user, you wouldn't see the contact info as it wasn't explicitly requested.
Does that help address your issue? Want to make sure I'm understanding correctly what you're looking to do. : )
This guidance worked great. I furthered the example by utilizing multiple relationships using an array within the with(). Worked great! Thanks for the help.
Hello Everyone,
I have implemented the authentication plugin (sanctum) into my project. I am having difficulty understanding how to customize the information the registration form gathers. Right now I know that the authentication middleware is controlled from
app/Http/Middleware
but that doesn't have much detail. There is another locationvendor/laravel/sanctum
which has much of what I think makes the authentication app work. What I am specifically looking for is to collect more info on the registration form like address, city, state, zip, etc. I believe if I change things under vendor those changes get wiped if I update or upgrade the application and also wouldn't carry over if this app was redeployed so I know that changing anything under vendor is not the correct action. I just don't understand how to customize the data collection yet. Can anyone help?