Laravel 5.4: Securizando la API

Bueno, de las entradas anteriores ya tenemos listo el CRUD de usuarios y las rutas para las llamadas.

Ahora voy a seguir las indicaciones de https://styde.net/api-rest-con-laravel-5-1-proteccion-con-access-key/ para poder securizar la API.

Una vez seguidos los pasos de este tutorial para generar la access key de toda la aplicación y securizarla de manera que nadie que no tenga esa clave la pueda utilizar, es el momento de generar la llamada de login para que un usuario pueda loguearse en la aplicacion con una llamada y recibir un access token que le sirva para poder utilizarla.

Cuándo se creó la tabla de usuarios, se añadió un campo de “api_token” que se autogeneraba cuando se guardaba el usuario por primera vez, así que ahora es el momento de generar la llamada de login. Si recordais del paso anterior, en el archivo “routes/web.php” ya incluimos la ruta de login, para estas llamadas.

También os puede pasar que, despues de seguir los pasos del tutorial de styde.net, os esteis encontrando que las llamadas os devuelven un 401 not authorized si intentais las llamadas sin incluir el access token que ahí está generado.

Pero vamos por pasos. Lo primero es generar el controlador y el modelo que usaremos para el login

E incluir la función login() en la clase del controlador, y el modelo, por lo que quedaría así:

Si estamos siguiendo los pasos, ahora mismo al probar la url de login nos pueden pasar dos cosas: o bien nos de el ok sin contenido, o bien nos de un 401 not authorized. Esto ultimo se debe a la comprobación que hace la clase “VerifyAccessKey” que generamos para securizar la API. Lo que tenemos que conseguir es que no haga esta comprobación si las rutas de uso son “/” o “/v1/login”.

Para ello, tendremos que modificar lo siguiente (o al menos lo que a mi me ha funcionado):

En App\Http\Kernel.php, ha quedado así:

En App\routes\web.php, modifcar el grupo para el prefijo “v1”, ha quedado así:

En App\Http\Middleware\VerisyCsrfToken.php, añadir al array $except la ruta de login:

Ya tenemos la api segura para las llamadas que no sean la raíz y el login. Ahora es el momento de que ese login haga algo. Únicamente va a tener una funcion login para hacer la petición, y devolverá 3 datos para que sean guardados en la sesión del usuario.

LoginController.php

Models/Login.php

Con esto ya tenemos hecho el login y el usuario recibe un token para poder interactuar después con el resto de la API.

En este punto, hemos de cambiar el verificador de token. Al final queda de esta forma:

Y tras esto habra que modificar y probar adecuadamente el controlador de usuarios para ver que todas las llamadas se producen correctamente y ver que si no está el token no funciona y no autoriza a efectuar la operación.

Por hoy es suficiente…

Laravel 5.4. API. Rutas de la aplicación

Continuemos.

Ahora es el momento de preparar las rutas de la aplicación que van a hacer que la magia funcione.

Para ello, en Laravel disponemos de los archivos situados en la carpeta “routes”, que de momento los que nos interesan son los archivos “api.php” y “web.php”. La diferencia entre cada uno de ellos es que la ruta de acceso será diferente, para la api todas las rutas incluirán al inicio la ruta “/api/” y los de web no la incluirán.

Dicho esto, y para separar mejor las rutas de la api y las diferentes modifcaciones, voy a tomar la costumbre de nombrar las llamadas con la versión de la API que utilice, “v1”, “v2”, etc… así será más sencillo luego a la hora de documentarlo.

Bien, para incluir todas las rutas del manejo de usuarios creadas en el anterior post, hemos de incluir en el archivo “web.php” lo siguiente:

Y modificando o añadiendo las rutas que queramos podremos ir montando nuestra api con los modulos necesarios.

Laravel 5.4: Comenzando API. CRUD Usuarios

Continuamos con este “cursillo – aprendizaje” sobre crear una aplicación con Laravel y Angular.

Lo primero con lo que vamos a comenzar es con las operaciones CRUD básicas para los usuarios de la aplicación.

Lo primero será crear el controlador que usaremos para estas funciones, para lo que será necesario ejecutar el siguiente comando:

Con el modificador  –resource conseguiremos que nos cree el controlador con un esqueleto basico de todas las funciones básicas para el manejo de los usuarios (aparte de las CRUD, las necesarias para manejar las vistas y formularios relacionados con la creación, update, etc).

