c# - 使用 OpenId、OAuth2、Cognito、.NET Core 3.1 和 Swagger 的 Invalid_request、未授权客户端
问题描述
我正在尝试在我的 API 中添加一个身份验证层,OpenId
但是OAuth2
当我拨打电话时,在标头中传递令牌,我一直收到
Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectProtocolException:消息包含错误:'invalid_request',error_description:'unauthorized_client',error_uri:'error_uri is null'。
我已经配置AWS Cognito
了startup.cs
, 并且我可以成功地JWT token
从 Swagger 或 Postman 获得一个。
您是否看到我的startup.cs
?
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddAuthentication(c =>
{
c.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
c.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
c.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(c =>
{
c.ResponseType = Configuration["Authentication:Cognito:ResponseType"];
c.MetadataAddress = Configuration["Authentication:Cognito:MetadataAddress"];
c.ClientId = Configuration["Authentication:Cognito:ClientId"];
c.Authority = "https://auth.myauthserver.com";
c.Scope.Add("myscope");
c.GetClaimsFromUserInfoEndpoint = true;
});
// Configure named auth policies that map directly to OAuth2.0 scopes
services.AddAuthorization(c =>
{
c.AddPolicy("myscope", p => p.RequireClaim("scope", "myscope"));
});
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo
{
Title = "MyAPI", Version = "v1"
});
c.OperationFilter<AddAuthHeaderOperationFilter>();
c.AddSecurityDefinition("bearer", //Name the security scheme
new OpenApiSecurityScheme{
Flows = new OpenApiOAuthFlows()
{
ClientCredentials = new OpenApiOAuthFlow()
{
TokenUrl = new Uri("https://auth.myauthserver.com/oauth2/token"),
Scopes = new Dictionary<string, string>(){ {"myscope", "Access API"}},
AuthorizationUrl = new Uri("https://auth.myautherver.com/oauth2/authorize")
}
},
Type = SecuritySchemeType.OAuth2,
OpenIdConnectUrl = new Uri("https://cognito-idp-url.../.well-known/openid-configuration"),
BearerFormat = "JWT",
In = ParameterLocation.Header,
Scheme = "bearer"
});
c.AddSecurityRequirement(new OpenApiSecurityRequirement{
{
new OpenApiSecurityScheme{
Reference = new OpenApiReference{
Id = "Bearer",
Type = ReferenceType.SecurityScheme
},
OpenIdConnectUrl = new Uri("https://cognito-idp-url.../.well-known/openid-configuration")
},new List<string>(){"myscope"}
}
});
});
services.AddOptions();
services.AddCors(options => options.AddPolicy("CorsPolicy",
builder =>
{
builder
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials();
}));
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
app.UseDeveloperExceptionPage();
else
app.UseHsts();
app.UseCors(policy =>
policy
.SetIsOriginAllowedToAllowWildcardSubdomains()
.AllowAnyOrigin()
.SetPreflightMaxAge(TimeSpan.FromDays(1))
);
app.UseCors("CorsPolicy");
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
app.UseAuthentication();
app.UseSwagger();
app.UseSwaggerUI(c => {
c.SwaggerEndpoint($"v1/swagger.json", "MyAPI v1");
c.OAuth2RedirectUrl("https://auth.myauthserver.com/signin-oidc");
});
}
控制器上有[Authorize]
和[Produces("application/json")]
属性。
这是AddAuthHeaderOperationFilter
:
public class AddAuthHeaderOperationFilter : IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
var isAuthorized = (context.MethodInfo.DeclaringType.GetCustomAttributes(true).OfType<AuthorizeAttribute>().Any()
|| context.MethodInfo.GetCustomAttributes(true).OfType<AuthorizeAttribute>().Any())
&& !context.MethodInfo.GetCustomAttributes(true).OfType<AllowAnonymousAttribute>().Any(); // this excludes methods with AllowAnonymous attribute
if (!isAuthorized) return;
operation.Responses.TryAdd("401", new OpenApiResponse { Description = "Unauthorized" });
operation.Responses.TryAdd("403", new OpenApiResponse { Description = "Forbidden" });
var jwtbearerScheme = new OpenApiSecurityScheme
{
Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "bearer" }
};
operation.Security = new List<OpenApiSecurityRequirement>
{
new OpenApiSecurityRequirement { [jwtbearerScheme] = new string []{} }
};
}
}
这是一部分appsettings.json
:
"Authentication": {
"Cognito": {
"ClientId": "47...",
"IncludeErrorDetails": true,
"MetadataAddress": "https://cognito-idp-url.../.well-known/openid-configuration",
"RequireHttpsMetadata": false,
"ResponseType": "code",
"SaveToken": true,
"TokenValidationParameters": {
"ValidateIssuer": true
}
}
},
Cognito
配置为接受客户端凭据 OAuth 流并myscope
选择允许的身份验证范围。
这是一个卷曲的例子:
curl -X GET "https://localhost:5001/v1/MyController/2" -H "accept: application/json" -H "Authorization: Bearer eyJraWQiOiI2dGFPTW..."
谢谢
解决方案
我终于找到了我的问题的解决方案。并非所有内容都配置得很好,我将在此处留下startup.cs
与客户端凭据流一起使用并允许来自 Swagger 和 OpenAPI 的身份验证的内容。
Authentication:Cognito:Authority
在appsettings.json
as中配置"Authority": "https://cognito-idp.eu-west-1.amazonaws.com/your_region-id"
public void ConfigureServices(IServiceCollection services)
{
IdentityModelEventSource.ShowPII = true;
services.AddControllers();
Initializer.RegisterServices(services);
services.AddAuthentication(o =>
{
o.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
o.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
IssuerSigningKeyResolver = (s, securityToken, identifier, parameters) =>
{
var json = new WebClient().DownloadString(
parameters.ValidIssuer + "/.well-known/jwks.json");
var keys = JsonConvert.DeserializeObject<JsonWebKeySet>(json).Keys;
return (IEnumerable<SecurityKey>) keys;
},
ValidIssuer = Configuration["Authentication:Cognito:Authority"],
ValidateIssuerSigningKey = true,
ValidateIssuer = false,
ValidateLifetime = true,
ValidateAudience = false,
};
options.IncludeErrorDetails = true;
options.SaveToken = true;
options.Authority = Configuration["Authentication:Cognito:Authority"];
options.RequireHttpsMetadata = true;
})
.AddOpenIdConnect(options =>
{
options.Authority = Configuration["Authentication:Cognito:Authority"];
options.RequireHttpsMetadata = false;
options.ClientId = Configuration["Authentication:Cognito:ClientId"];
options.Scope.Add("myscope");
});;
services.AddAuthorization(options =>
{
options.DefaultPolicy = new AuthorizationPolicyBuilder(JwtBearerDefaults.AuthenticationScheme)
.RequireAuthenticatedUser()
.Build();
});
services.AddSwaggerGen(c =>
{
c.SwaggerDoc(ApiVersion, new OpenApiInfo
{
Title = "MyAPI", Version = "v1"
});
c.OperationFilter<AddAuthHeaderOperationFilter>();
c.AddSecurityDefinition("bearer", //Name the security scheme
new OpenApiSecurityScheme
{
Flows = new OpenApiOAuthFlows
{
ClientCredentials = new OpenApiOAuthFlow
{
TokenUrl = new Uri("https://auth.myauthserver.com/oauth2/token"),
Scopes = new Dictionary<string, string> {{"myscope", "Access API"}},
AuthorizationUrl = new Uri("https://auth.myauthserver.com/oauth2/authorize")
}
},
Type = SecuritySchemeType.OAuth2,
OpenIdConnectUrl =
new Uri(
"https://cognito-idp.eu-west-1.amazonaws.com/your_region-id/.well-known/openid-configuration"),
BearerFormat = "JWT",
In = ParameterLocation.Header,
Scheme = "bearer"
});
});
services.AddOptions();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
app.UseDeveloperExceptionPage();
else
app.UseHsts();
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
app.UseAuthentication();
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint($"{ApiVersion}/swagger.json", "MyAPI v1");
c.OAuth2RedirectUrl("https://auth.myauthserver.com/signin-oidc");
c.OAuthConfigObject = new OAuthConfigObject
{
ClientId = Configuration["Authentication:Cognito:ClientId"],
UsePkceWithAuthorizationCodeGrant = true
};
});
}
我希望它有所帮助。
推荐阅读
- highcharts - 将 Xaxis 值设置为在 highcharts 中从“00:00”开始
- keras - 如何水平合并分类模型
- api - Salesforce 商务云 Ocapi
- sap-analytics-cloud - SAC 应用程序输入“文本框”过滤器
- javascript - 使用 indexOf 来过滤数组 - ( Next.js app with typescript )
- tensorflow - 使用 Tensorflow 和 Pytorch for MobilenetV3 Small 得到完全不同的结果
- angular - 角度材料中的分页动态表
- r - r bookdown epub 表标题问题
- c# - 如何修改从使用 Json.Net 序列化数据集获得的 JSON 以用于 ESRI 地理编码
- django - 为什么在 Django 中需要子类化 AppConfig