繁体   English   中英

使用承载令牌访问 IdentityServer4 上受保护的 API

[英]Accessing protected API on IdentityServer4 with Bearer Token

我试图寻找解决此问题的方法,但没有找到正确的搜索文本。

我的问题是,如何配置我的 IdentityServer 以便它也接受/授权带有 BearerTokens 的 Api 请求?

我配置并运行了 IdentityServer4。 我还在我的 IdentityServer 上配置了一个测试 API,如下所示:

[Authorize]
[HttpGet]
public IActionResult Get()
{
    return new JsonResult(from c in User.Claims select new { c.Type, c.Value });
}

在我的startup.cs中ConfigureServices()如下:

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 时,它总是重定向到登录页面,即使有效的不记名令牌已添加到请求标头中。

注释掉 [Authorize] 属性将正确返回响应,但当然 User.Claims 是空的。

当登录 IdentityServer(通过浏览器)然后访问 API(通过浏览器)时,它也会返回一个响应。 这一次,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")]

如果您想将默认身份验证方案设置为比策略高一级(当您有多个策略或根本没有策略时最相关):

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]标记属性,而无需使用 sceme 污染每个授权属性:

[Authorize]
public IActionResult GetFoo()
{
}

找到了更好的解决方案,在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.AddLocalApiAuthentication();

同样,你仍然需要

[Authorize(IdentityServerConstants.LocalApi.PolicyName)]

在您的控制器/方法上。 并且不要忘记添加

IdentityServerConstants.LocalApi.ScopeName

到令牌中允许的范围/请求的范围。 有关更多详细信息,请参阅 文档

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM