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.