Skip to content

Commit cf03cc4

Browse files
authored
Merge pull request #2678 from vlondonoma/patch-12
[es] Part4d content update
2 parents c6db68e + d5b4148 commit cf03cc4

File tree

1 file changed

+81
-26
lines changed

1 file changed

+81
-26
lines changed

src/content/4/es/part4d.md

Lines changed: 81 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,24 @@ La función auxiliar _getTokenFrom_ aísla el token del encabezado de <i>authori
194194
const decodedToken = jwt.verify(token, process.env.SECRET)
195195
```
196196

197+
La verificación del token también puede causar un error <i>JsonWebTokenError</i> si es que es inválido o está ausente. Extendamos nuestro middleware para tener en cuenta este caso particular.
198+
199+
```js
200+
const errorHandler = (error, request, response, next) => {
201+
logger.error(error.message)
202+
203+
if (error.name === 'CastError') {
204+
return response.status(400).send({ error: 'malformatted id' })
205+
} else if (error.name === 'ValidationError') {
206+
return response.status(400).json({ error: error.message })
207+
} else if (error.name === 'JsonWebTokenError') { // highlight-line
208+
return response.status(400).json({ error: error.message }) // highlight-line
209+
}
210+
211+
next(error)
212+
}
213+
```
214+
197215
El objeto decodificado del token contiene los campos <i>username</i> y <i>id</i>, que le dice al servidor quién hizo la solicitud.
198216

199217
Si no hay ningún token, o el objeto decodificado del token no contiene la identidad del usuario (_decodedToken.id_ no está definido), el código de estado de error [401 unauthorized](https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2) es devuelto y el motivo del error se explica en el cuerpo de la respuesta.
@@ -217,50 +235,87 @@ Usando Postman, esto se ve de la siguiente manera:
217235
y con el cliente REST de Visual Studio Code
218236

219237
![](../../images/4/21e.png)
238+
239+
El código de la aplicación actual se puede encontrar en [Github](https://github.com/fullstack-hy2020/part3-notes-backend/tree/part4-9), rama <i>part4-9</i>.
240+
241+
Si la aplicación tiene múltiples interfaces que requieren identificación, la validación de JWT debe separarse en su propio middleware. También se podría utilizar alguna librería existente como [express-jwt](https://www.npmjs.com/package/express-jwt).
220242

221-
### Manejo de errores
243+
### Problemas de la autenticación basada en Tokens
222244

223-
La verificación del token también puede causar un <i>JsonWebTokenError</i>. Si, por ejemplo, eliminamos algunos caracteres del token e intentamos crear una nueva nota, esto sucede:
245+
La autenticación basada en tokens es muy fácil de implementar, pero tiene un problema. Una vez que el cliente de la API, por ejemplo una aplicación React, obtiene un token, la API tiene una confianza ciega en el titular del token. ¿Qué sucede si necesitamos revocar los derechos de acceso del titular del token?
224246

225-
```bash
226-
JsonWebTokenError: invalid signature
227-
at /Users/mluukkai/opetus/_2019fullstack-koodit/osa3/notes-backend/node_modules/jsonwebtoken/verify.js:126:19
228-
at getSecret (/Users/mluukkai/opetus/_2019fullstack-koodit/osa3/notes-backend/node_modules/jsonwebtoken/verify.js:80:14)
229-
at Object.module.exports [as verify] (/Users/mluukkai/opetus/_2019fullstack-koodit/osa3/notes-backend/node_modules/jsonwebtoken/verify.js:84:10)
230-
at notesRouter.post (/Users/mluukkai/opetus/_2019fullstack-koodit/osa3/notes-backend/controllers/notes.js:40:30)
247+
Hay dos soluciones al problema. La más fácil es limitar el período de validez de un token:
248+
249+
```js
250+
loginRouter.post('/', async (request, response) => {
251+
const { username, password } = request.body
252+
253+
const user = await User.findOne({ username })
254+
const passwordCorrect = user === null
255+
? false
256+
: await bcrypt.compare(password, user.passwordHash)
257+
258+
if (!(user && passwordCorrect)) {
259+
return response.status(401).json({
260+
error: 'invalid username or password'
261+
})
262+
}
263+
264+
const userForToken = {
265+
username: user.username,
266+
id: user._id,
267+
}
268+
269+
// token expires in 60*60 seconds, that is, in one hour
270+
// highlight-start
271+
const token = jwt.sign(
272+
userForToken,
273+
process.env.SECRET,
274+
{ expiresIn: 60*60 }
275+
)
276+
// highlight-end
277+
278+
response
279+
.status(200)
280+
.send({ token, username: user.username, name: user.name })
281+
})
231282
```
232283

