# 9.7 Refrescando tu token

Algunos servicios incluyen la opción de refrescar tu token, por ejemplo si un hacker obtiene tu token ya sea porque esta rastreando las peticiones al servicio o mediante un mail falso, si das un tiempo corto de vida, por ejemplo 1 hora, si un hacker obtiene el token solo podría utilizarlo durante máximo una hora, también puedes agregar validaciones para poder desactivar un token a un usuario.

Como ya tenemos la función que nos da el código para refrescar el token, vamos a crear el servicio para refrescar el token, será mediante un método POST y va a recibir como parámetro el código para refrescar el token.

Primero en nuestra clase **UsuarioAcceso** le vamos a cambiar la longitud a 400 caracteres

{% code title="UsuarioAcceso.cs" %}

```csharp
public class UsuarioAcceso
{
    //Otros campos
    [Column(TypeName = "VARCHAR(400)")]
    [Required(ErrorMessage = "Required")]
    public string Token { get; set; }
}
```

{% endcode %}

Agregamos la migración y actualizamos la base de datos.

En nuestra carpeta **DTO** agregamos la clase **RefreshTokenDTO** el cual va a contener solamente el código para refrescar el token.

{% code title="RefreshTokenDTO.cs" %}

```csharp
/// <summary>
/// Clase para refrescar el token
/// </summary>
public class RefreshTokenDTO
{
    /// <summary>
    /// Código para refrescar el token
    /// </summary>
    public string RefreshToken { get; set; }
}
```

{% endcode %}

Como para refrescar el token regresamos un nuevo Token, vamos a agregar una función para regresar el token, el cual vamos a utilizarlo para el login y para refrescar el token.&#x20;

{% code title="UsuarioDAO.cs" %}

```csharp
public TokenDTO GenerarToken(IConfiguration config, 
                             int usuarioId, 
                             string nombre)
{
    Token token = new Token(config);
    tokenDTO = new TokenDTO();
    var claims = new List<Claim>
    {
            new Claim(ClaimTypes.Sid, usuarioId.ToString()),
    };
    RolDAO rolDAO = new RolDAO(contexto, localizacion);
    var roles = rolDAO.ObtenerRolesPorUsuarios(usuarioId);

    foreach (var rol in roles)
    {
        claims.Add(new Claim(ClaimTypes.Role, rol));
        if (rol == "Vendedor" || rol == "Administrador")
        {
            var totalCategorias = contexto.UsuarioCategoria
                               .Where(u => u.UsuarioId == usuarioId)
                               .Count();
            if (totalCategorias > 0)
                claims.Add(new Claim("Categorias", 
                              totalCategorias.ToString()));
        }
    }
    DateTime fechaExpiracion = DateTime.Now.AddDays(15).ToLocalTime();
    tokenDTO.Token = token.GenerarToken(claims.ToArray(), 
                                                   fechaExpiracion);
    tokenDTO.TokenExpiration = fechaExpiracion;
    tokenDTO.UsuarioId = usuarioId;
    tokenDTO.RefreshToken = token.RefrescarToken();
    tokenDTO.Nombre = nombre;
    return tokenDTO;
}
```

{% endcode %}

Agregamos una función para validar el Token, para esto en nuestra tabla UsuarioAcceso vamos a buscar el código para refrescar el token. En esta tabla **UsuarioAcceso** cada vez que un usuario realiza el login vamos a registrar algunos datos como el **navegador**, **sistema operativo** y **ciudad** desde la cual se conecta el usuario, por el momento solo vamos a guardar el token y el código para refrescar el token.  Si todo es correcto generamos un nuevo token

{% code title="UsuarioDAO.cs" %}

```csharp
public bool ValidarToken(string refreshToken, IConfiguration config)
{
    //Buscamos el código para refrescar el token enviado
    var tokenGuardado = contexto.UsuarioAcceso
            .FirstOrDefault(u => u.RefreshToken == refreshToken 
                            && u.Activo);
    //No existe marcamos error
    if (tokenGuardado == null)
        return false;
    //Revisamos que el usuario este activo
    var usuario = contexto.Usuario.Find(tokenGuardado.UsuarioId);
    if (usuario == null || !usuario.Activo)
        return false;
    tokenDTO = GenerarToken(config, usuario.Id, usuario.Nombre);
    return true;
}
```

{% endcode %}

Cambiamos  nuestra función **LoginAsync** para guardar los datos del acceso del usuario en el login.

{% code title="UsuarioDAO.cs" %}

```csharp
public async Task<TokenDTO> LoginAsync(LoginDTO loginDTO, 
                                       IConfiguration config)
{
    Seguridad seguridad = new Seguridad();           
    var usuario = await contexto.Usuario
           .FirstOrDefaultAsync(usu => usu.Clave == loginDTO.Usuario);
    if (usuario == null)
    {
        customError = new CustomError(400,
            String.Format(this.localizacion
                 .GetLocalizedHtmlString("GeneralNoExiste"),
                    "La clave del usuario"));
        return tokenDTO;
    }
    if (usuario.Password != seguridad.
               GetHash(usuario.Adicional1 + loginDTO.Password))
    {
        customError = new CustomError(400,
                    this.localizacion
                       .GetLocalizedHtmlString("PasswordIncorrecto"));
        return tokenDTO;
    }
    if (!usuario.Activo)
    {
        customError = new CustomError(403,
                    this.localizacion
                          .GetLocalizedHtmlString("UsuarioInactivo"));
        return tokenDTO;
    }
    tokenDTO = GenerarToken(config, usuario.Id, usuario.Nombre);
    var usuarioAcceso = new UsuarioAcceso();
    usuarioAcceso.UsuarioId = usuario.Id;       
    usuarioAcceso.Fecha = DateTime.Now;
    usuarioAcceso.Token = tokenDTO.Token;
    usuarioAcceso.Activo = true;
    usuarioAcceso.Ciudad = "Default";
    usuarioAcceso.Estado = "Default";
    usuarioAcceso.SistemaOperativo = "Default";
    usuarioAcceso.RefreshToken = tokenDTO.RefreshToken;
    usuarioAcceso.Navegador = "Default";
    contexto.UsuarioAcceso.Add(usuarioAcceso);
    contexto.SaveChanges();
    return tokenDTO;
}
```

{% endcode %}

Por último agregamos el servicio para refrescar el token

{% code title="UsuariosController.cs" %}

```csharp
public class UsuariosController : BaseController
{
    [HttpPost("Refresh")]
    [AllowAnonymous]
    public IActionResult RefreshToken(
                            [FromBody]RefreshTokenDTO refreshToken)
    {
        UsuarioDAO usuarioDao = new UsuarioDAO(this._context, 
                                                   this._localizer);
        if (!usuarioDao.ValidarToken(refreshToken.RefreshToken,
                                                   _config))
            return StatusCode(403, new CustomError(403, 
                                 this._localizer
                                 .GetLocalizedHtmlString
                                 ("AccesoNoAutorizado")));
        return Ok(usuarioDao.tokenDTO);
    }
}
```

{% endcode %}

Puedes probar tus servicios con Postman. Puedes reducir el tiempo de expiración del token a 1 minuto para probar más rápido


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://abi.gitbook.io/net-core/7.-seguridad/7.7-refrescando-tu-token.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