Una vez conseguido esto, editaremos el archivo routes\web.php y añadiremos lo siguiente:

(si, de momento lo vamos a meter en la ruta web, para irlo probando, más adelante lo ingresaremos en una api con autenticación).

Con este código conseguimos que se reconozcan las rutas necesarias para las operaciones. Como en este caso estamos creando una api que no tendrá “vistas” (formularios o webs que ver) podemos obviar rutas y decirle que únicamente utilice las relativas al CRUD.

También hemos de crear el modelo. En este momento voy a ir creando modelos (aunque se pueden usar factorías y demás opciones, eso ya lo dejo de momento a la investigación de cada uno, o para más adelante). Para ello el comando es

Nota: un apunte, si ejecutamos directamente el comando de crear modelo con el modificador resource, como en el controlador, ya nos creara el modelo y el controlador enlazados (lo cual nos agilizará un poco estos pasos)

Y ahora hay que meterse en harina.

Con el siguiente comando podemos ver una lista de las rutas que están incluidas en este momento. Así veremos los métodos y opciones que se van a utilizar para las operaciones.

Y ahora se tratará de ir modificando las funciones en el controlador y o el modelo para ir adaptando el control de usuarios.

Dejo por ejemplo el código (sin finalizar) de la función de guardar un usuario

Tras modificar todas las funciones, estaremos listos para el siguiente paso Smile

Laravel 5.4 y Angular 4. Base de datos.

Continuamos con esta serie de entradas de un proyecto con Laravel.

Dado que voy a utilizar Laravel como backend y voy a generar una API REST con este framework, es hora de prepararlo.

Así que vamos con ello.

Preparando la base de datos.

Lo primero de todo proyecto es preparar la base de datos.

En estas lides nos va a resultar muy útil el sistema de “migraciones” (migrates) y “semillas” (seeds) de Laravel.
No me voy a detener mucho tiempo en definir que son, para eso recomiendo mirar la documentación.

User Migrate.

Para empezar, al menos en este proyecto, modificaremos el archivo “2014_10_12_000000_create_users_table.php”, que es un archivo de migración que se copia al iniciar el proyecto con composer para generar la tabla de usuarios, y ya que está, para que complicarnos.
No pongo todos los campos que voy a utilizar en la vase de datos, únicamente alguno o los no relevantes.
Todas las migraciones tienen dos funciones, la función up() y la down(), que son las acciones al crear la base de datos o cuando se hace algún rollback, respectivamente. En la función up() incluiremos lo siguiente:

Levels Migrate

En mi caso, y para la aplicación, voy a incluir un sistema de niveles, por lo que es necesario una tabla que guarde los niveles a utilizar.
Para crear el migrate que se encargará de crear la base de datos.

Una vez creado, le generaremos los campos necesarios (idlevel y name) en el código de la misma manera que para el usuario.

En este caso, lo más recomendable es insertar algunas filas, para lo que será necesario que utilicemos los seeders de Laravel para rellenar esos huecos.

Para empezar, crearemos un Seeder, que se guardará en la carpeta Database/seeds

Una vez creado, al entrar a modificarlo observaremos que únicamente tiene la función run(), donde se ejecutarán los procesos que rellenaran las filas de la tabla.

Aquí en este caso, voy a incluir los registros necesarios (ya que mi plan para esta tabla es un numero finito y relativamente asequible de mantener), aunque se puede automatizar con Factorias. Así que, de momento, incluiré el siguiente código:

Nota: que no se os olvide incluir el uso de Carbon en esta clase, porque sino no funcionará. Añadid

al inicio del archivo, en la sección de uses.

Una vez generado el archivo del seed, es necesario indicar que se ejecutará. Para ello, lo primero es modificar el archivo “App\Database\seeds\DatabaseSeeder.php”, en el cual hay que añadir la clase seed que acabamos de crear, así que dentro de la función run de este archivo incluiremos una línea por cada seeder que queramos ejecutar:

Una vez hecho todo esto, para ejecutar estos seeds hay tres formas principales:

O bien ejecutarlo cuando se hace un migrate:refresh (explicado debajo).

Utilizando migrates y seeds

Ahora es el momento de hacer que Laravel ejecute estas migraciones y rellenos de datos.

Para ello, el comando a ejecutar es :

Para que se ejecuten los seeds es necesario ejecutar el siguiente:

