{"id":4480,"date":"2025-03-08T17:50:18","date_gmt":"2025-03-08T23:50:18","guid":{"rendered":"https:\/\/linuxitos.com\/main\/?p=4480"},"modified":"2025-03-08T17:50:19","modified_gmt":"2025-03-08T23:50:19","slug":"api-rest-laravel-12-sanctum-autenticacion-autorizacion-bearer","status":"publish","type":"post","link":"https:\/\/linuxitos.com\/main\/api-rest-laravel-12-sanctum-autenticacion-autorizacion-bearer\/","title":{"rendered":"API REST Laravel 12 Sanctum Autenticaci\u00f3n Autorizaci\u00f3n Bearer"},"content":{"rendered":"\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/api_rest_laravel_12_sanctum.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"512\" src=\"https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/api_rest_laravel_12_sanctum.png\" alt=\"\" class=\"wp-image-4481\" srcset=\"https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/api_rest_laravel_12_sanctum.png 1024w, https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/api_rest_laravel_12_sanctum-300x150.png 300w, https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/api_rest_laravel_12_sanctum-768x384.png 768w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<h1 class=\"wp-block-heading\">Contexto<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Laravel Sanctum es una API paquete de autenticaci\u00f3n para Laravel las aplicaciones, proporcionando un peso ligero, sencillo de usar un sistema de autenticaci\u00f3n para una sola p\u00e1gina de aplicaciones (SPAs), aplicaciones para m\u00f3viles, y otras API. Ofrece token de autenticaci\u00f3n basada en el uso de JSON Web de Tokens (JWT) o API tokens, la habilitaci\u00f3n de la autenticaci\u00f3n segura sin la sobrecarga de sesi\u00f3n tradicional basado en la autenticaci\u00f3n. Sanctum simplifica la configuraci\u00f3n de token de autenticaci\u00f3n, permitiendo a los desarrolladores centrarse en la construcci\u00f3n de sus aplicaciones en lugar de lidiar con la autenticaci\u00f3n de complejidades.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">En este ejemplo se usar\u00e1 Sanctum, para autenticaci\u00f3n y autorizaci\u00f3n con token bearer en las peticiones a endpoints.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Requerimientos<\/h1>\n\n\n\n<ul class=\"wp-block-list\">\n<li>PHP nativo 8.2 o superior o XAMPP con 8.2 o superior que contenga PHP 8.2 o superior<\/li>\n\n\n\n<li>MariaDB o MySQL<\/li>\n\n\n\n<li>Laravel 12<\/li>\n\n\n\n<li>Composer<\/li>\n\n\n\n<li>Terminal<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">El proyecto est\u00e1 disponible en \u00e9ste <a href=\"https:\/\/gitlab.com\/linuxitos\/api-rest-laravel-12-sanctum\" target=\"_blank\" rel=\"noreferrer noopener\">repositorio<\/a>, por si no requieren realizar el paso a paso. S\u00f3lo clonar, aplicar composer install y levantar el proyecto.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Creaci\u00f3n de proyecto<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Crear el proyecto con el siguiente comando:<\/p>\n\n\n\n<pre style=\"background: rgb(54, 63, 72); border-radius: 6px; border: 0px; box-sizing: border-box; color: white; font-family: menlo, monaco, monospace; font-style: inherit; font-weight: inherit; line-height: 15.68px; margin-bottom: 1.1em; max-width: 100%; outline: 0px; overflow: auto; padding: 13.125px 16.4062px; vertical-align: baseline; white-space: pre-wrap; word-wrap: break-word;\">composer create-project laravel\/laravel apidash<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">**El nombre del directorio del proyecto es apidash, lo pueden modificar en caso de ser necesario.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Instalar paquete API:<\/p>\n\n\n\n<pre style=\"background: rgb(54, 63, 72); border-radius: 6px; border: 0px; box-sizing: border-box; color: white; font-family: menlo, monaco, monospace; font-style: inherit; font-weight: inherit; line-height: 15.68px; margin-bottom: 1.1em; max-width: 100%; outline: 0px; overflow: auto; padding: 13.125px 16.4062px; vertical-align: baseline; white-space: pre-wrap; word-wrap: break-word;\">php artisan install:api<\/pre>\n\n\n\n<h1 class=\"wp-block-heading\">Creaci\u00f3n de la base datos<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">La base de datos se llamar\u00e1 <strong>ApiDashExample<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Crear la base de datos en el gestor de base de datos que se haya elegido, ya sea phpMyAdmin o MySQL o cualquier otro.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Modificar el archivo .env del directorio ra\u00edz del proyecto, y ajustar la conexi\u00f3n a la base de datos, como lo son la contrase\u00f1a, usuario IP, Puerto.<\/p>\n\n\n\n<pre style=\"background: rgb(245, 245, 245); border-radius: 6px; border: 1px solid rgb(204, 204, 204); box-sizing: border-box; color: #333; font-family: menlo, monaco, monospace; font-style: inherit; font-weight: inherit; line-height: 15.68px; margin-bottom: 1.1em; max-width: 100%; outline: 0px; overflow: auto; padding: 13.125px 16.4062px; vertical-align: baseline; white-space: pre-wrap; word-wrap: break-word;\">[...]\n\nDB_CONNECTION=mysql\nDB_HOST=127.0.0.1\nDB_PORT=3306\nDB_DATABASE=ApiDashExample\nDB_USERNAME=root\nDB_PASSWORD=\n\n[...]<\/pre>\n\n\n\n<h1 class=\"wp-block-heading\">Crear controladores<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\">BaseController<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">BaseController : llevar\u00e1 el control de las respuestas y ser\u00e1 el encargado de obtener las respuestas de los controladores como AuthController o PostController.<\/p>\n\n\n\n<pre style=\"background: rgb(54, 63, 72); border-radius: 6px; border: 0px; box-sizing: border-box; color: white; font-family: menlo, monaco, monospace; font-style: inherit; font-weight: inherit; line-height: 15.68px; margin-bottom: 1.1em; max-width: 100%; outline: 0px; overflow: auto; padding: 13.125px 16.4062px; vertical-align: baseline; white-space: pre-wrap; word-wrap: break-word;\">php artisan make:controller BaseController<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">El controlador debe tener \u00e9ste c\u00f3digo:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;?php\n\nnamespace App\\Http\\Controllers;\n\nuse Illuminate\\Http\\JsonResponse;\nuse App\\Http\\Controllers\\Controller;\n\nclass BaseController extends Controller\n{\n    \/**\n     * Enviar respuesta de \u00e9xito.\n     *\n     * @param mixed  $data      Datos de la respuesta\n     * @param string $message   Mensaje a mostrar\n     * @param int    $code      C\u00f3digo de respuesta HTTP (por defecto 200)\n     * @return JsonResponse\n     *\/\n    public function sendResponse($data, $message, $code = 200): JsonResponse\n    {\n        return response()->json(&#91;\n            'status'  => 'success',\n            'code'    => 200,\n            'message' => 'Conexi\u00f3n exitosa',\n            'resultado' => &#91;\n                'status'  => 'success',\n                'code'    => $code,\n                'message' => $message,\n                'data'    => $data,\n            ],\n        ], 200);\n    }\n\n    \/**\n     * Enviar respuesta de error.\n     *\n     * @param string $message        Mensaje de error\n     * @param array  $errorMessages  Errores adicionales (opcional)\n     * @param int    $code           C\u00f3digo de error (por defecto 400)\n     * @return JsonResponse\n     *\/\n    public function sendError($message, $errorMessages = &#91;], $code = 400): JsonResponse\n    {\n        return response()->json(&#91;\n            'status'  => 'success',\n            'code'    => 200,\n            'message' => 'Conexi\u00f3n exitosa',\n            'resultado' => &#91;\n                'status'  => 'danger',\n                'code'    => $code,\n                'message' => is_array($errorMessages) ? implode(' ', $errorMessages) : $message,\n            ],\n        ], 200);\n    }\n}<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">AuthController<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">AuthController: Contiene las declaraciones de Login, Signup, y logout<\/p>\n\n\n\n<pre style=\"background: rgb(54, 63, 72); border-radius: 6px; border: 0px; box-sizing: border-box; color: white; font-family: menlo, monaco, monospace; font-style: inherit; font-weight: inherit; line-height: 15.68px; margin-bottom: 1.1em; max-width: 100%; outline: 0px; overflow: auto; padding: 13.125px 16.4062px; vertical-align: baseline; white-space: pre-wrap; word-wrap: break-word;\">php artisan make:controller AuthController<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">C\u00f3digo dentro del controlador:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;?php\n\nnamespace App\\Http\\Controllers;\n\nuse Illuminate\\Http\\Request;\nuse App\\Http\\Controllers\\BaseController as BaseController;\nuse Validator;\nuse Illuminate\\Http\\JsonResponse;\nuse App\\Models\\User;\nuse Illuminate\\Support\\Facades\\Auth;\nuse Illuminate\\Support\\Facades\\Hash;\n\nclass AuthController extends BaseController\n{\n    public function signup(Request $request): JsonResponse\n    {\n        $validator = Validator::make($request->all(), &#91;\n            'name'      => 'required|string',\n            'email'     => 'required|string|email|unique:users,email',\n            'password'  => 'required|string|min:4|confirmed',\n        ]);\n        if ($validator->fails()) {\n            return $this->sendError('Error de validaci\u00f3n.', $validator->errors()->all(), 401);\n        }\n        $user = User::create(&#91;\n            'name'      => $request->name,\n            'email'     => $request->email,\n            'password'  => Hash::make($request->password),\n        ]);\n        $fullToken = $user->createToken('user-token')->plainTextToken;\n        $token = explode('|', $fullToken)&#91;1];\n        return $this->sendResponse(&#91;], 'Usuario registrado correctamente.');\n    }\n\n    public function login(Request $request): JsonResponse\n    {\n        if (!Auth::attempt(&#91;'email' => $request->email, 'password' => $request->password])) {\n            return $this->sendError('Credenciales incorrectas.', &#91;'El email o la contrase\u00f1a son incorrectos.'], 401);\n        }\n        $user = Auth::user();\n        if ($user->status !== 1) {\n            return $this->sendError('Acceso denegado.', &#91;'Su cuenta no est\u00e1 activa. Contacte al administrador.'], 403);\n        }\n        $fullToken = $user->createToken('MyApp')->plainTextToken;\n        $token = explode('|', $fullToken)&#91;1];\n        $expiresAt = now()->addHour();\n        $user->tokens()->latest()->first()->update(&#91;\n            'expires_at' => $expiresAt,\n        ]);\n        $data = &#91;\n            'token' => $token,\n            'expires_at' => $expiresAt->toDateTimeString(),\n            'name' => $user->name,\n            'email' => $user->email,\n            'avatar' => $user->avatar,\n        ];\n\n        return $this->sendResponse($data, 'Inicio de sesi\u00f3n exitoso.');\n    }\n\n    public function logout()\n    {\n        Auth::user()->tokens->each(function ($token) {\n            $token->forceDelete();\n        });\n        $response = &#91;\n            'status' => 'success',\n            'code' => 200,\n            'message' => 'Conexi\u00f3n exitosa',\n            'resultado' => &#91;\n                'status' => 'success',\n                'code' => 200,\n                'message' => 'Sesi\u00f3n finalizada.',\n            ]\n        ];\n        return response()->json( $response, 200);\n    }\n}<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">PostController<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">PostController : Tendr\u00e1 el c\u00f3digo para administrar las opciones de creaci\u00f3n de post de los usuarios<\/p>\n\n\n\n<pre style=\"background: rgb(54, 63, 72); border-radius: 6px; border: 0px; box-sizing: border-box; color: white; font-family: menlo, monaco, monospace; font-style: inherit; font-weight: inherit; line-height: 15.68px; margin-bottom: 1.1em; max-width: 100%; outline: 0px; overflow: auto; padding: 13.125px 16.4062px; vertical-align: baseline; white-space: pre-wrap; word-wrap: break-word;\">php artisan make:controller PostController<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">C\u00f3digo del controlador.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;?php\n\nnamespace App\\Http\\Controllers;\n\nuse Illuminate\\Http\\Request;\nuse App\\Models\\Post;\nuse Illuminate\\Support\\Str;\nuse Illuminate\\Support\\Facades\\Auth;\nuse Illuminate\\Http\\JsonResponse;\nuse Illuminate\\Support\\Facades\\Validator;\nuse Illuminate\\Validation\\ValidationException;\nuse Symfony\\Component\\HttpKernel\\Exception\\UnauthorizedHttpException;\n\nclass PostController extends BaseController\n{\n    public function get(Request $request): JsonResponse\n    {\n        try {\n            \/\/ Verificar si se busca un solo registro o una lista\n            if ($request->id > 0) {\n                $reg = Post::where('id', $request->id)\n                    ->where('user_id', Auth::id())\n                    ->first();\n\n                $regs = $reg ? &#91;$reg] : &#91;];\n                if ($reg) {\n                    $total = 1;\n                }else{\n                    $total = 0;\n                }\n            } else {\n                $query = Post::query();\n\n                if ($request->page > 0) {\n                    $request->search = trim($request->search);\n\n                    $query->where(function ($q) use ($request) {\n                        $q->where('title', 'LIKE', '%' . $request->search . '%')\n                            ->orWhere('content', 'LIKE', '%' . $request->search . '%')\n                            ->orWhere('slug', 'LIKE', '%' . $request->search . '%');\n                    });\n\n                    $query = $query->where('user_id', Auth::id());\n\n                    $total = $query->count();\n                    $offset = ($request->page - 1) * $request->per_page;\n                    $query = $query->offset($offset)->limit($request->per_page);\n                    $query = $query->orderBy($request->order_by, $request->order);\n                    $regs = $query->get();\n                } else {\n                    $total = $query->where('user_id', Auth::id())->count();\n                    $regs = $query->get();\n                }\n            }\n\n            return $this->sendResponse(&#91;\n                'total' => $total,\n                'regs' => $regs\n            ], 'Listado de registros.');\n\n        } catch (UnauthorizedHttpException $e) {\n            return $this->sendError('Error de autenticaci\u00f3n.', &#91;'El token ha expirado o es inv\u00e1lido. Por favor, inicia sesi\u00f3n nuevamente.'], 401);\n        } catch (\\Exception $e) {\n            return $this->sendError('Error en la operaci\u00f3n.', &#91;$e->getMessage()], 500);\n        }\n    }\n\n    public function delete(Request $request): JsonResponse\n    {\n        try {\n            $user = Auth::user();\n            $post = Post::where('id', $request->id)->where('user_id', $user->id)->first();\n            if (!$post) {\n                return $this->sendError('No encontrado.', &#91;'El post no existe o no pertenece al usuario.'], 404);\n            }\n            if ($post->delete()) {\n                return $this->sendResponse(&#91;], 'Registro eliminado correctamente.');\n            } else {\n                return $this->sendError('Error al eliminar el registro.', &#91;], 500);\n            }\n        } catch (UnauthorizedHttpException $e) {\n            return $this->sendError('Error de autenticaci\u00f3n.', &#91;'El token ha expirado o es inv\u00e1lido. Por favor, inicia sesi\u00f3n nuevamente.'], 401);\n        } catch (\\Exception $e) {\n            return $this->sendError('Error en la operaci\u00f3n.', &#91;$e->getMessage()], 500);\n        }\n    }\n\n    public function save(Request $request): JsonResponse\n    {\n        try {\n            $user = Auth::user();\n\n            \/\/ Reglas de validaci\u00f3n\n            $rules = &#91;\n                'title'   => 'required|string|max:300|unique:posts,title,' . $request->id,\n                'content' => 'nullable|string',\n            ];\n\n            $messages = &#91;\n                'title.required' => 'El t\u00edtulo es obligatorio.',\n                'title.string'   => 'El t\u00edtulo debe ser un texto v\u00e1lido.',\n                'title.max'      => 'El t\u00edtulo no puede exceder los 300 caracteres.',\n                'title.unique'   => 'El t\u00edtulo ya ha sido registrado, elige otro.',\n            ];\n\n            $validator = Validator::make($request->all(), $rules, $messages);\n            if ($validator->fails()) {\n                return $this->sendError('Error de validaci\u00f3n.', &#91;implode(' ', $validator->errors()->all())], 422);\n            }\n            $validated = $validator->validated();\n            $slug = Str::slug($validated&#91;'title'], '-');\n\n            if (Post::where('slug', $slug)->exists()) {\n                $slug .= '-' . Str::random(6);\n            }\n            if ($request->id > 0) {\n                $post = Post::where('id', $request->id)->where('user_id', $user->id)->first();\n                if (!$post) {\n                    return $this->sendError('No encontrado.', &#91;'El post no existe o no pertenece al usuario.'], 404);\n                }\n                $post->update(&#91;\n                    'title'   => $validated&#91;'title'],\n                    'content' => $validated&#91;'content'],\n                    'slug'    => $slug,\n                ]);\n                return $this->sendResponse(&#91;], 'La informaci\u00f3n del registro ha sido actualizada correctamente.');\n            } else {\n                $post = Post::create(&#91;\n                    'title'   => $validated&#91;'title'],\n                    'content' => $validated&#91;'content'],\n                    'slug'    => $slug,\n                    'user_id' => $user->id,\n                ]);\n                return $this->sendResponse(&#91;], 'Registro grabado correctamente.');\n            }\n\n        } catch (\\Exception $e) {\n            return $this->sendError('Error en la operaci\u00f3n.', &#91;$e->getMessage()], 500);\n        }\n    }\n}<\/code><\/pre>\n\n\n\n<h1 class=\"wp-block-heading\">Modelos<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Creaci\u00f3n de modelos y migraciones<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Modelo User<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">User \u00e9ste modelo ya existe previamente, modificarlo, y modificar la migraci\u00f3n<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;?php\n\nnamespace App\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Factories\\HasFactory;\nuse Illuminate\\Foundation\\Auth\\User as Authenticatable;\nuse Illuminate\\Notifications\\Notifiable;\nuse Laravel\\Sanctum\\HasApiTokens;\n\nclass User extends Authenticatable\n{\n    use HasFactory, Notifiable, HasApiTokens;\n\n    \/**\n     * The attributes that are mass assignable.\n     *\n     * @var array\n     *\/\n    protected $fillable = &#91;\n        'name',\n        'email',\n        'password',\n    ];\n\n    \/**\n     * The attributes that should be hidden for serialization.\n     *\n     * @var array\n     *\/\n    protected $hidden = &#91;\n        'password',\n        'remember_token',\n    ];\n\n    \/**\n     * Get the attributes that should be cast.\n     *\n     * @return array\n     *\/\n    protected function casts(): array\n    {\n        return &#91;\n            'email_verified_at' => 'datetime',\n            'password' => 'hashed',\n        ];\n    }\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Migraci\u00f3n de User:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration\n{\n    \/**\n     * Run the migrations.\n     *\/\n    public function up(): void\n    {\n        Schema::create('users', function (Blueprint $table) {\n            $table->id();\n            $table->integer('status')->default(1);\n            $table->string('name');\n            $table->string('email')->unique();\n            $table->string('password');\n            $table->string('avatar')->nullable();\n            $table->timestamp('email_verified_at')->nullable();\n            $table->rememberToken();\n            $table->timestamps();\n        });\n\n        Schema::create('password_reset_tokens', function (Blueprint $table) {\n            $table->string('email')->primary();\n            $table->string('token');\n            $table->timestamp('created_at')->nullable();\n        });\n\n        Schema::create('sessions', function (Blueprint $table) {\n            $table->string('id')->primary();\n            $table->foreignId('user_id')->nullable()->index();\n            $table->string('ip_address', 45)->nullable();\n            $table->text('user_agent')->nullable();\n            $table->longText('payload');\n            $table->integer('last_activity')->index();\n        });\n    }\n\n    \/**\n     * Reverse the migrations.\n     *\/\n    public function down(): void\n    {\n        Schema::dropIfExists('users');\n        Schema::dropIfExists('password_reset_tokens');\n        Schema::dropIfExists('sessions');\n    }\n};<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Modelo Post<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Modelo post: administra los post o publicaciones que el usuario crear\u00e1:<\/p>\n\n\n\n<pre style=\"background: rgb(54, 63, 72); border-radius: 6px; border: 0px; box-sizing: border-box; color: white; font-family: menlo, monaco, monospace; font-style: inherit; font-weight: inherit; line-height: 15.68px; margin-bottom: 1.1em; max-width: 100%; outline: 0px; overflow: auto; padding: 13.125px 16.4062px; vertical-align: baseline; white-space: pre-wrap; word-wrap: break-word;\">php artisan make:model Post -m<\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;?php\n\nnamespace App\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Model;\n\nclass Post extends Model\n{\n    protected $primaryKey = 'id';\n\n    public $timestamps = false;\n\n    protected $fillable = &#91;'title', 'content', 'slug', 'image', 'status', 'fc', 'user_id'];\n\n\n    public function author()\n    {\n        return $this->belongsTo(User::class, 'user_id', 'id');\n    }\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Migraci\u00f3n del modelo Post:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration\n{\n    \/**\n     * Run the migrations.\n     *\/\n    public function up(): void\n    {\n        Schema::create('posts', function (Blueprint $table) {\n            $table->id();\n            $table->tinyInteger('status')->default(1)->comment('0 delete, 1 private, 2 public');\n            $table->string('title', 300)->nullable();\n            $table->text('content')->nullable();\n            $table->string('slug', 300)->nullable();\n            $table->string('image', 300)->nullable();\n            $table->timestamp('fc')->useCurrent();\n            $table->foreignId('user_id');\n            $table->foreign('user_id')->references('id')->on('users');\n        });\n    }\n\n    \/**\n     * Reverse the migrations.\n     *\/\n    public function down(): void\n    {\n        Schema::dropIfExists('posts');\n    }\n};<\/code><\/pre>\n\n\n\n<h1 class=\"wp-block-heading\">Migraci\u00f3n de la Base de Datos<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Migrar la base de datos:<\/p>\n\n\n\n<pre style=\"background: rgb(54, 63, 72); border-radius: 6px; border: 0px; box-sizing: border-box; color: white; font-family: menlo, monaco, monospace; font-style: inherit; font-weight: inherit; line-height: 15.68px; margin-bottom: 1.1em; max-width: 100%; outline: 0px; overflow: auto; padding: 13.125px 16.4062px; vertical-align: baseline; white-space: pre-wrap; word-wrap: break-word;\">php artisan migrate:fresh --seed<\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/image.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"324\" src=\"https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/image-1024x324.png\" alt=\"\" class=\"wp-image-4488\" srcset=\"https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/image-1024x324.png 1024w, https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/image-300x95.png 300w, https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/image-768x243.png 768w, https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/image.png 1258w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<h1 class=\"wp-block-heading\">Levantar el servidor<\/h1>\n\n\n\n<pre style=\"background: rgb(54, 63, 72); border-radius: 6px; border: 0px; box-sizing: border-box; color: white; font-family: menlo, monaco, monospace; font-style: inherit; font-weight: inherit; line-height: 15.68px; margin-bottom: 1.1em; max-width: 100%; outline: 0px; overflow: auto; padding: 13.125px 16.4062px; vertical-align: baseline; white-space: pre-wrap; word-wrap: break-word;\">php artisan serve<\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/image-1.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"109\" src=\"https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/image-1-1024x109.png\" alt=\"\" class=\"wp-image-4490\" srcset=\"https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/image-1-1024x109.png 1024w, https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/image-1-300x32.png 300w, https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/image-1-768x81.png 768w, https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/image-1.png 1178w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Desde el navegador se puede acceder y s\u00f3lo se visualizar\u00e1 lo siguiente:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/image-2.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"288\" src=\"https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/image-2-1024x288.png\" alt=\"\" class=\"wp-image-4491\" srcset=\"https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/image-2-1024x288.png 1024w, https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/image-2-300x84.png 300w, https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/image-2-768x216.png 768w, https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/image-2-1536x432.png 1536w, https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/image-2.png 1657w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Y con eso se sabe que todo bien, ahora desde un cliente de API como postman lanzar las peticiones.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Pruebas<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\">Registro:<\/h2>\n\n\n\n<pre style=\"background: rgb(245, 245, 245); border-radius: 6px; border: 1px solid rgb(204, 204, 204); box-sizing: border-box; color: #333; font-family: menlo, monaco, monospace; font-style: inherit; font-weight: inherit; line-height: 15.68px; margin-bottom: 1.1em; max-width: 100%; outline: 0px; overflow: auto; padding: 13.125px 16.4062px; vertical-align: baseline; white-space: pre-wrap; word-wrap: break-word;\">\nURL http:\/\/127.0.0.1:8000\/api\/v1\/auth\/signup\nM\u00e9todo: POST\nBody:\n\n{\n\t\"name\":\"andy\",\n\t\"email\":\"andy@dev.com\",\n\t\"password_confirmation\":\"holamundo\",\n\t\"password\":\"holamundo\"\n}\n<\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/image-3.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"260\" src=\"https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/image-3-1024x260.png\" alt=\"\" class=\"wp-image-4494\" srcset=\"https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/image-3-1024x260.png 1024w, https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/image-3-300x76.png 300w, https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/image-3-768x195.png 768w, https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/image-3.png 1482w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Login:<\/h2>\n\n\n\n<pre style=\"background: rgb(245, 245, 245); border-radius: 6px; border: 1px solid rgb(204, 204, 204); box-sizing: border-box; color: #333; font-family: menlo, monaco, monospace; font-style: inherit; font-weight: inherit; line-height: 15.68px; margin-bottom: 1.1em; max-width: 100%; outline: 0px; overflow: auto; padding: 13.125px 16.4062px; vertical-align: baseline; white-space: pre-wrap; word-wrap: break-word;\">\nURL http:\/\/127.0.0.1:8000\/api\/v1\/auth\/login\nM\u00e9todo: POST\nBody:\n\n{\n\t\"email\":\"andy@dev.com\",\n\t\"password\":\"holamundo\"\n}<\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/image-4.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"309\" src=\"https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/image-4-1024x309.png\" alt=\"\" class=\"wp-image-4495\" srcset=\"https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/image-4-1024x309.png 1024w, https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/image-4-300x90.png 300w, https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/image-4-768x232.png 768w, https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/image-4.png 1482w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Registro Post:<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Del token que se recibi\u00f3 en login, se usar\u00e1 para poder enviar una petici\u00f3n en el save de post:<\/p>\n\n\n\n<pre style=\"background: rgb(245, 245, 245); border-radius: 6px; border: 1px solid rgb(204, 204, 204); box-sizing: border-box; color: #333; font-family: menlo, monaco, monospace; font-style: inherit; font-weight: inherit; line-height: 15.68px; margin-bottom: 1.1em; max-width: 100%; outline: 0px; overflow: auto; padding: 13.125px 16.4062px; vertical-align: baseline; white-space: pre-wrap; word-wrap: break-word;\">\nURL http:\/\/127.0.0.1:8000\/api\/v1\/post\/save\nM\u00e9todo: POST\nBody:\n\n{\n\t\"id\":0,\n\t\"title\": \"Fedora dual boot con Windows 12\",\n\t\"content\": \"Contenido del POST\"\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Se agrega en la pesta\u00f1a Auth &#8211; Bearer Token<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/image-5.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"309\" src=\"https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/image-5-1024x309.png\" alt=\"\" class=\"wp-image-4497\" srcset=\"https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/image-5-1024x309.png 1024w, https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/image-5-300x90.png 300w, https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/image-5-768x232.png 768w, https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/image-5.png 1482w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/image-7.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"309\" src=\"https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/image-7-1024x309.png\" alt=\"\" class=\"wp-image-4499\" srcset=\"https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/image-7-1024x309.png 1024w, https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/image-7-300x90.png 300w, https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/image-7-768x232.png 768w, https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/image-7.png 1482w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Listar Posts<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Listar todos los post del usuario logeado:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Explicaci\u00f3n del body:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>id: si se env\u00eda 0, se listar\u00e1n todas los registros que coincidan con la b\u00fasqueda, con el filtros, el ordenado, y la paginaci\u00f3n, si es mayor a cero, se obtendr\u00e1 un s\u00f3lo registro con dicho ID, siempre y cuando exista.<\/li>\n\n\n\n<li>page: Es el n\u00famero de la paginaci\u00f3n y s\u00f3lo se respeta si el di es 0<\/li>\n\n\n\n<li>search: lleva la b\u00fasqueda o filtro que se realiza del title y content<\/li>\n\n\n\n<li>order_by: se ordena de acuerdo al campo que lleve, puede ser cualquiera, y se usa en ordenamiento en tablas<\/li>\n\n\n\n<li>order: puede ser asc o desc<\/li>\n\n\n\n<li>per_page: es el total de registro a mostrar en una p\u00e1gina <\/li>\n<\/ul>\n\n\n\n<pre style=\"background: rgb(245, 245, 245); border-radius: 6px; border: 1px solid rgb(204, 204, 204); box-sizing: border-box; color: #333; font-family: menlo, monaco, monospace; font-style: inherit; font-weight: inherit; line-height: 15.68px; margin-bottom: 1.1em; max-width: 100%; outline: 0px; overflow: auto; padding: 13.125px 16.4062px; vertical-align: baseline; white-space: pre-wrap; word-wrap: break-word;\">\nURL http:\/\/127.0.0.1:8000\/api\/v1\/post\/get\nM\u00e9todo: POST\nBody:\n\n{\n    \"id\": 0,\n    \"page\" : 1,\n    \"search\": \"\",\n    \"order_by\": \"id\",\n    \"order\": \"desc\",\n    \"per_page\": 10\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">A\u00f1adir en la pesta\u00f1a Auth el Bearer Token:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/image-8.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"558\" src=\"https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/image-8-1024x558.png\" alt=\"\" class=\"wp-image-4501\" srcset=\"https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/image-8-1024x558.png 1024w, https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/image-8-300x163.png 300w, https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/image-8-768x418.png 768w, https:\/\/linuxitos.com\/main\/wp-content\/uploads\/2025\/03\/image-8.png 1472w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Eliminar Post<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Para eliminar un post, s\u00f3lo se env\u00eda un ID del registro a eliminar.<\/p>\n\n\n\n<pre style=\"background: rgb(245, 245, 245); border-radius: 6px; border: 1px solid rgb(204, 204, 204); box-sizing: border-box; color: #333; font-family: menlo, monaco, monospace; font-style: inherit; font-weight: inherit; line-height: 15.68px; margin-bottom: 1.1em; max-width: 100%; outline: 0px; overflow: auto; padding: 13.125px 16.4062px; vertical-align: baseline; white-space: pre-wrap; word-wrap: break-word;\">\nURL http:\/\/127.0.0.1:8000\/api\/v1\/post\/delete\nM\u00e9todo: POST\nBody:\n\n{\n    \"id\": 0,\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Y eso ser\u00eda todo, cualquier comentario o mejora, no duden en dejarlos en la caja de comentarios.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Contexto Laravel Sanctum es una API paquete de autenticaci\u00f3n para Laravel las aplicaciones, proporcionando un peso ligero, sencillo de usar un sistema de autenticaci\u00f3n para una sola p\u00e1gina de aplicaciones (SPAs), aplicaciones para m\u00f3viles, y otras API. Ofrece token de autenticaci\u00f3n basada en el uso de JSON Web de Tokens (JWT) o API tokens, la [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":4481,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1101,167,400,1543,998,101,1541],"tags":[2023,2026,1720,1638,1932,2025,2027,1587],"class_list":["post-4480","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-actualizar-fedora","category-actualizar-phpmyadmin-de-xampp","category-archlinux","category-developer","category-lampp","category-va-api","category-web-developer","tag-api","tag-bearer","tag-lampp","tag-laravel","tag-rest","tag-sacntum","tag-token","tag-xampp"],"_links":{"self":[{"href":"https:\/\/linuxitos.com\/main\/wp-json\/wp\/v2\/posts\/4480","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/linuxitos.com\/main\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/linuxitos.com\/main\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/linuxitos.com\/main\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/linuxitos.com\/main\/wp-json\/wp\/v2\/comments?post=4480"}],"version-history":[{"count":16,"href":"https:\/\/linuxitos.com\/main\/wp-json\/wp\/v2\/posts\/4480\/revisions"}],"predecessor-version":[{"id":4506,"href":"https:\/\/linuxitos.com\/main\/wp-json\/wp\/v2\/posts\/4480\/revisions\/4506"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/linuxitos.com\/main\/wp-json\/wp\/v2\/media\/4481"}],"wp:attachment":[{"href":"https:\/\/linuxitos.com\/main\/wp-json\/wp\/v2\/media?parent=4480"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/linuxitos.com\/main\/wp-json\/wp\/v2\/categories?post=4480"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/linuxitos.com\/main\/wp-json\/wp\/v2\/tags?post=4480"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}