我正在尝试使用OpenId
和OAuth2
在我的 API 中添加身份验证层,但是当我进行调用时,在标头中传递令牌,我不断收到
Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectProtocolException:消息包含错误:"invalid_request",error_description:"unauthorized_client",error_uri:"error_uri为空"。
我已经配置了AWS Cognito
,startup.cs
,我可以成功地从Swagger或Postman获得JWT token
。
您是否看到我的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..."
谢谢
我终于找到了我的问题的解决方案。并非所有内容都配置良好,我将在此处保留与客户端凭据流一起使用并允许从 Swagger 和 OpenAPI 进行身份验证的startup.cs
。
Authentication:Cognito:Authority
在appsettings.json
中配置为"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
};
});
}
我希望它有所帮助。