Pero si quereis regenerar la base de datos completa e incluir los cambios, lo mejor es ejecutar:

Esto hará que se reinicie todos los campos y migraciones de la base de datos.

Nota: es posible que os dé un error, en estos casos antes del migrate:refresh o de ejecutar los seeds, es recomendable ejecutar lo siguiente:

Para que se regenere el árbol de clases que utilizará luego artisan.

Conclusión

De esta forma, y tras generar todos los migrates y seeds necesarios para todos los campos y tablas de la base de datos que vaya a utilizar nuestra aplicación, estaremos preparados para poder empezar a meternos en harina para generar las rutas, controladores, modelos, etc, que va a necesitar nuestra aplicación.

Qué seguiremos con ello en el siguiente capítulo.

Gracias por seguir hasta aquí 😉

 

 

Laravel 5.4 y Angular 4. Inicio.

Bienvenidos.

Vamos a comenzar el desarrollo de una aplicación con Laravel 5.4 y Angular 4.

En esta entrada comenzaremos por instalar Laravel, corregirlo para poder ser utilizado por el servidor Virtualmin y configuraremos el IIS para que acepte toda esta estructura. También instalaremos angular 4 para poder hacer el desarrollo de la parte frontend.

Tras mucho bucear por internet y por tutoriales y preguntas en stackoverflow y sitios similares, al final voy a optar por un entorno separado. La parte frontend (con AngularJS) es la que irá en la dirección principal, y la parte backend (con Laravel) se encontrará en un subdominio “api”. Así cada proyecto está separado y no se pegan entre ellos y simplifica los cambios y despliegues de cada parte.

Instalando Laravel 5.4.

Lo más sencillo (al menos en mi caso) es utilizar Composer para que se instale laravel en el directorio que voy a utilizar para desarrollar.

Lo primero es elegir la carpeta dónde se va a desarrollar.

Por lo tanto, en una terminal, dentro de la carpeta del proyecto, comenzaremos con la instalación de Laravel.

Con lo que se nos instalará la base del framework.

Una vez conseguido, voy a seguir las instrucciones que ya detallé aquí para tener el entorno listo para virtualmin, y que en resumidas cuentas vienen a ser:

  • Mover la carpeta “public” dentro de “nombre_laravel” a la raíz de nuestro proyecto.
  • Renombrar “public” a “public_html” dentro de su nueva ubicación.
  • Cambiar las líneas 22 y 36 de “public_html/index.php”.

En mi caso han quedado así (sí, he puesto “laravel” a la carpeta de Laravel, original 😉 ):

Una vez realizado todo esto, procedo a subirlo al servidor IIS de pruebas, para lo cual sigo los siguientes pasos:
  • Tener una carpeta para el proyecto.
  • Copiar las carpetas public_html y laravel a la carpeta del proyecto dentro del servidor IIS (se acepta el método preferido de cada uno)
  • Importante: Asegurarse de que el usuario IUSR tiene control total (al menos de momento para desarrollar) en la carpeta del proyecto y todos sus archivos y carpetas dependientes.

  • Crear un nuevo sitio en IIS que apunte a la carpeta “public_html” dentro de nuestro proyecto.
  • Probar en el navegador.

Si todo ha ido bien tendremos instalado Laravel listo para comenzar.

Para desplegarlo en el sitio remoto (con virtualmin y apache), será necesario subir por ftp las dos carpetas, laravel y public_html a la raíz del subdominio donde se va a ejecutar.

Instalando Angular 4.

Ha llegado el momento de instalar la base de Angular 4 para comenzar a trabajar.

Para ello, y siguiendo con la terminal de VS code, lo mejor es seguir los siguientes pasos.

  • Asegurarse de que tenemos node instalado con “node -v”.
  • Después ver si se tiene instalado el Angular-CLI con el comando “ng -v”. De no ser así ejecutar “npm install -g @angular/cli” para instalarlo globalmente y que nos sirva para otros desarrollos.
  • Efectuar la instalación de una aplicación AngularJS con el comando “ng new web” (nombre para el proyecto original otra vez jeje).
  • al finalizar tendremos una estructura de carpetas parecida a la siguiente, en el ordenador de desarrollo.

Para probar que está en marcha, lo mejor es utilizar una nueva terminal de consola o powershell, y probar a arrancar angularjs con el comando “npm start” dentro de la carpeta “angular” de nuestro proyecto. Y acceder con un navegador a la url http://localhost:4200

