【问题标题】:Separating Auth and Resource Servers with AspNet.Security.OpenIdConnect - the Audience?使用 AspNet.Security.OpenIdConnect 分离身份验证和资源服务器 - 受众?
【发布时间】:2015-12-24 05:37:32
【问题描述】:

AspNet.Security.OpenIdConnect.Server 上的示例在我看来既是身份验证服务器又是资源服务器。我想把它们分开。我已经这样做了。

在身份验证服务器的 Startup.Config 中,我有以下设置:

app.UseOpenIdConnectServer(options => {

    options.AllowInsecureHttp = true;
    options.ApplicationCanDisplayErrors = true;
    options.AuthenticationScheme = OpenIdConnectDefaults.AuthenticationScheme;
    options.Issuer = new System.Uri("http://localhost:61854"); // This auth server
    options.Provider = new AuthorizationProvider();
    options.TokenEndpointPath = new PathString("/token");              
    options.UseCertificate(new X509Certificate2(env.ApplicationBasePath + "\\mycertificate.pfx","mycertificate"));

});

我写了一个 AuthorizationProvider,但我认为它与我当前的问题无关(但可能相关)。在它的 GrantResourceOwnerCredentials 覆盖中,我硬编码了一个声明主体,以便它验证每个令牌请求:

public override Task GrantResourceOwnerCredentials(GrantResourceOwnerCredentialsNotification context)
{
    var identity = new ClaimsIdentity(OpenIdConnectDefaults.AuthenticationScheme);

    identity.AddClaim(ClaimTypes.Name, "me");
    identity.AddClaim(ClaimTypes.Email, "me@gmail.com");
    var claimsPrincipal = new ClaimsPrincipal(identity);

    context.Validated(claimsPrincipal);
    return Task.FromResult<object>(null);
}

在资源服务器,我的 Startup.config 中有以下内容:

app.UseWhen(context => context.Request.Path.StartsWithSegments(new PathString("/api")), branch =>
{
    branch.UseOAuthBearerAuthentication(options => {
        options.Audience = "http://localhost:54408"; // This resource server, I believe.
        options.Authority = "http://localhost:61854"; // The auth server
        options.AutomaticAuthentication = true;               
    });
});

在 Fiddler 上,我要一个令牌,我得到一个:

POST /token HTTP/1.1
Host: localhost:61854
Content-Type: application/x-www-form-urlencoded

username=admin&password=aaa000&grant_type=password

所以现在我使用该访问令牌从资源服务器访问受保护的资源:

GET /api/values HTTP/1.1
Host: localhost:54408
Content-Type: application/json;charset=utf-8
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI.....

我现在收到此错误 - 观众验证失败。观众:“空”。不匹配 validationParameters.ValidAudience: 'http://localhost:54408' 或 validationParameters.ValidAudiences: 'null'。

我认为原因是因为我从未在身份验证服务器上设置受众(在 app.UseOpenIdConnectServer(...)),所以我认为它没有将受众信息写入令牌。所以我需要在身份验证服务器上设置一个受众(就像在 IdentityServer3 中所做的那样),但是我在选项对象上找不到可以让我这样做的属性。

AspNet.Security.OpenIdConnect.Server 是否要求身份验证和资源位于同一服务器中?

在将 ClaimsPrincipal 放在一起时是否已设置受众,如果是,如何设置?

是否需要编写自定义受众验证器并将其连接到系统? (我当然希望答案是否定的。)

【问题讨论】:

    标签: asp.net-web-api oauth asp.net-core openid-connect aspnet-contrib


    【解决方案1】:

    AspNet.Security.OpenIdConnect.Server 是否要求身份验证和资源位于同一服务器中?

    不,你当然可以将这两个角色分开。

    正如您已经知道的那样,如果您没有明确指定它,授权服务器无法确定访问令牌的目标/受众,该令牌在没有 aud 声明的情况下发出,默认情况下需要OAuth2 不记名中间件。

    解决这个问题很简单:只需在创建身份验证票证时调用ticket.SetResources(resources),授权服务器就会确切知道它应该在aud 声明中添加哪个值(即资源服务器/API) .

    app.UseOpenIdConnectServer(options =>
    {
        // Force the OpenID Connect server middleware to use JWT tokens
        // instead of the default opaque/encrypted token format used by default.
        options.AccessTokenHandler = new JwtSecurityTokenHandler();
    });
    
    public override Task HandleTokenRequest(HandleTokenRequestContext context)
    {
        if (context.Request.IsPasswordGrantType())
        {
            var identity = new ClaimsIdentity(context.Options.AuthenticationScheme);
            identity.AddClaim(OpenIdConnectConstants.Claims.Subject, "unique identifier");
    
            var ticket = new AuthenticationTicket(
                new ClaimsPrincipal(identity),
                new AuthenticationProperties(),
                context.Options.AuthenticationScheme);
    
            // Call SetResources with the list of resource servers
            // the access token should be issued for.
            ticket.SetResources("resource_server_1");
    
            // Call SetScopes with the list of scopes you want to grant.
            ticket.SetScopes("profile", "offline_access");
    
            context.Validate(ticket);
        }
    
        return Task.FromResult(0);
    }     
    
    app.UseJwtBearerAuthentication(new JwtBearerOptions
    {
        AutomaticAuthenticate = true,
        AutomaticChallenge = true,
        Audience = "resource_server_1",
        Authority = "http://localhost:61854"
    });
    

    【讨论】:

    • 非常感谢!现在可以了!我使用了选项 1,因为我可能有多个观众能够请求访问令牌。
    • @MickaelCaruso 我更新了我的答案以使用ticket.SetResources,因为在下一个测试版中将不再原生支持resource 参数(有关更多信息,请参阅github.com/aspnet-contrib/AspNet.Security.OpenIdConnect.Server/…)。我们还将停止使用 JWT 作为访问令牌的默认格式:github.com/aspnet-contrib/AspNet.Security.OpenIdConnect.Server/…
    • 感谢您的回答,这对我很有帮助。我的 GrantResourceOwnerCredentials 方法几乎相同,但我还添加了 identity.AddClaim(ClaimTypes.Name, "MyFullName");但是当我在我的 web api 控制器中调用 User.GetUserName() 时,我得到 NULL? User.GetUserId() 返回在 NameIdentifier 声明中传递的内容。如何让 User.GetUserName 返回数据?
    • @partyelite 不要忘记设置目的地:stackoverflow.com/questions/33797838/… ;)
    • 更新为使用 ASOS beta5 中引入的新语法(适用于 ASP.NET Core RC2)。
    猜你喜欢
    • 1970-01-01
    • 2020-11-12
    • 1970-01-01
    • 1970-01-01
    • 2021-10-16
    • 2020-05-07
    • 2017-07-08
    • 2017-05-25
    相关资源
    最近更新 更多