验证 AspNet.Security.OpenIdConnect.Server (ASP.NET vNext) 颁发的令牌
Validating Tokens Issued by AspNet.Security.OpenIdConnect.Server (ASP.NET vNext)
我正在使用 Visual Studio 2015 Enterprise 和 ASP.NET vNext Beta8 构建一个端点,该端点同时发布和使用 JWT 令牌。我最初是通过自己生成令牌来解决这个问题的,如 所述。
后来@Pinpoint 的一个有用的 透露 AspNet.Security.OpenIdConnect.Server (a.k.a.OIDC) 可以配置为为我发行和使用令牌。
所以我按照这些说明,建立了一个端点,并通过从 postman 提交 x-www-form-urlencoded post 我收到了一个合法的令牌:
{
"token_type": "bearer",
"access_token": "eyJ0eXAiO....",
"expires_in": "3599"
}
这很棒,但也是我遇到困难的地方。现在,我如何注释控制器操作以便它需要此不记名令牌?
我以为我所要做的就是用
[Authorize("Bearer")], 添加认证方案:
services.AddAuthorization
(
options =>
{
options.AddPolicy
(
JwtBearerDefaults.AuthenticationScheme,
builder =>
{
builder.
AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme).
RequireAuthenticatedUser().
Build();
}
);
}
);
然后使用 "Authorization bearer eyJ0eXAiO...." header 调用我的控制器操作,就像我在之前的示例中所做的那样。可悲的是,所有这些方法似乎都产生了一个异常:
An unhandled exception occurred while processing the request.
SocketException: No connection could be made because the target machine actively refused it 127.0.0.1:50000
WebException: Unable to connect to the remote server
HttpRequestException: An error occurred while sending the request.
IOException: IDX10804: Unable to retrieve document from: 'http://localhost:50000/.well-known/openid-configuration'.
Microsoft.IdentityModel.Logging.LogHelper.Throw(String message, Type exceptionType, EventLevel logLevel, Exception innerException)
InvalidOperationException: IDX10803: Unable to obtain configuration from: 'http://localhost:50000/.well-known/openid-configuration'. Inner Exception: 'IDX10804: Unable to retrieve document from: 'http://localhost:50000/.well-known/openid-configuration'.'.
考虑以下步骤来重现(但请不要考虑此生产价值代码):
应用 ASP.NET Beta8 工具 here
打开Visual Studio Enterprise 2015 并创建一个新的Web API ASP.NET 5 预览模板项目
改变project.json
{
"webroot": "wwwroot",
"version": "1.0.0-*",
"dependencies":{
"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”
},
"commands":{
"web": "Microsoft.AspNet.Server.Kestrel"
},
"frameworks":{
"dnx451":{}
},
"exclude": [
"wwwroot",
"node_modules"
],
"publishExclude": [
".用户",
“.vspscc
]
}
更改Startup.cs如下(这是@Pinpoint 的原创文章;我删除了评论并添加了 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();
}
}
- 更改向导 ValuesController.cs 以指定授权属性:
[Route("api/[controller]")]
public class ValuesController : Controller
{
// GET: api/values
[Authorize("Bearer")]
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
}
运行项目,使用postman获取token。要获取令牌,请使用 x-www-form-urlencoded POST 和 "grant_type" of "password"、"username" 任何东西、"password" 任何东西和 "resource" 地址API 端点。例如,我的特定 URL 是 http://localhost:37734/authorization/v1.
复制 Base64 编码的令牌,然后使用令牌通过 postman 调用向导值控制器。要使用令牌,请使用 headers Content-Type application/json 和授权持有人 eyJ0eXAiO....(您的令牌)进行 GET。我的特定 URL 是 http://localhost:37734/api/values.
观察前面提到的异常。
如果我在上面尝试的 [Authorize("Bearer")] 方法是错误的方法,如果有人可以帮助我了解如何摄取 JWT 令牌的最佳实践,我将不胜感激OIDC.
谢谢。
options.Authority
对应发行人地址(即您的OIDC服务器地址)。
http://localhost:50000/
似乎不正确,因为您稍后在问题中使用 http://localhost:37734/
。尝试修复 URL 再试一次。
我正在使用 Visual Studio 2015 Enterprise 和 ASP.NET vNext Beta8 构建一个端点,该端点同时发布和使用 JWT 令牌。我最初是通过自己生成令牌来解决这个问题的,如
所以我按照这些说明,建立了一个端点,并通过从 postman 提交 x-www-form-urlencoded post 我收到了一个合法的令牌:
{
"token_type": "bearer",
"access_token": "eyJ0eXAiO....",
"expires_in": "3599"
}
这很棒,但也是我遇到困难的地方。现在,我如何注释控制器操作以便它需要此不记名令牌?
我以为我所要做的就是用 [Authorize("Bearer")], 添加认证方案:
services.AddAuthorization
(
options =>
{
options.AddPolicy
(
JwtBearerDefaults.AuthenticationScheme,
builder =>
{
builder.
AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme).
RequireAuthenticatedUser().
Build();
}
);
}
);
然后使用 "Authorization bearer eyJ0eXAiO...." header 调用我的控制器操作,就像我在之前的示例中所做的那样。可悲的是,所有这些方法似乎都产生了一个异常:
An unhandled exception occurred while processing the request.
SocketException: No connection could be made because the target machine actively refused it 127.0.0.1:50000
WebException: Unable to connect to the remote server
HttpRequestException: An error occurred while sending the request.
IOException: IDX10804: Unable to retrieve document from: 'http://localhost:50000/.well-known/openid-configuration'. Microsoft.IdentityModel.Logging.LogHelper.Throw(String message, Type exceptionType, EventLevel logLevel, Exception innerException)
InvalidOperationException: IDX10803: Unable to obtain configuration from: 'http://localhost:50000/.well-known/openid-configuration'. Inner Exception: 'IDX10804: Unable to retrieve document from: 'http://localhost:50000/.well-known/openid-configuration'.'.
考虑以下步骤来重现(但请不要考虑此生产价值代码):
应用 ASP.NET Beta8 工具 here
打开Visual Studio Enterprise 2015 并创建一个新的Web API ASP.NET 5 预览模板项目
改变project.json
{
"webroot": "wwwroot",
"version": "1.0.0-*",
"dependencies":{
"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”
},
"commands":{
"web": "Microsoft.AspNet.Server.Kestrel"
},
"frameworks":{
"dnx451":{}
},
"exclude": [
"wwwroot",
"node_modules"
],
"publishExclude": [
".用户",
“.vspscc
]
}更改Startup.cs如下(这是@Pinpoint 的原创文章;我删除了评论并添加了 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();
}
}
- 更改向导 ValuesController.cs 以指定授权属性:
[Route("api/[controller]")]
public class ValuesController : Controller
{
// GET: api/values
[Authorize("Bearer")]
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
}
运行项目,使用postman获取token。要获取令牌,请使用 x-www-form-urlencoded POST 和 "grant_type" of "password"、"username" 任何东西、"password" 任何东西和 "resource" 地址API 端点。例如,我的特定 URL 是 http://localhost:37734/authorization/v1.
复制 Base64 编码的令牌,然后使用令牌通过 postman 调用向导值控制器。要使用令牌,请使用 headers Content-Type application/json 和授权持有人 eyJ0eXAiO....(您的令牌)进行 GET。我的特定 URL 是 http://localhost:37734/api/values.
观察前面提到的异常。
如果我在上面尝试的 [Authorize("Bearer")] 方法是错误的方法,如果有人可以帮助我了解如何摄取 JWT 令牌的最佳实践,我将不胜感激OIDC.
谢谢。
options.Authority
对应发行人地址(即您的OIDC服务器地址)。
http://localhost:50000/
似乎不正确,因为您稍后在问题中使用 http://localhost:37734/
。尝试修复 URL 再试一次。