Gerenciar Tokens Web JSON no desenvolvimento com dotnet user-jwts

Por Rick Anderson

A ferramenta de linha de comando dotnet user-jwts pode criar e gerenciar JWTs (Tokens Web JSON) locais específicos do aplicativo.

Sinopse

dotnet user-jwts [<PROJECT>] [command]
dotnet user-jwts [command] -h|--help

Descrição

Cria e gerencia Tokens Web JSON locais específicos do projeto.

Argumentos

PROJECT | SOLUTION

O projeto do MSBuild ao qual aplicar um comando. Se um projeto não for especificado, o MSBuild procurará no diretório de trabalho atual um arquivo que tenha uma extensão que termine em proj e usará esse arquivo.

Comandos

Comando Descrição
clear Excluir todos os JWTs emitidos para um projeto.
create Emitir um novo Token Web JSON.
remove Excluir um JWT específico.
chave Exibir ou redefinir a chave de assinatura usada para emitir JWTs.
lista Listar os JWTs emitidos para o projeto.
print Exibir os detalhes de um JWT específico.

Criar

Uso: dotnet user-jwts create [options]

Opção Descrição
-p | --project O caminho do projeto para operar. O padrão é o projeto no diretório atual.
--scheme O nome do esquema a ser usado para o token gerado. O padrão é "Portador".
-n | --name O nome do usuário para o qual será criado o JWT. O padrão é o usuário do ambiente atual.
--audience O público-alvo para o qual será criado o JWT. O padrão são as URLs configuradas no launchSettings.json do projeto.
--issuer O emissor do JWT. O padrão é "dotnet-user-jwts".
--scope Uma declaração de escopo para adicionar ao JWT. Especificar uma vez para cada escopo.
--role Uma declaração de função para adicionar ao JWT. Especificar uma vez para cada função.
--claim Declarações para adicionar ao JWT. Especificar uma vez para cada declaração no formato "name=value".
--not-before A data e hora UTC do JWT não deve ser válida antes do formato "aaaa-MM-dd [[HH:mm[[:ss]]]]". O padrão é a data e hora em que o JWT é criado.
--expires-on A data e hora UTC em que o JWT deve expirar no formato "aaaa-MM-dd [[[ [HH:mm]]:ss]]". O padrão é 6 meses após a data --not-before. Não use essa opção em conjunto com a opção --valid for.
--valid-for O período após o qual o JWT deve expirar. Especifique usando um número seguido do tipo de duração como "d" para dias, "h" para horas, "m" para minutos e "s" para segundos, por exemplo, 365d. Não use essa opção em conjunto com a opção --expires-on.
-o | --output O formato a ser usado para exibir a saída do comando. Pode ser um dos formatos "default", "token" ou "json".
-h | --help Mostra informações da Ajuda

Exemplos

Execute os seguintes comandos para criar um projeto Web vazio e adicionar o pacote NuGet Microsoft.AspNetCore.Authentication.JwtBearer:

dotnet new web -o MyJWT
cd MyJWT
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer

Substitua o conteúdo de Program.cs pelo seguinte código:

using System.Security.Claims;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddAuthorization();
builder.Services.AddAuthentication("Bearer").AddJwtBearer();

var app = builder.Build();

app.UseAuthorization();

app.MapGet("/", () => "Hello, World!");
app.MapGet("/secret", (ClaimsPrincipal user) => $"Hello {user.Identity?.Name}. My secret")
    .RequireAuthorization();

app.Run();

No código anterior, uma solicitação GET para /secret retorna um erro 401 Unauthorized. Um aplicativo de produção pode obter o JWT de um Serviço de token de segurança (STS), talvez em resposta ao logon por meio de um conjunto de credenciais. Para trabalhar com a API durante o desenvolvimento local, a ferramenta de linha de comando dotnet user-jwts pode ser usada para criar e gerenciar JWTs locais específicos do aplicativo.

A ferramenta user-jwts é semelhante em conceito à ferramenta user-secrets, podendo ser usada para gerenciar valores para o aplicativo que são válidos apenas para o desenvolvedor no computador local. Na verdade, a ferramenta user-jwts utiliza a infraestrutura user-secrets para gerenciar a chave com a qual os JWTs são assinados, garantindo que ela seja armazenada com segurança no perfil do usuário.

A ferramenta user-jwts oculta detalhes de implementação, como onde e como os valores são armazenados. A ferramenta pode ser usada sem conhecer os detalhes da implementação. Os valores são armazenados em um arquivo JSON na pasta de perfil de usuário do computador local:

Caminho do sistema de arquivos:

%APPDATA%\Microsoft\UserSecrets\<secrets_GUID>\user-jwts.json

Criação de um JWT

O seguinte comando cria um JWT local:

dotnet user-jwts create

O comando anterior cria um JWT e atualiza o arquivo appsettings.Development.json do projeto com JSON semelhante ao seguinte:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "Authentication": {
    "Schemes": {
      "Bearer": {
        "ValidAudiences": [
          "http://localhost:8401",
          "https://localhost:44308",
          "http://localhost:5182",
          "https://localhost:7076"
        ],
        "ValidIssuer": "dotnet-user-jwts"
      }
    }
  }
}

Copie o JWT e o ID criado no comando anterior. Use uma ferramenta como Curl para testar /secret:

curl -i -H "Authorization: Bearer {token}" https://localhost:{port}/secret

Onde {token} é o JWT gerado anteriormente.

Exibição de informações de segurança do JWT

O seguinte comando exibe as informações de segurança do JWT, incluindo expiração, escopos, funções, cabeçalho e conteúdo do token e o token compacto:

dotnet user-jwts print {ID} --show-all

Criação de um token para um usuário e escopo específicos

Consulte Criar neste tópico para ver as opções de criação compatíveis.

O seguinte comando cria um JWT para um usuário chamado MyTestUser:

dotnet user-jwts create --name MyTestUser --scope "myapi:secrets"

O comando anterior tem uma saída semelhante à seguinte:

New JWT saved with ID '43e0b748'.
Name: MyTestUser
Scopes: myapi:secrets

Token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.{Remaining token deleted}

O token anterior pode ser usado para testar o ponto de extremidade /secret2 no seguinte código:

using System.Security.Claims;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddAuthorization();
builder.Services.AddAuthentication("Bearer").AddJwtBearer();

var app = builder.Build();

app.MapGet("/", () => "Hello, World!");
app.MapGet("/secret", (ClaimsPrincipal user) => $"Hello {user.Identity?.Name}. My secret")
    .RequireAuthorization();
app.MapGet("/secret2", () => "This is a different secret!")
    .RequireAuthorization(p => p.RequireClaim("scope", "myapi:secrets"));

app.Run();