我正在用 asp.net core 2.0、AspNet.Security.OpenIdConnect.Server 和 AspNet.Security.OAuth.Extensions 编写一个测试应用程序。我遇到了访问令牌自省的问题。当我从 /connect/token 获取令牌并将其发送到我的资源服务器时,我的服务器中出现以下错误:
fail: AspNet.Security.OpenIdConnect.Server.OpenIdConnectServerHandler[0]
The introspection request was rejected with the following error: invalid_request ; (null)
info: AspNet.Security.OpenIdConnect.Server.OpenIdConnectServerHandler[0]
The introspection response was successfully returned: {
"error": "invalid_request"
}
在我的资源服务器中:
fail: AspNet.Security.OAuth.Introspection.OAuthIntrospectionHandler[0]
An error occurred while validating an access token: the remote server returned a BadRequest response with the following payload: Date: Sat, 21 Oct 2017 17:11:50 GMT
Server: Kestrel
{"error":"invalid_request"}.
info: AspNet.Security.OAuth.Introspection.OAuthIntrospectionHandler[7]
Bearer was not authenticated. Failure message: Authentication failed because the authorization server rejected the access token.
这是我的资源服务器 (WebApi) 的 Startup 类中的 ConfigureServices 方法:
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication().AddOAuthIntrospection(
options =>
{
options.Authority = new Uri("http://localhost:64855/");
options.Audiences.Add("resource_server");
options.ClientId = "client_id";
options.ClientSecret = "client_secret";
options.RequireHttpsMetadata = false;
});
services.AddMvc();
}
这是我在资源服务器中受 AuthorizeAttribute 控制器保护:
[Route("api/[controller]")]
[Authorize(AuthenticationSchemes = OAuthIntrospectionDefaults.AuthenticationScheme)]
public class ValuesController : Controller
{
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] {"value1", "value2"};
}
}
这是身份验证服务器中的启动类:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(
options =>
{
options.DefaultScheme = OAuthValidationDefaults.AuthenticationScheme;
})
.AddOAuthValidation(
options =>
{
options.Audiences.Add("resource_server");
});
services.AddAuthentication().AddOpenIdConnectServer(options =>
{
options.TokenEndpointPath = "/connect/token";
options.IntrospectionEndpointPath = "/connect/introspect";
options.AllowInsecureHttp = true;
options.ApplicationCanDisplayErrors = true;
options.Provider.OnValidateTokenRequest = context =>
{
if (!context.Request.IsPasswordGrantType() && !context.Request.IsRefreshTokenGrantType())
{
context.Reject(
error: OpenIdConnectConstants.Errors.UnsupportedGrantType,
description: "Only grant_type=password and refresh_token " +
"requests are accepted by this server.");
return Task.CompletedTask;
}
if (string.Equals(context.ClientId, "client_id", StringComparison.Ordinal) &&
string.Equals(context.ClientSecret, "client_secret", StringComparison.Ordinal))
{
context.Validate();
}
return Task.CompletedTask;
};
options.Provider.OnHandleTokenRequest = context =>
{
if (context.Request.IsPasswordGrantType())
{
if (!string.Equals(context.Request.Username, "Bob", StringComparison.Ordinal) ||
!string.Equals(context.Request.Password, "P@ssw0rd", StringComparison.Ordinal))
{
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidGrant,
description: "Invalid user credentials.");
return Task.CompletedTask;
}
var identity = new ClaimsIdentity(context.Scheme.Name,
OpenIdConnectConstants.Claims.Name,
OpenIdConnectConstants.Claims.Role);
identity.AddClaim(OpenIdConnectConstants.Claims.Subject, "[unique id]");
identity.AddClaim("urn:customclaim", "value",
OpenIdConnectConstants.Destinations.AccessToken,
OpenIdConnectConstants.Destinations.IdentityToken);
var ticket = new AuthenticationTicket(
new ClaimsPrincipal(identity),
new AuthenticationProperties(),
context.Scheme.Name);
ticket.SetScopes(
OpenIdConnectConstants.Scopes.Profile,
OpenIdConnectConstants.Scopes.OfflineAccess);
context.Validate(ticket);
}
return Task.CompletedTask;
};
});
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseAuthentication();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
在我看来,我在配置服务器和客户端时遗漏了一些东西,但我不明白在哪里。或者,也许我只是做错了什么。也许,我应该自己实现自省方法……不知道(我已经尝试覆盖 OpenIdServerConnectProvider 中的方法,但最终什么也没发生。
请告诉我可能是什么问题或我做错了什么。谢谢。
UPD:在所有修复之后,感谢 Pinpoint,这是我的工作解决方案: https ://github.com/mstya/Introspection.Sample 我希望它对某人有所帮助。