【问题标题】:Validating Tokens Issued by AspNet.Security.OpenIdConnect.Server (ASP.NET vNext)验证 AspNet.Security.OpenIdConnect.Server (ASP.NET vNext) 颁发的令牌
【发布时间】:2016-01-28 20:51:21
【问题描述】:

我正在使用 Visual Studio 2015 Enterprise 和 ASP.NET vNext Beta8 来构建一个端点,该端点发出并使用 JWT 令牌。如here 所述,我最初是通过自己生成令牌来解决这个问题的。 后来@Pinpoint 提供的有用的article 透露,可以将 AspNet.Security.OpenIdConnect.Server(又名 OIDC)配置为为我发放和使用令牌。

所以我按照这些说明,建立了一个端点,并通过提交来自postman 的 x-www-form-urlencoded 帖子,我收到了一个合法的令牌:

{
  "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....”标题调用我的控制器操作。可悲的是,所有这些方法似乎都会产生一个异常:

处理请求时发生未处理的异常。

SocketException: 无法建立连接,因为目标机器主动拒绝了它 127.0.0.1:50000

WebException: 无法连接到远程服务器

HttpRequestException: 发送请求时出错。

IOException:IDX10804:无法从“http://localhost:50000/.well-known/openid-configuration”检索文档。 Microsoft.IdentityModel.Logging.LogHelper.Throw(String message, Type exceptionType, EventLevel logLevel, Exception innerException)

InvalidOperationException:IDX10803:无法从“http://localhost:50000/.well-known/openid-configuration”获取配置。内部异常:'IDX10804:无法从以下位置检索文档:'http://localhost:50000/.well-known/openid-configuration'。'。


考虑以下步骤来重现(但请不要考虑这个生产有价值的代码):

  • 按照here 的描述应用 ASP.NET Beta8 工具

  • 打开 Visual Studio Enterprise 2015 并创建一个新的 Web API ASP.NET 5 Preview Template 项目

  • 更改项目.json

    {
    "webroot": "wwwroot",
    “版本”:“1.0.0-*”,

    “依赖”:{
    "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"
    },

    “命令”:{
    "web": "Microsoft.AspNet.Server.Kestrel"
    },

    “框架”:{
    "dnx451": { }
    },

    “排除”:[
    “wwwroot”,
    “节点模块”
    ],
    “发布排除”:[
    ".user",
    .vspscc”
    ]
    }

  • 如下更改 Startup.cs(这是@Pinpoint 的原始文章提供的;我已删除 cmets 并添加了 AddAuthorization snip):

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();
    }
}
  • 更改 Wizarded ValuesController.cs 以指定 Authorize 属性:
[Route("api/[controller]")]
public class ValuesController : Controller
{
    // GET: api/values
    [Authorize("Bearer")] 
    [HttpGet]
    public IEnumerable<string> Get()
    {
        return new string[] { "value1", "value2" };
    }
}
  • 运行项目,并使用postman 获取令牌。要获取令牌,请使用 x-www-form-urlencoded POST,其中“grant_type”为“password”,“username”为任何内容,“password”为任何内容,“resource”为 API 端点的地址。例如,我的特定 URL 是 http://localhost:37734/authorization/v1

  • 复制 Base64 编码的令牌,然后使用令牌通过 postman 调用向导值控制器。要使用令牌,请使用标头 Content-Type application/json 和 Authorization Bearer eyJ0eXAiO....(您的令牌)进行 GET。我的特定网址是http://localhost:37734/api/values

  • 注意前面提到的异常。

如果我在上面尝试的 [Authorize("Bearer")] 方法是错误的方法,如果有人能帮助我了解如何使用 OIDC 获取 JWT 令牌的最佳实践,我将不胜感激。

谢谢。

【问题讨论】:

  • 注意:您应该考虑在发出令牌请求时删除options.TokenValidationParameters.ValidateAudience 并开始使用resource 参数,因为它可能在未来的版本中成为强制性的。只需在表单数据(JS 端)中添加 &amp;resource=http%3A%2F%2Flocalhost%3A37734%2F 即可。我已经更新了我原来的帖子来提及这一点。
  • @Pinpoint,好的,谢谢。我在发出我的令牌请求时添加了资源请求并接收到这样的令牌:{“sub”:“todo”,“iss”:“localhost:37734”,“aud”:“localhost:37734”,“exp” : 1446131180, "nbf": 1446127580 } 但是当我注释掉 options.TokenValidationParameters.ValidateAudience = false 并尝试使用令牌时,我收到“IDX10208:无法验证观众。validationParameters.ValidAudience 为空或空格和validationParameters.ValidAudiences 为空。”
  • 不要忘记将options.Audience = "http://localhost:37734/"; 添加到您的 JWT 不记名身份验证选项中;)
  • @Pinpoint,谢谢你,这就是问题所在。与此同时,这让我想到了关于 OIDC authority configuration 的下一个问题。
  • @Pinpoint,关于使用资源参数的另一个问题。我们注意到 OIDC 似乎要求 options.Audience 和资源完全相同,因此例如,即使向资源传递了缺少尾部斜杠,也会引发此异常:IDX10214: Audience validation failed .观众:'api.contoso.com'。不匹配:validationParameters.ValidAudience: 'api.contoso.com' 或 validationParameters.ValidAudiences: 'null'。有没有办法让我自己进行观众验证,或者放宽比较的严格性?

标签: asp.net jwt openid-connect aspnet-contrib


【解决方案1】:

options.Authority对应发行者地址(即你的OIDC服务器地址)。

http://localhost:50000/ 似乎不正确,因为您稍后在问题中使用了http://localhost:37734/。尝试修复 URL,然后再试一次。

【讨论】:

    猜你喜欢
    • 2016-03-31
    • 2016-10-09
    • 2016-03-15
    • 2023-03-18
    • 2016-04-30
    • 1970-01-01
    • 2019-05-02
    • 2016-06-14
    • 2013-08-07
    相关资源
    最近更新 更多