Para poder probar esta primera instalación en el sitio remoto, será necesario seguir estos pasos:

  • Ejecutar en la carpeta de angular (web) el comando ng build –prod para que se generen y compilen las fuentes.
  • Esto creara un directorio “dist” dentro de la carpeta del proyecto de Angular.
  • Subir por ftp el contenido de la carpeta “dist” a la carpeta “public_html” del dominio remoto.
  • Probar en el sitio remoto.

Y con todo esto ya tendremos las dos herramientas funcionando y listas para comenzar.

He elegido esta separación de carpetas por dos motivos: Para poder enviar al servidor virtualmin lo necesario para los proyectos y que la parte privada siga funcionando correctamente, y para poder tener cada desarrollo totalmente separado, dado que utilizaré Laravel para formar la parte backend y angular para la parte frontend.

Nos vemos en la siguiente parte.

Iniciando un proyecto: Laravel 5.4 y Angular 4

Hola a todos.

Hoy voy a empezar una serie de entradas contando mi experiencia al tratar de combinar estas dos tecnologías.

He buceado mucho por internet buscando la manera de hacerlo y, sinceramente, no me ha quedado clara la forma al final. Así que me he decidido a ir contando lo que me ha ido ocurriendo al tratar de utilizar estas tecnologías.

Consideraciones.

  • Estoy aprendiendo a la vez que voy a ir publicando estas entradas, así que es probable que haya fallos o cosas que no funcionen del todo, por lo que todo comentario será bienvenido.
  • No habrá videos (carita triste), así que intentaré que las explicaciones estén lo suficientemente detalladas como para poder seguirlas sin problemas (y lo que me falte se puede comentar o imaginar y descubrir)
  • Voy a desarrollar con VS Code, sobre Windows 10, desplegar en pruebas en un Windows Server 2012 (IIS) y utilizaré un servidor Ubuntu con Virtualmin para el despliegue “a producción” (dado que es un proyecto personal, incluso este último servidor se podría considerar de “pre-producción” o “desarrollo”.
  • Voy a intentar estructurar cada parte como si fuera un curso, por lo que habrá varias entradas relacionadas, y aquí en esta entrada estará el índice de todas.
  • Para que todo funcione, seguiré las instrucciones de instalación de los sitios oficiales, o indicaré los post o sitios dónde he encontrado respuestas.
  • Para que todo funcione se supone que se ha seguido la instalación de:
  • La aplicación estará disponible, por lo que los avances (o desastres), se podrán ver ahí.
    (Actualización: de momento va a dejar de funcionar el dominio donde estaba alojada, estoy pensando dónde continuarlo, el trabajo y otras cuestiones no me han dejado continuar por ahora. Probablemente lo pase a un subdominio de este.)
  • De momento no voy a subir el código a repositorios como GitHub. Si que están bajo control de código git, pero alojados en mi propio servidor. No quiero hacer demasiados commits y push (elección personal).

Índice de temas:

Laravel.

  1. Instalando y configurando herramientas.
  2. Preparando la base de datos.
  3. Comenzando API. CRUD Usuarios.
  4. Rutas de la Aplicación.
  5. Securizando la API.
  6. Middlewares.
  7. CORS.

AngularJS.

  1. Instalando Angularjs.
  2. Añadiendo Jquery y Bootstrap.
  3. Modificando el menu superior.
  4. Cambiando los estilos de la app.
  5. Implementando login.
  6. Entornos.
  7. Cambiando el login para que funcione con la API.

Desarrollar con Laravel en un servidor con Virtualmin.

Bien, un pequeño tutorial.

Si deseamos instalar y desarrollar con Laravel en un servidor de hosting que tiene instalado Virtualmin, es necesario realizar algunos pasos.

La solución la he encontrado en https://laravel.io/forum/03-06-2015-how-to-setup-laravel-5-in-shared-hosting y en concreto ha consistido en:

  1. Partiendo de la base de que composer está instalado correctamente, y de que se ha realizado la instalación de laravel.
  2. Ejecutar en la raiz del dominio (donde se encuentra el directorio “public_html” el siguiente comando composer create-project –prefer-dist laravel/laravel ./nombre_proyecto
  3. mover los archivos de la carpeta public de “nombre_proyecto” a la carpeta “public_html”
  4. Y aqui viene la magia:
    1. Ir a public_html/index.php y cambiar en la línea 22:
    2. Seguimos en index.php, cambiar en la linea 36
    3. ir a public_html/.htaccess y editarlo, en mi caso ha quedado algo así:

A partir de este momento en el navegador ya se presentará la pantalla de inicio de Laravel. Si no ha ido algo bien se tendrá una bonita pantalla en blanco

Error con Git: “Cannot access URL return code 22”

Una de las cosas que os pueden ocurrir al trabajar con git es que os salga este bonito error “Cannot access URL return code 22” .

Antecedentes:

  • El repositorio no está en GitHub, sino en un repositorio personal.
  • El repositorio fue creado con Virtualmin, con la sección de “Git Repositories” de un dominio.
  • Tratais de hacer un push para subir los cambios.

Tratando de buscar la solución, la he encontrado con StackOverFlow: http://stackoverflow.com/questions/5264949/cannot-push-git-to-remote-repository-with-http-https

La solución es editar el archivo config que está dentro de la carpeta .git del repositorio local.

Y donde pone:

Cambiarlo a:

Es decir, añadir el usuario y la contraseña que se van a usar para acceder al repositorio.

Entonces ya si que funciona un  git push origin master.

 

PHP 7 y MySQL

Apunte rápido.

Si se hace una migración de versión a PHP 7, hay una cosa que se ha de tener en cuenta en los desarrollos.

Hasta ahora había 3 formas principales de acceso a los datos de MySQL, el driver mysql, el más moderno mysqli, y a través de PDO.

Si os encontrais con desarrollos que utilicen el viejo driver mysql, dejarán de funcionar muy probablemente todos esos maravillosos objetos y funciones que obtengan los datos de MySQL.

La solución pasa por cambiar el código para usar alguno de los más modernos. Si no quereis complicaros mucho la solución sencilla (al menos para mí) consiste en cambiar en el código la el texto “mysql” por “mysqli”.

Sin embargo, no funcionará solo con ese cambio. Hay que tener en cuenta que para las funciones de selección de juego de caracteres y recuperación de datos necesitarán que se les incluya la conexión.

También, para mejorar el proceso, en PHP7 deja de permitirse el generar el constructor de un objeto utilizando como nombre de funcion el nombre de la clase, pasando a tener que utilizar un metodo “__construct”.

Aquí os dejo un pequeño ejemplo:

class bd{
var $host;
var $conexion;
var $bd;
var $usuario;
var $clave;
var $tipo;

/*metodo contructor que carga los datos de la conexion. Este ya NO ES VALIDO*/
/*
function bd(){
global $bdhost;
global $bdnombre;
global $bdusuario;
global $bdclave;
$this->host=$bdhost;
$this->bd=$bdnombre;
$this->usuario=$bdusuario;
$this->clave=$bdclave;
$this->tipo=”mysqli”;
$this->conexion=mysqli_connect($this->host, $this->usuario, $this->clave) or die (mysqli_error());
mysqli_set_charset($this->conexion, ‘utf8’);
mysqli_select_db($this->bd, $this->conexion) or die(“Error en la selecci�n de la base de datos”);
}//contructor
*
*/

function __construct(){
global $bdhost;
global $bdnombre;
global $bdusuario;
global $bdclave;
$this->host=$bdhost;
$this->bd=$bdnombre;
$this->usuario=$bdusuario;
$this->clave=$bdclave;
$this->tipo=”mysqli”;
$this->conexion=mysqli_connect($this->host, $this->usuario, $this->clave) or die (mysqli_error());
mysqli_set_charset($this->conexion, ‘utf8’);
mysqli_select_db($this->conexion, $this->bd ) or die(“Error en la selección de la base de datos”);
}//contructor

/*funcion que ejecuta una sentencia sql sobre la base de dato y devuelve la consulta a dicha base*/
function query($sql){
$query=mysqli_query($this->conexion,$sql) or die(“Error MySql: “.mysqli_error().” “.$sql);
return $query;
}//query

/*funcion que devuelve el numero de filas cuando se le pasa una consulta generada por sql*/
function num_rows($query){
$num_rows=mysqli_num_rows($query);
return $num_rows;
}//num_rows

/*funcion que va sacando los datos con formato de array asociativo de una consulta generada por sql
la cual se le pasa, cada vez que se le llama avanza una fila*/
function fetch_array($query){
$fila=mysqli_fetch_array($query);
return $fila;
}//fetch_array

/*funcion que va sacando los datos con formato de objeto de una consulta generada por sql
la cual se le pasa, cada vez que se le llama avanza una fila*/
function fetch_object($query){
$fila=mysqli_fetch_object($query);
return $fila;
}//fetch_object

/*funcion que libera el buffer de la consulta generada por sql que se le pasa*/
function free_result($query){
mysqli_free_result($query);
}//free_result

/*funcion que cierra la conexion de la base de datos*/
function cerrar(){
mysqli_close();
}//cerrar conexion
}//class bdwd
?>

Virtualmin mod_fcgid error: No se ejecuta el código php.

Hoy volvemos con una nota rápida.

Para aquellos que uséis Virtualmin para configurar vuestros servidores, si os ocurre como a mi, que tras instalarlo en un servidor y recuperar una copia de seguridad anterior cuando intentáis acceder a los sitios que teníais configurados os da para descargar el archivo php en vez de ejecutarlo, os puede suceder por lo siguiente:

Comprobad que:
En la parte de “Opciones del website”, dentro de “Configuración del servidor” dentro del dominio…

image

Estan las opciones como os muestro:image

Después, y esto es lo que me dio guerra, y al final he encontrado la solución en https://www.virtualmin.com/node/25521, y aquí os muestro los pasos:

  1. imageDirigiros a “Configurar Website” dentro de “Servicios”, en el dominio.
  2. Entráis a “Editar Directivas”, que se muestra con este icono.image
  3. Comprobad si en el archivo del dominio se encuentran las siguientes líneas:
    RemoveHandler .php
    RemoveHandler .php5
    php_admin_value engine Off
    y si es así, eliminadlas.
  4. Recargad el servidor Apache y a correr.

Colaborando con Freddy Varó.

Viejos amigos, nuevos proyectos.

Desde hace unas semanas vengo colaborando con el mago profesional Freddy Varó,

Principalmente es sobre todo ayuda técnica, orientada a las necesidades tecnológicas y cotidianas que le pueden surgir a cualquier profesional, tanto de la rama de espectáculos como de cualquier otra.

Toda compañia es buena si sirve para crecer e ir aprendiendo, y la verdad es que con Freddy he ido descubriendo algunas cuestiones que interesan a la hora de crecer y plantear nuevos retos.

Y desde luego, en el plano profesional, es un auténtico “crack”. Todas sus actuaciones estan preparadas a conciencia y consigue algo complicado, que niños y mayores estén pendientes de su actuación hasta el final. Siempre sorprendente y siempre agradable.

Os invito a visitar su página o a seguirle en Facebook o Twitter y enteraros de todas sus novedades.

Vladimir-Magic-Portada

Windows 8.1. Impresiones.

imageBien, tras más de un año como usuario de Windows 8 (tanto en las betas como en la versión final) no me he podido resistir y actualice Windows 8 a la Release Preview del 8.1 (o actualización Blue)

Que puedo decir, si antes el sistema iba fluido pero adolecía de algunos “problemas” a la hora de adaptarse a la nueva forma de trabajar, ahora muchos de esos temas se han solventado.

Para empezar la sensación de “doble personalidad”: no la ha perdido del todo, pero detalles como que el fondo de la parte “Modern UI” y el fondo del escritorio clásico sean el mismo se agradecen y le dan sensación de conjunto.
No por eso deja uno de tener esa impresión cuando cambia entre aplicaciones Windows 8 y aplicaciones clásicas, pero al menos ya no da ese “golpe” a la vista cada vez que se van a utilizar los programas.

El botón de inicio: ¡ha vuelto! Si bien es cierto que no como antes. Su función primaria es la de enviarte a la pantalla principal de selección de “Modern UI” pero también tiene cositas útiles si se le utiliza con el botón derecho, tal como se ve en la imagen adjunta. Un buen montón de opciones que nos evitarán perdernos a la hora de tocar algunas opciones del panel de control (que casi siempre son las más utilizadas).

Un sistema fluido, detalles que si se echaban de menos cuando salió Windows 8. La verdad es que esta actualización de Windows 8 da la misma idea que dió Windows 7 y su antecesor, Windows Vista… “¿Por qué no lo sacaron así a la primera?”