Creo que faltó un pedazo al inicio del video, para instalar Sanctum debe hacerse con el siguiente código desde la terminal:
composer require laravel/sanctum
Laravel y Base de Datos
Entorno de trabajo y repaso de Laravel
Qué aprenderás sobre Laravel Avanzado
Repaso de Laravel y requisitos del curso
Configuración de la base de datos-SQLite en Laravel
Instalación, configuración y uso de Homestead
Instalar Laravel Sanctum
API de autenticación: laravel UI y laravel sanctum
Manejo de tu base de datos con Laravel
Capa de transformación con API Resources
Manejo de relaciones en bases de datos con Laravel
Relaciones Polimórficas en Eloquent
La terminal de Laravel
Cómo crear comandos para la terminal de Laravel
Ejecutando comandos desde la API
Programación de tareas
Eventos y tareas de Laravel
Eventos y Listeners en Laravel
Eventos de Eloquent
Introducción al uso de Queues y Jobs
Cómo disparar eventos en Queues
Laravel Horizon
Manejo de errores
Cómo capturar y leer errores con la clase Handler
Excepciones personalizadas
Excepciones HTTP personalizadas y debugging con Laravel Telescope
Configuración de logs y channels en Laravel
El corazón de Laravel
Ciclo de vida de una aplicación en Laravel
¿Qué son los service containers?
¿Cómo funciona un service container?
Registro y carga de clases con service providers
Creación de paquetes
¿Cómo crear mis propios paquetes de Laravel?
Propiedades para manejo de dependencias
Comprende el archivo composer.json
Extendiendo composer.json, autocarga de clases y PSR-4
Crear mis propios Services Providers
Publicación de archivos
Uso de repositorios locales
Publicación de paquetes en packagist
No tienes acceso a esta clase
¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera
Sergio Ojeda
Aportes 56
Preguntas 7
Creo que faltó un pedazo al inicio del video, para instalar Sanctum debe hacerse con el siguiente código desde la terminal:
composer require laravel/sanctum
demasiados DEMASIADOSSS criterios sin explicar en este curso, perdido totalmente apesar de haber visto los anteriores de php y laravel, lo extraño es que cuando habla se le entiende lo que dice, se nota que tampoco es arrogante y su lenguaje y manera de explicar es muy amigable, que paso aqui platzi???
Se extraña al profesor Italo uu
Si están utilizando PostMan deben de modificar el Header Accept para que solo de respuesta Postman acepte del tipo application/json.
Quedaría algo como:
Accept: application/json
La validación dentro de UserTokenController, debería quedar así, ésto para que en caso de que el usuario no exista o la contraseña no es correcta, nos lance el mensaje de error.
if (!$user || !Hash::check($request->password, $user->password)) {
throw ValidationException::withMessages([
'email' => ['El email no existe o no coincide con nuestros datos.'],
]);
}
Para crear el usuario pueden utilizar tinker
php artisan tinker
App\User::create(['name'=>'nombre','email'=>'[email protected]','password'=>Illuminate\Support\Facades\Hash::make('contraseña')];
el video esta cortado no esta la parte de laravel ui
Hay muchos errores empezando por la logica mal implementada en el Throw
Esto esta mal porque literlamente dice: Si el usuario no existe y si el password no coincide
if (!$user && !Hash::check($request->password, $user->password) {
Lo correcto seria:
if (!$user || !Hash::check($request->password, $user->password) {
Publico algunos cambios en mi UserTokenController que a mi me ha funcionado mejor:
<?php
namespace App\Http\Controllers;
use App\User;
use Illuminate\Support\Facades\Hash;
use App\Http\Requests\UserTokenRequest;
use Illuminate\Validation\ValidationException;
class UserTokenController extends Controller
{
public function __invoke(UserTokenRequest $request)
{
$user = User::where('email', $request->email)->first();
if ( !$user->exists() || !Hash::check($request->password, $user->password) ) {
throw ValidationException::withMessages([
'email' => 'El usuario no se encuentra o es incorrecto'
]);
}
return response()->json([
'token' => $user->createToken($request->device_name)->plainTextToken
]);
}
}
Vale, el video está cortado y no se explicó lo de Laravel UI (Pero se explica en otros cursos) Laravel UI nos provee la autenticación en el caso que estemos trabajando sobre una aplicación que va a renderizar Laravel, no sobre una API, esto porque la API no contiene nada de lógica de frontend, todo es backend ^^
Les dejo la url del commit de esta clase:
https://github.com/RetaxMaster/platzi-api/commit/c2e0f1c7ff09b533b99892fae2eb453ff47ae83a
Creo que deberían de mejorar este curso, hay muchas cosas que se dejan al aire, existen cortes en el video, no se que paso con este curso si todos los anteriores a este con el profesor Italo Morales eran muy buenos…
Un pregunta profe
al usar throw ValidationException::withMessages([]
si falla a mi me manda a http://127.0.0.1:8000 no me salen los mensaje de la excepciones
que tengo que hacer me puede ayudar por favor
En el caso del if donde verifica si User existe o el hash coincide tuve que separarlo porque daba un error de que el user->password no encontraba la propiedad password, quedó de la siguiente manera:
if (!$user) {
throw ValidationException::withMessages([
'email' => 'El email no existe o no coincide con los datos',
]);
}
if (!Hash::check($request->password, $user->password)) {
throw ValidationException::withMessages([
'email' => 'El email no existe o no coincide con los datos',
]);
}
Para quienes ha tenido problemas no se olviden de poner en los archivos del test
<code>
use App\User;
use Laravel\Sanctum\Sanctum;
Siento que esta todo mal explicado, muchas cosas
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
Actualmente estoy intentando realizar este curso pero pareciera que hubieran cortado clases por que aparece el controlador de categoría así como por arte de magia
Este curso necesita una nueva edición, está como mal editado.
Les dejo una manera optima de hacer un login o creación de token en laravel +8
public function __invoke(Request $request)
{
$request->validate([
'email' => 'required|email',
'password' => 'required',
'device_name' => 'required'
]);
throw_if(!Auth::guard('web')->attempt($request->only('email','password')), ValidationException::withMessages([
'email' => 'Credenciales incorrectas'
]));
return response([
'token'=> Auth::guard('web')->user()->createToken($request->device_name)->plainTextToken
])->setStatusCode(Response::HTTP_OK);
}
Y para crear el usuario rápido, usen esta forma en el archivo DatabaseSeeder.php
User::create([
'name' => 'Admin',
'email' => '[email protected]',
'password' => '$2a$10$7oMxkBuQ0PpbVxpJl0ufNerj0TTuZmRxrD76LlyKCaMCh8bpZqVS2', //admin
]);
Asi debe ir el condicional en el UserTokenController:
if (!$user || !Hash::check($request->password, $user->password)) {
throw ValidationException::withMessages([
'email' => ['Las credenciales son incorrectas.'],
]);
}
return response()->json([
'token' => $user->createToken($request->device_name)->plainTextToken
]);
Creo que tambien deberia de mstrar todo el codigo en pantalla porque hay muchos namespace que no se ve donde los grega…
En mi opinión, este profesor deja muchas cosas en el aire y sin explicar, espero cambien de profesor para futuros cursos de laravel porque con Sergio Ojeda no me entero…
En la parte del test min 3:20 es necesario agregar la clase Sanctum al principio. El IDE del profesor la agrega automáticamente.
Por otra parte, Sanctum tiene dos formas de autenticar:
<?php
namespace App\Http\Controllers;
use App\Models\User;
use App\Http\Requests\UserTokenRequest;
use Illuminate\Validation\ValidationException;
use Illuminate\Support\Facades\Hash;
class UserTokenController extends Controller
{
public function __invoke(UserTokenRequest $request)
{
/** @var User $user */
$user = User::where('email', $request->input('email'))->first();
if (!$user) {
throw ValidationException::withMessages([
'email' => 'El email no existe',
]);
}
if (!Hash::check($request->password, $user->password)) {
throw ValidationException::withMessages([
'password' => 'Contraseña incorrecta',
]);
}
$token = $user->createToken($request->device_name)->plainTextToken;
return response()->json([
'token' => $token,
]);
}
}
Buscaré otro curso de laravel, no entendí nada de homestead, los archivos creo que los instalé donde no era. Estoy usando windows y nada, “no specific file found” no me funciona nada. Con ésta clase terminé de perderme.
Laravel 10 ya viene configurado con sanctum
A lo que va del curso pienso que se deberia actualizar a laravel 9 , lo que hace que el profe se quede corto en su explicacion y no es culpa de el, sino de que ya se han actualizado procesos
En versiones más recientes podrían realizarlo de esta forma
public function test_index()
{
$user = User::factory()->create();
Product::factory(5)->create();
$this
->actingAs($user)
->get('/api/products')
->assertSuccessful()
->assertHeader('content-type', 'application/json')
->assertJsonCount(5);
}
les dejare unos datos para se les faciliten las cosas en laravel 9, si ven el se loguea con usuarios y no emos visto nada de ellos, entonces debemos agregar el seeder, les dejo el
DatabaseSeeder.php
public function run()
{
$seeds = array_merge(
[
ProductSeeder::class,
UserSeeder::class,
]
);
$this->call($seeds);
}
luego creamos el UserSeeder con este comando
php artisan make:seed UserSeeder
y a UserSeeder.php le agregamos esto:
public function run()
{
User::factory(10)->create();
}
para finalizar, el factory se user ya existe, solo demos cambiar el string que aparece en el campo de contraseña, con una contraseña encryptada, entonces el UserFactory.php se ve asi
public function definition()
{
return [
'name' => fake()->name(),
'email' => fake()->unique()->safeEmail(),
'email_verified_at' => now(),
'password' => bcrypt('password'),
'remember_token' => Str::random(10),
];
}
public function unverified()
{
return $this->state(fn (array $attributes) => [
'email_verified_at' => null,
]);
}
la contraseña de todos los usuarios que creemos sera la palabra “password”,
ahora debemos correr los seeder conm este comando
php artisan db:seed
y si quieren hacer mejor un refresh y los seed seria asi
php artisan migrate:refresh --seed
ahora ya podemos copiar cualquier coreo de los usuarios de la base de datos y colocar como contrasena a todos “password” y podran probar desde postman con ellos.
parta terminar, tambien les dejo el archivo de UserTokenController.php
public function __invoke(Request $request)
{
$request->validate([
'email' => 'required|email',
'password' => 'required',
'device_name' => 'required',
]);
$user = User::whereEmail($request->email)->first();
if (!$user || !Hash::check($request->password, $user->password)) {
throw ValidationException::withMessages([
'email' => ['estas credenciales no existen o no coinciden con nuestros datos.'],
]);
}
$token = $user->createToken($request->token_name);
return response()->json([
'token' => $token->plainTextToken
]);
}
cabe mencionar que podriamos haber creado un login request y validan la informacion ahi y no en el metodo invoke de la clase UserTokenController
Si querés definir un controlador que sólo maneje una acción simple, podés agregar el método simple __invoke
al controlador:
<?php
namespace App\Http\Controllers;
use App\User;
use App\Http\Controllers\Controller;
class ShowProfile extends Controller
{
public function __invoke($id)
{
return view('user.profile', ['user' => User::findOrFail($id)]);
}
}
Cuando registres rutas con controladores de acciones simples, no necesitas especificar un método:
Route::get('user/{id}', 'ShowProfile');
Podés generar un controlador invokable usando la opción --invokable
del comando Artisan make:controller
:
php artisan make:controller ShowProfile --invokable
Una forma fácil para assert que los Header del response sean de tipo '‘content-type’, ‘application/json’ es hacerlo desde el controlador enviado la respuesta de esta manera:
public function store(Request $request)
{
return response()->json(Product::create($request->all()));
}
La otra forma mas elaborada es crear un Resource
"ProductResource"
el profe explica muy bien, pero creo que a ustedes les faltara importar: use Illuminate\Validation\ValidationException; y esta parte es con || en lugar de &&
if(!$user || !Hash::check($request->password, $user->password) ){
throw ValidationException::withMessages([
‘email’ => ‘email or password doesn’t match with our records’
]);
}
Tambien creen un UserSeeder que llame el userFactory, para que puedan crear con postman
El capítulo API de autenticación no dice nada sobre Laravel UI, salta directamente a Sanctum para APIs.
De hecho, creo que también se están mezclando conceptos. En las APIs no hay uso de cookies, solo de tokens (ejemplo JWT, OAuth…). Las cookies y sesiones se usan en la parte web (rutas en web.php) con un navegador asociado a las peticiones.
¿Qué opináis?.
En el curso de OAuth2 podéis ver más al respecto.
Saludos!.
php artisan make:controller UserTokenController --invokable
Con este comando se puede crear el controller con el metodo __invoke directamente
En laravel 8, Sanctum ya viene instalado por defecto
Considerando que en el curso de omiten varias explicaciones una de ellas es la creación de los usuarios …
Pueden crear el seeder de usuario ejecutando el comando
php artisan make:seeder UserSeeder
y agregar la siguiente línea en el seeder creado
factory(\App\User::class, 20)->create();
y si necesitan ejecutar solo ese seeder lo hacen con
php artisan db:seed --class=UserSeeder
Saludos! no pierdan el animo!
Para probar el funcionamiento del endpoint es necesario tener un usuario registrado, lo puedes ingresar en el registro desde el formulario web (si instalaste laravel ui) o con PHP Tinker.
Dejo el comando por si acaso tienen alguna falla.
php artisan vendor:publish --provider=“Laravel\Sanctum\SanctumServiceProvider”
Si no te reconoce la clase Sanctum en el controlador, agega esta linea arriba.
use Laravel\Sanctum\Sanctum;
Excelente gracias.
Para las personas que quieren ver el tema de Laravel UI, les dejo este tutorial en español sobre Laravel UI
EnsureFrontendRequestsAreStateful::class
es necesario que la ruta "/sanctum/token valla a esa url?
hice un controllador para crear un usuario sepa si esta bien, jajaj si les sirve ahí esta, solamente asignale una ruta
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\User;
use Illuminate\Support\Facades\Hash;
class AuthController extends Controller
{
public function register(Request $request)
{
$validator = $request->validate([
'email' => 'required|email',
'name' => 'required',
'password' => 'required',
]);
$newUser = User::create(['name' => $request->name,'email'=>$request->email,'password'=>Hash::make($request->password)]);
return response()->json($newUser);
}
}
Laravel Sanctum provides a featherweight authentication system for SPAs (single page applications), mobile applications, and simple, token based APIs. Sanctum allows each user of your application to generate multiple API tokens for their account. These tokens may be granted abilities / scopes which specify which actions the tokens are allowed to perform.
Fuente: https://laravel.com/docs/8.x/sanctum
https://laravel.com/docs/7.x/sanctum
Mas informacion acerca de Sanctum
La validación de que exista el usuario y de que la contraseña sea correcta usa los operadores && en lugar de || ya que, como está en el video, la contraseña aun si es incorrecta pero el usuario si existe se generará el token.
if(!$user || !Hash::check($request->password, $user->password){
// Código
}
No seria mejor hacerlo con passport?
Al comienzo del video antes de publicar los archivos puedes instalar ambos paquetes con un solo comando:
composer require laravel/sanctum laravel/ui
Lo que yo hice fue validar que ambos fueran verdaderos, ya que debemos asegurar que el usuario exista y que las contraseñas coincidan, puse el throw en el else.
if( $user && Hash::check($request->password, $user->password) ){
return response()->json([
'token' => $user->createToken($request->device_name)->plainTextToken
]);
} else {
throw ValidationException::withMessages([
'email' => 'El email no existe o no coincide'
]);
}
No se si sea la mejor manera de hacerlo.
Mi solución:
if( isset($user) ){
if( !Hash::check( $request->password, $user->password ) ){
throw ValidationException::withMessages([
'password' => 'Acceso incorrecto.'
]);
}
}else{
throw ValidationException::withMessages([
'email' => 'El email no existe o es invalido'
]);
}
return response()->json([
'token' => $user->createToken( $request->device_name )->plainTextToken
]);
Para el metodo de autenticacion usen esto
use Illuminate\Support\Facades\Auth;
$this->validateLogin($request);
if (Auth::attempt($request->only('email', 'password'))) {
return response()->json([
'token' => $request->user()->createToken($request->name)->plainTextToken,
'message' => 'Success'
]);
}
return response()->json([
'message' => 'Unauthorized'
], 401);
}
public function validatelogin(Request $request)
{
return $request->validate([
'email' => 'required|email',
'password' => 'required',
'name' => 'required'
]);
}```
En mi caso tuve que refactorizar el codigo para proteger la ruta, con laravel 8 la declaracion de la ruta
Route::apiResource('professions', 'ProductController')->middleware('auth:sanctum');
me daba un error tuve que escribirlo asi:
Route::apiResource('professions', ProductController::class)->middleware('auth:sanctum');
Buen video
Con Laravel 8 cuando uso la api con una contraseña errada la respuesta es una redirección 302. ¿Alguna sugerencia?
¿Quieres ver más aportes, preguntas y respuestas de la comunidad?