Validando tokens emitidos pelo AspNet.Security.OpenIdConnect.Server (ASP.NET vNext)

Estou usando o Visual Studio 2015 Enterprise e o ASP.NET vNext Beta8 para criar um ponto de extremidade que emita e consome tokens JWT. Originalmente, eu me aproximei disso gerando os tokens, conforme descritoaqui. Mais tarde, um útilartigo by @Pinpoint revelou que o AspNet.Security.OpenIdConnect.Server (também conhecido como OIDC) pode ser configurado para emitir e consumir os tokens para mim.

Então, eu segui essas instruções, levantei um ponto de extremidade e, ao enviar uma postagem x-www-form-urlencoded decarteiro Eu recebo de volta um token legítimo:

{
  "token_type": "bearer",
  "access_token": "eyJ0eXAiO....",
  "expires_in": "3599"
}

Isso é ótimo, mas também onde eu fico preso. Agora, como faço para anotar uma ação do controlador para exigir esse token de portador?

Eu pensei que tudo o que eu teria que fazer é decorar meu método de controlador com o [Authorize ("Bearer")], adicionar um esquema de autenticação:

        services.AddAuthorization
        (
            options => 
            {
                options.AddPolicy
                (
                    JwtBearerDefaults.AuthenticationScheme, 
                    builder => 
                    {
                        builder.
                        AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme).
                        RequireAuthenticatedUser().
                        Build();
                    } 
                );
            }
        );

E, em seguida, chame minha ação de controlador com o cabeçalho "Portador de autorização eyJ0eXAiO ....", como havia feito no exemplo anterior. Infelizmente, tudo o que essa abordagem parece fazer é gerar uma exceção:

Ocorreu uma exceção não tratada durante o processamento da solicitação.

SocketException: nenhuma conexão pôde ser estabelecida porque a máquina de destino a recusou ativamente 127.0.0.1:50000

WebException: Não foi possível conectar ao servidor remoto

HttpRequestException: ocorreu um erro ao enviar a solicitação.

IOException: IDX10804: Não foi possível recuperar o documento de: 'http: // localhost: 50000 / .well-conhecido / openid-configuração' Microsoft.IdentityModel.Logging.LogHelper.Throw (Mensagem de cadeia, Tipo exceptionType, EventLevel logLevel, Exception innerException)

InvalidOperationException: IDX10803: Não foi possível obter a configuração de: 'http: // localhost: 50000 / .well-conhecido / openid-configuração' Exceção interna: 'IDX10804: Não foi possível recuperar o documento de:'http: // localhost: 50000 / .well-conhecido / openid-configuração'.'.


Considere as seguintes etapas para reproduzir (mas não considere este código digno de produção):

Aplique as ferramentas do ASP.NET Beta8 conforme descritoaqui

Abra o Visual Studio Enterprise 2015 e crie um novo projeto de modelo de visualização da API da Web ASP.NET 5

Alterar project.json

{
"webroot": "wwwroot",
"version": "1.0.0- *",

"dependências": {
"Microsoft.AspNet.IISPlatformHandler": "1.0.0-beta8",
"Microsoft.AspNet.Mvc": "6.0.0-beta8",
"Microsoft.AspNet.Server.Kestrel": "1.0.0-beta8",
"Microsoft.AspNet.Authentication.JwtBearer": "1.0.0-beta8",
"AspNet.Security.OpenIdConnect.Server": "1.0.0-beta3",
"Microsoft.AspNet.Authentication.OpenIdConnect": "1.0.0-beta8",
"Microsoft.Framework.ConfigurationModel.Json": "1.0.0-beta4",
"Microsoft.AspNet.Diagnostics": "1.0.0-beta8"
}

"comandos": {
"web": "Microsoft.AspNet.Server.Kestrel"
}

"frameworks": {
"dnx451": {}
}

"excluir": [
"wwwroot",
"node_modules"
],
"publishExclude": [
".do utilizador",
"
.vspscc "
]
}

Altere o Startup.cs da seguinte maneira (isso é cortesia do artigo original da @ Pinpoint; removi os comentários e adicionei o snip AddAuthorization):

public class Startup
{
    public Startup(IHostingEnvironment env)
    {
    }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddAuthorization
        (
            options => 
            {
                options.AddPolicy
                (
                    JwtBearerDefaults.AuthenticationScheme, 
                    builder => 
                    {
                        builder.
                        AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme).
                        RequireAuthenticatedUser().
                        Build();
                    } 
                );
            }
        );
        services.AddAuthentication();
        services.AddCaching();
        services.AddMvc();
        services.AddOptions();
    }

    // Configure is called after ConfigureServices is called.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env, IOptions<AppSettings> appSettings)
    {
        app.UseDeveloperExceptionPage();

        // Add a new middleware validating access tokens issued by the OIDC server.
        app.UseJwtBearerAuthentication(options => {
            options.AutomaticAuthentication = true;
            options.Audience = "http://localhost:50000/";
            options.Authority = "http://localhost:50000/";
            options.ConfigurationManager = new ConfigurationManager<OpenIdConnectConfiguration>
            (
                metadataAddress : options.Authority + ".well-known/openid-configuration",
                configRetriever : new OpenIdConnectConfigurationRetriever(),
                docRetriever    : new HttpDocumentRetriever { RequireHttps = false }
            );
        });

        // Add a new middleware issuing tokens.
        app.UseOpenIdConnectServer
        (
            configuration => 
            {
                configuration.Options.TokenEndpointPath= "/authorization/v1";
                configuration.Options.AllowInsecureHttp = true;
                configuration.Provider = new OpenIdConnectServerProvider {

                    OnValidateClientAuthentication = context => 
                    {
                        context.Skipped();
                        return Task.FromResult<object>(null);
                    },

                    OnGrantResourceOwnerCredentials = context => 
                    {
                        var identity = new ClaimsIdentity(OpenIdConnectDefaults.AuthenticationScheme);
                        identity.AddClaim( new Claim(ClaimTypes.NameIdentifier, "todo")  );
                        identity.AddClaim( new Claim("urn:customclaim", "value", "token id_token"));
                        context.Validated(new ClaimsPrincipal(identity));
                        return Task.FromResult<object>(null);
                    }
                };
            }
        );

        app.UseMvc();
    }
}
Altere ValuesController.cs assistido para especificar um atributo Autorizar:
[Route("api/[controller]")]
public class ValuesController : Controller
{
    // GET: api/values
    [Authorize("Bearer")] 
    [HttpGet]
    public IEnumerable<string> Get()
    {
        return new string[] { "value1", "value2" };
    }
}

Execute o projeto e adquira um token usandocarteiro. Para adquirir um token, use o POST x-www-form-urlencoded com "grant_type" de "senha", "nome de usuário" qualquer coisa, "senha" qualquer coisa e "recurso" o endereço do terminal da API. Meu URL específico, por exemplo, éhttp: // localhost: 37734 / autorização / v1.

Copie o token codificado em Base64 e use o token para chamar o controlador de valores assistidos usandocarteiro. Para usar o token, faça um GET com os cabeçalhos application-json do tipo de conteúdo e portador da autorização eyJ0eXAiO .... (seu token). Meu URL específico éhttp: // localhost: 37734 / api / values.

Observe a exceção mencionada anteriormente.

Se a abordagem [Autorizar ("Portador")] que estou tentando acima for o caminho errado, ficaria muito grato se alguém pudesse me ajudar a entender as práticas recomendadas para como ingerir o token JWT usando o OIDC.

Obrigado.

questionAnswers(1)

yourAnswerToTheQuestion