233-
Hay muchas razones posibles para un error de decodificación. El token puede ser defectuoso (como en nuestro ejemplo), falsificado o vencido. Extendamos nuestro middleware errorHandler para tener en cuenta los diferentes errores de decodificación.
284+
Una vez que el token caduca, la aplicación cliente necesita obtener un nuevo token. Por lo general, esto sucede al obligar al usuario a volver a iniciar sesión en la aplicación.
234285

235-
```js
236-
const unknownEndpoint = (request, response) => {
237-
response.status(404).send({ error: 'unknown endpoint' })
238-
}
286+
El middleware de manejo de errores debe extenderse para dar un error adecuado en el caso de un token caducado:
239287

288+
```js
240289
const errorHandler = (error, request, response, next) => {
290+
logger.error(error.message)
291+
241292
if (error.name === 'CastError') {
242-
return response.status(400).send({
243-
error: 'malformatted id'
244-
})
293+
return response.status(400).send({ error: 'malformatted id' })
245294
} else if (error.name === 'ValidationError') {
246-
return response.status(400).json({
247-
error: error.message
295+
return response.status(400).json({ error: error.message })
296+
} else if (error.name === 'JsonWebTokenError') {
297+
return response.status(401).json({
298+
error: 'invalid token'
299+
})
300+
// highlight-start
301+
} else if (error.name === 'TokenExpiredError') {
302+
return response.status(401).json({
303+
error: 'token expired'
248304
})
249-
} else if (error.name === 'JsonWebTokenError') { // highlight-line
250-
return response.status(401).json({ // highlight-line
251-
error: 'invalid token' // highlight-line
252-
}) // highlight-line
253305
}
254-
255-
logger.error(error.message)
306+
// highlight-end
256307

257308
next(error)
258309
}
259310
```
260311

261-
El código de la aplicación actual se puede encontrar en [Github](https://github.com/fullstack-hy2020/part3-notes-backend/tree/part4-9), rama <i>part4-9</i>.
312+
Cuanto más corto sea el tiempo de caducidad, más segura será la solución. Por lo tanto, si el token cae en las manos equivocadas o es necesario revocar el acceso del usuario al sistema, el token solo se puede utilizar durante un período de tiempo limitado. Por otro lado, un tiempo de caducidad corto genera un dolor potencial para el usuario, ya que le implica iniciar sesión en el sistema con más frecuencia.
262313

263-
Si la aplicación tiene múltiples interfaces que requieren identificación, la validación de JWT debe separarse en su propio middleware. También se podría utilizar alguna librería existente como [express-jwt](https://www.npmjs.com/package/express-jwt).
314+
La otra solución es guardar información sobre cada token en la base de datos y verificar en cada solicitud de API si el derecho de acceso correspondiente al token sigue siendo válido. Con este esquema, los derechos de acceso pueden ser revocados en cualquier momento. Este tipo de solución a menudo se denomina <i>server-side session</i>.
315+
316+
El aspecto negativo de las sesiones del lado del servidor es la mayor complejidad en el backend y también el efecto en el rendimiento, ya que se debe verificar la validez del token para cada solicitud de API a la base de datos. El acceso a la base de datos es considerablemente más lento en comparación con la verificación de la validez del token en sí. Es por eso que es bastante común guardar la sesión correspondiente a un token en una <i>base de datos de llave-valor</i> como [Redis](https://redis.io/) que tiene una funcionalidad limitada en comparación con MongoDB o bases de datos relacionales, pero es extremadamente rápida en algunos escenarios de uso.
317+
318+
Cuando se utilizan sesiones del lado del servidor, el token suele ser solo una cadena aleatoria, que no incluye ninguna información sobre el usuario, como suele ser el caso cuando se utilizan jwt-tokens. Para cada solicitud de API, el servidor obtiene la información relevante sobre la identidad del usuario de la base de datos. También es bastante habitual que, en lugar de utilizar el encabezado de autorización, se utilicen <i>cookies</i> como mecanismo para transferir el token entre el cliente y el servidor.
264319

265320
### Notas finales
266321

0 commit comments

Comments
 (0)