使用 Bearer Token 在 IdentityServer4 上访问受保护的 API
Accessing protected API on IdentityServer4 with Bearer Token
我已尝试搜索此问题的解决方案,但未找到正确的搜索文本。
我的问题是,如何配置我的 IdentityServer 以便它也可以 accept/authorize Api 使用 BearerTokens 请求?
我配置了 IdentityServer4 并且 运行。
我还在我的 IdentityServer 上配置了一个测试 API,如下所示:
[Authorize]
[HttpGet]
public IActionResult Get()
{
return new JsonResult(from c in User.Claims select new { c.Type, c.Value });
}
在我的startup.csConfigureServices()中是这样的:
public IServiceProvider ConfigureServices(IServiceCollection services)
{
...
// configure identity server with stores, keys, clients and scopes
services.AddIdentityServer()
.AddCertificateFromStore(Configuration.GetSection("AuthorizationSettings"), loggerFactory.CreateLogger("Startup.ConfigureServices.AddCertificateFromStore"))
// this adds the config data from DB (clients, resources)
.AddConfigurationStore(options =>
{
options.DefaultSchema = "auth";
options.ConfigureDbContext = builder =>
{
builder.UseSqlServer(databaseSettings.MsSqlConnString,
sql => sql.MigrationsAssembly(migrationsAssembly));
};
})
// this adds the operational data from DB (codes, tokens, consents)
.AddOperationalStore(options =>
{
options.DefaultSchema = "auth";
options.ConfigureDbContext = builder =>
builder.UseSqlServer(databaseSettings.MsSqlConnString,
sql => sql.MigrationsAssembly(migrationsAssembly));
// this enables automatic token cleanup. this is optional.
options.EnableTokenCleanup = true;
options.TokenCleanupInterval = 30;
})
// this uses Asp Net Identity for user stores
.AddAspNetIdentity<ApplicationUser>()
.AddProfileService<AppProfileService>()
;
services.AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)
.AddIdentityServerAuthentication(options =>
{
options.Authority = authSettings.AuthorityUrl;
options.RequireHttpsMetadata = authSettings.RequireHttpsMetadata;
options.ApiName = authSettings.ResourceName;
})
和Configure()如下:
// NOTE: 'UseAuthentication' is not needed, since 'UseIdentityServer' adds the authentication middleware
// app.UseAuthentication();
app.UseIdentityServer();
我有一个客户端配置为允许隐式授权类型,并将配置的 ApiName 作为 AllowedScopes 之一包含在内:
new Client
{
ClientId = "47DBAA4D-FADD-4FAD-AC76-B2267ECB7850",
ClientName = "MyTest.Web",
AllowedGrantTypes = GrantTypes.Implicit,
RequireConsent = false,
RedirectUris = { "http://localhost:6200/assets/oidc-login-redirect.html", "http://localhost:6200/assets/silent-redirect.html" },
PostLogoutRedirectUris = { "http://localhost:6200/?postLogout=true" },
AllowedCorsOrigins = { "http://localhost:6200" },
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.Email,
"dev.api",
"dev.auth" // <- ApiName for IdentityServer authorization
},
AllowAccessTokensViaBrowser = true,
AllowOfflineAccess = true,
AccessTokenLifetime = 18000,
},
当我使用 Postman 访问受保护的 API 但它总是重定向到登录页面,即使已将有效的 Bearer Token 添加到请求 header.
注释掉 [Authorize] 属性将正确 return 一个响应,但是 User.Claims 当然是空的。
当登录到 IdentityServer(通过浏览器)然后访问 API(通过浏览器)时,它也会 return 一个响应。这一次,User.Claims可用。
有一个示例在 IdentityServer 中共同托管受保护的 API:IdentityServerAndApi
我将他们的初创公司与您的初创公司进行快速比较,他们调用的是 AddJwtBearer
而不是 AddIdentityServerAuthentication
:
services.AddAuthentication()
.AddJwtBearer(jwt => {
jwt.Authority = "http://localhost:5000";
jwt.RequireHttpsMetadata = false;
jwt.Audience = "api1";
});
Authorize
属性还设置身份验证方案:
[Authorize(AuthenticationSchemes = "Bearer")]
找到更好的解决方案,配置在Startup.cs:
services.AddAuthentication()
.AddLocalApi();
services.AddAuthorization(options =>
{
options.AddPolicy(IdentityServerConstants.LocalApi.PolicyName, policy =>
{
policy.AddAuthenticationSchemes(IdentityServerConstants.LocalApi.AuthenticationScheme);
policy.RequireAuthenticatedUser();
});
});
并在控制器中使用:
[Authorize(IdentityServerConstants.LocalApi.PolicyName)]
public class UserInfoController : Controller
{
...
}
如果您想将默认身份验证方案设置为比策略高一级(当您有多个策略或根本没有策略时最相关):
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(o =>
{
o.Authority = "http://localhost:5000";
o.RequireHttpsMetadata = false;
o.Audience = "api1";
});
然后您可以简单地使用控制器方法上方的 [Authorize]
标记属性,而不会用场景污染每个授权属性:
[Authorize]
public IActionResult GetFoo()
{
}
或者更简单:
services.AddLocalApiAuthentication();
同样,您还需要
[Authorize(IdentityServerConstants.LocalApi.PolicyName)]
在你的 controller/method 上。并且不要忘记添加
IdentityServerConstants.LocalApi.ScopeName
到令牌中允许的 scopes/requested 个。
有关详细信息,请参阅 docs。
我已尝试搜索此问题的解决方案,但未找到正确的搜索文本。
我的问题是,如何配置我的 IdentityServer 以便它也可以 accept/authorize Api 使用 BearerTokens 请求?
我配置了 IdentityServer4 并且 运行。 我还在我的 IdentityServer 上配置了一个测试 API,如下所示:
[Authorize]
[HttpGet]
public IActionResult Get()
{
return new JsonResult(from c in User.Claims select new { c.Type, c.Value });
}
在我的startup.csConfigureServices()中是这样的:
public IServiceProvider ConfigureServices(IServiceCollection services)
{
...
// configure identity server with stores, keys, clients and scopes
services.AddIdentityServer()
.AddCertificateFromStore(Configuration.GetSection("AuthorizationSettings"), loggerFactory.CreateLogger("Startup.ConfigureServices.AddCertificateFromStore"))
// this adds the config data from DB (clients, resources)
.AddConfigurationStore(options =>
{
options.DefaultSchema = "auth";
options.ConfigureDbContext = builder =>
{
builder.UseSqlServer(databaseSettings.MsSqlConnString,
sql => sql.MigrationsAssembly(migrationsAssembly));
};
})
// this adds the operational data from DB (codes, tokens, consents)
.AddOperationalStore(options =>
{
options.DefaultSchema = "auth";
options.ConfigureDbContext = builder =>
builder.UseSqlServer(databaseSettings.MsSqlConnString,
sql => sql.MigrationsAssembly(migrationsAssembly));
// this enables automatic token cleanup. this is optional.
options.EnableTokenCleanup = true;
options.TokenCleanupInterval = 30;
})
// this uses Asp Net Identity for user stores
.AddAspNetIdentity<ApplicationUser>()
.AddProfileService<AppProfileService>()
;
services.AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)
.AddIdentityServerAuthentication(options =>
{
options.Authority = authSettings.AuthorityUrl;
options.RequireHttpsMetadata = authSettings.RequireHttpsMetadata;
options.ApiName = authSettings.ResourceName;
})
和Configure()如下:
// NOTE: 'UseAuthentication' is not needed, since 'UseIdentityServer' adds the authentication middleware
// app.UseAuthentication();
app.UseIdentityServer();
我有一个客户端配置为允许隐式授权类型,并将配置的 ApiName 作为 AllowedScopes 之一包含在内:
new Client
{
ClientId = "47DBAA4D-FADD-4FAD-AC76-B2267ECB7850",
ClientName = "MyTest.Web",
AllowedGrantTypes = GrantTypes.Implicit,
RequireConsent = false,
RedirectUris = { "http://localhost:6200/assets/oidc-login-redirect.html", "http://localhost:6200/assets/silent-redirect.html" },
PostLogoutRedirectUris = { "http://localhost:6200/?postLogout=true" },
AllowedCorsOrigins = { "http://localhost:6200" },
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.Email,
"dev.api",
"dev.auth" // <- ApiName for IdentityServer authorization
},
AllowAccessTokensViaBrowser = true,
AllowOfflineAccess = true,
AccessTokenLifetime = 18000,
},
当我使用 Postman 访问受保护的 API 但它总是重定向到登录页面,即使已将有效的 Bearer Token 添加到请求 header.
注释掉 [Authorize] 属性将正确 return 一个响应,但是 User.Claims 当然是空的。
当登录到 IdentityServer(通过浏览器)然后访问 API(通过浏览器)时,它也会 return 一个响应。这一次,User.Claims可用。
有一个示例在 IdentityServer 中共同托管受保护的 API:IdentityServerAndApi
我将他们的初创公司与您的初创公司进行快速比较,他们调用的是 AddJwtBearer
而不是 AddIdentityServerAuthentication
:
services.AddAuthentication()
.AddJwtBearer(jwt => {
jwt.Authority = "http://localhost:5000";
jwt.RequireHttpsMetadata = false;
jwt.Audience = "api1";
});
Authorize
属性还设置身份验证方案:
[Authorize(AuthenticationSchemes = "Bearer")]
找到更好的解决方案,配置在Startup.cs:
services.AddAuthentication()
.AddLocalApi();
services.AddAuthorization(options =>
{
options.AddPolicy(IdentityServerConstants.LocalApi.PolicyName, policy =>
{
policy.AddAuthenticationSchemes(IdentityServerConstants.LocalApi.AuthenticationScheme);
policy.RequireAuthenticatedUser();
});
});
并在控制器中使用:
[Authorize(IdentityServerConstants.LocalApi.PolicyName)]
public class UserInfoController : Controller
{
...
}
如果您想将默认身份验证方案设置为比策略高一级(当您有多个策略或根本没有策略时最相关):
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(o =>
{
o.Authority = "http://localhost:5000";
o.RequireHttpsMetadata = false;
o.Audience = "api1";
});
然后您可以简单地使用控制器方法上方的 [Authorize]
标记属性,而不会用场景污染每个授权属性:
[Authorize]
public IActionResult GetFoo()
{
}
或者更简单:
services.AddLocalApiAuthentication();
同样,您还需要
[Authorize(IdentityServerConstants.LocalApi.PolicyName)]
在你的 controller/method 上。并且不要忘记添加
IdentityServerConstants.LocalApi.ScopeName
到令牌中允许的 scopes/requested 个。 有关详细信息,请参阅 docs。