Something like AddScoped in autofac? How to fix slow response time - asp.net

I converted my application from .NET 5 to .NET 6. In the old version the response from the api was very fast. But in the new version it is very slow. The record has only 2 objects. This is my code. Please help. Thank!
In .NET 5 EF core:
namespace AspNetCoreTemplate.IoC
{
public static class NativeInjectorConfig
{
public static void RegisterServices(this IServiceCollection services)
{
services.AddScoped<ISongService, SongService>();
services.AddScoped<IUnitOfWork, UnitOfWork>();
}
}
}
In .Net 6 EF core:
public class CoreModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterGeneric(typeof(GenericRepository<>)).As(typeof(IGenericRepository<>)).InstancePerLifetimeScope();
builder.RegisterGeneric(typeof(Service<>)).As(typeof(IGenericService<>)).InstancePerLifetimeScope();
builder.RegisterType<UnitOfWork>().As<IUnitOfWork>();
var apiAssembly = Assembly.GetExecutingAssembly();
var repoAssembly = Assembly.GetAssembly(typeof(DatabaseContext));
var serviceAssembly = Assembly.GetAssembly(typeof(MapProfile));
builder.RegisterAssemblyTypes(apiAssembly, repoAssembly, serviceAssembly).Where(x => x.Name.EndsWith("Repository")).AsImplementedInterfaces().InstancePerLifetimeScope();
builder.RegisterAssemblyTypes(apiAssembly, repoAssembly, serviceAssembly).Where(x => x.Name.EndsWith("Service")).AsImplementedInterfaces().InstancePerLifetimeScope();
}
}
My response:
Program.cs
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers(options => options.Filters.Add(new ValidateFilterAttribute())).AddFluentValidation(x => x.RegisterValidatorsFromAssemblyContaining<UserLoginDtoValidator>());
builder.Services.Configure<ApiBehaviorOptions>(options =>
{
options.SuppressModelStateInvalidFilter = true;
});
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>
{
options.RequireHttpsMetadata = false;
options.SaveToken = true;
options.TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuer = true,
ValidateAudience = true,
ValidAudience = builder.Configuration["Jwt:Audience"],
ValidIssuer = builder.Configuration["Jwt:Issuer"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"]))
};
});
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddScoped(typeof(NotFoundIdFilter<>));
builder.Services.AddScoped(typeof(NotFoundUpdateFilter<>));
builder.Services.AddAutoMapper(typeof(MapProfile));
builder.Services.AddDbContext<DatabaseContext>(x =>
{
x.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection"), option =>
{
option.MigrationsAssembly(Assembly.GetAssembly(typeof(DatabaseContext)).GetName().Name);
});
});
builder.Host.UseServiceProviderFactory
(new AutofacServiceProviderFactory());
builder.Host.ConfigureContainer<ContainerBuilder>(containerBuilder => containerBuilder.RegisterModule(new CoreModule()));
var app = builder.Build();
Old repo: https://github.com/ThanhDeveloper/AspNetCoreWebApplicationTemplate/blob/faf8296e20/AspNetCoreTemplate/IoC/NativeInjectorConfig.cs
New repo: https://github.com/ThanhDeveloper/AspNetCoreWebApplicationTemplate

Related

Localizing an ASP.NET Core 6 App using RouteDataRequestCultureProvider

I am trying to localize an ASP.Net Core 6 Web Application using RouteDataRequestCultureProvider.
I have configured Program.cs file as follows
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
builder.Services.AddLocalization(options => { options.ResourcesPath = "Resources"; });
builder.Services.AddMvc().AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix, opts => { opts.ResourcesPath = "Resources"; }).AddDataAnnotationsLocalization();
var supportedCultures = new List<CultureInfo>
{
new CultureInfo("el-GR"),
new CultureInfo("en-US"),
};
var requestLocalizationOptions = new RequestLocalizationOptions
{
DefaultRequestCulture = new RequestCulture("en-US"),
SupportedCultures = supportedCultures,
SupportedUICultures = supportedCultures
};
requestLocalizationOptions.RequestCultureProviders.Clear();
RequestCultureProvider requestProvider = new RouteDataRequestCultureProvider();
requestLocalizationOptions.RequestCultureProviders.Insert(0, requestProvider);
var app = builder.Build();
app.UseRequestLocalization(requestLocalizationOptions);
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{culture}/{controller=Home}/{action=Index}/{id?}");
app.Run();
I have included the following Resource files
Resources/Views/Home/Index.el-GR.resx
Resources/Views/Home/Index.en-US.resx
I have included in Index.cshtml
#inject IViewLocalizer Localizer
and use it #Localizer["PropertyInResxFile"] in Index View file
I make the following requests
el-GR/Home/Index
en-US/Home/Index
I always get the default Culture localization (from Index.en-US.resx)
Thanks

Not receiving token when custom header is used in swagger dotnet core api

I have a dotnet core 5 API with swagger enabled.
I have added authorization in swagger api and works fine token is sent with the request.
But i have a requirement in which i need to send header value along with the request, for that purpose i have created a class:
public class SwaggerHeaderFilter : IOperationFilter {
public void Apply(OpenApiOperation operation, OperationFilterContext context) {
if (operation.Parameters == null)
operation.Parameters = new List<OpenApiParameter>();
var scheme = new OpenApiSecurityScheme { Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "bearer" } };
operation.Security.Add(new OpenApiSecurityRequirement {
[scheme] = new List<string>()
});
operation.Parameters.Add(new OpenApiParameter {
Name = "channelId",
In = ParameterLocation.Header,
Required = false // set to false if this is optional
});
}
}
And in startup.cs file i have used it like this:
services.AddSwaggerGen(c => {
c.SwaggerDoc("v1", new OpenApiInfo { Title = "API", Version = "v1" });
c.ResolveConflictingActions(apiDescriptions => apiDescriptions.First());
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme {
In = ParameterLocation.Header,
Description = "Please enter token",
Name = "Authorization",
Type = SecuritySchemeType.Http,
BearerFormat = "JWT",
Scheme = "bearer"
});
c.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type=ReferenceType.SecurityScheme,
Id="Bearer"
}
},
new string[]{}
}
});
c.OperationFilter<SwaggerHeaderFilter>();
});
But the problem is when i add custom header i am not getting anything in token

ASP.NET CORE 3.1 Custom Identity ASP.Net Issue

i am getting following error when posting data
The output of this request is
My Code in Controller and Startup class is as below
Startup Class
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IRoleDao, RoleDao>();
services.AddSingleton<IRoleDao, RoleDao>();
services.AddSingleton<IUserDao, UserDao>();
services.AddSingleton<IUserRoleDao, UserRoleDao>();
services.AddSingleton<IUserClaimsDao, UserClaimsDao>();
services.AddIdentity<AppUser, AppRole>().AddDefaultTokenProviders();
services.AddTransient<IUserStore<AppUser>, UserStore>();
services.AddTransient<IRoleStore<AppRole>, RoleStore>();
//services.AddScoped<IIdentityAccountService, AccountService>();
services.AddScoped<JwtTokenGenerator>();
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options => options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = false,
ValidateAudience = false,
ValidAudience = Configuration["Jwt:ValidAudience"],
ValidIssuer = Configuration["Jwt:ValidIssuer"],
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"]))
});
services.AddControllers(options =>
{
var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
options.Filters.Add(new AuthorizeFilter(policy));
});
services.AddAuthorization(options =>
{
options.AddPolicy("DeleteClaimPolicy", policy => policy.RequireClaim("DeleteClaim"));
options.AddPolicy("AddClaimPolicy", policy => policy.RequireClaim("CreateClaim"));
});
}
// 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();
}
app.UseRouting();
app.UseCors("CorsPolicy");
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
ControllerClass
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private readonly JwtTokenGenerator _jwtTokenGenerator;
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger, JwtTokenGenerator jwtTokenGenerator)
{
_logger = logger;
_jwtTokenGenerator = jwtTokenGenerator;
}
[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
var rng = new Random();
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
})
.ToArray();
}
[AllowAnonymous]
[HttpGet("login")]
[ProducesResponseType(typeof(Result), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(typeof(Result), StatusCodes.Status500InternalServerError)]
public string Login()
{
string token = _jwtTokenGenerator.CreateUserToken("Test");
return token;
}
[HttpPost("create")]
[Authorize(Policy = "AddClaimPolicy")]
[ProducesResponseType(typeof(Result), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(typeof(Result), StatusCodes.Status500InternalServerError)]
public string CreateClaim()
{
return "Created Claim";
}
[HttpDelete("delete")]
[Authorize(Policy = "DeleteClaimPolicy")]
[ProducesResponseType(typeof(Result), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(typeof(Result), StatusCodes.Status500InternalServerError)]
public string DeleteClaim()
{
return "Deleted Claim";
}
}
However the when i comment the following line of code in ConfigureServices Method of Startup class
services.AddIdentity<AppUser, AppRole>().AddDefaultTokenProviders();
services.AddTransient<IUserStore<AppUser>, UserStore>();
services.AddTransient<IRoleStore<AppRole>, RoleStore>();
I get the desired output
On Closer observation, A second request to login is been called.
Please note that i am using custom implementation
GET /Account/Login?ReturnUrl=%2Fweatherforecast%2Fcreate HTTP/1.1
Can someone please correct me if i am missing something.
The above is solved, just changed
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options => options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = false,
ValidateAudience = false,
ValidAudience = Configuration["Jwt:ValidAudience"],
ValidIssuer = Configuration["Jwt:ValidIssuer"],
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"]))
});
to
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options => options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = false,
ValidateAudience = false,
ValidAudience = Configuration["Jwt:ValidAudience"],
ValidIssuer = Configuration["Jwt:ValidIssuer"],
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"]))
});
The parameter x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
is required to avoid redirection to Login
**> GET /Account/Login?ReturnUrl=%2Fapi%2FLSPAccount%2Frole%2Fcreate HTTP/1.1
Host: localhost:9000
User-Agent: insomnia/6.6.2
Content-Type: application/json
Accept: /**

Constantly get invalid scope error after udating my identityserver4

I had identityProviderService working with my API and web app, then I updated i updated my dependecies(identityServer4) and that resulted constantly in the following error either I use code or I hybrid.
IdentityServer4 Error: Invalid_scope
I checked the log and the scope was fine but I can resolve why I keep getting this error! The details as follows:
My local Idp (Identityserver4) log and the main error =>
IdentityServer4.Hosting.IdentityServerMiddleware: Information:
Invoking IdentityServer endpoint:
IdentityServer4.Endpoints.AuthorizeEndpoint for /connect/authorize
IdentityServer4.Validation.DefaultResourceValidator: Error: Scope
Bd.Web.Api not found in store.
IdentityServer4.Endpoints.AuthorizeEndpoint: Error: Request validation
failed IdentityServer4.Endpoints.AuthorizeEndpoint: Information: {
"ClientId": "BdWebAppClientId", "ClientName": "Bd web Client
Application", "RedirectUri": "https://localhost:xxxxx/signin-oidc",
"AllowedRedirectUris": [
"https://localhost:44386/signin-oidc" ], "SubjectId": "anonymous", "ResponseType": "code", "ResponseMode": "form_post",
"GrantType": "authorization_code", "RequestedScopes": "openid
profile Bd.Web.Api", "State":
"CfDJ8Foioa24zShFmzIFmkTbGBTrbiiEwQYmHGMRUN7FwsfKMgY2-olWJA1XVlAkA0uCWIR6HhMdu2X1exzVKTNFTcAD456Z0r3es5ki377uBEJgjA9jmyQFWWzTZV6_7GEmIC39xUh_b_YAqXgtzO0olZ52beNFuxruk_NshL47NhwcaETCH2cy3XTvRN0NTxZHmxVWglo13iSE7RVpNghHc7pBW7jCv7cB2RldQnEvsJ4s56AdiICw9sdKEJ5mQNoXngshanycX4MmD3qaW0TX6knY43pAqMuPgEEVqd7BXKt_koQfiQuAP3pQNbsyOAb1jtoZ8egUHiKgXjofs8ci2i4",
"PromptMode": "", "Raw": {
"client_id": "BdWebAppClientId",
"redirect_uri": "https://localhost:xxxxx/signin-oidc",
"response_type": "code",
"scope": "openid profile Bd.Web.Api",
"response_mode": "form_post",
"nonce": "637284460180108591.ZjIxYjhlZGEtYjk0Mi00M2UxLWExNWItOGYzMjhjODEyMGQzZmU5NjZmZDAtOTQwYi00YTFlLWJlMWUtM2U3YzBhM2NmNjQ4",
"state": "CfDJ8Foioa24zShFmzIFmkTbGBTrbiiEwQYmHGMRUN7FwsfKMgY2-olWJA1XVlAkA0uCWIR6HhMdu2X1exzVKTNFTcAD456Z0r3es5ki377uBEJgjA9jmyQFWWzTZV6_7GEmIC39xUh_b_YAqXgtzO0olZ52beNFuxruk_NshL47NhwcaETCH2cy3XTvRN0NTxZHmxVWglo13iSE7RVpNghHc7pBW7jCv7cB2RldQnEvsJ4s56AdiICw9sdKEJ5mQNoXngshanycX4MmD3qaW0TX6knY43pAqMuPgEEVqd7BXKt_koQfiQuAP3pQNbsyOAb1jtoZ8egUHiKgXjofs8ci2i4",
"x-client-SKU": "ID_NETSTANDARD2_0",
"x-client-ver": "5.5.0.0" }
My config comprises of three classes User, Resources and Client as follows:
public class Users
{
public static List<TestUser> Get()
{
return new List<TestUser> {
new TestUser {
SubjectId = "5BE86359-073C-434B-AD2D-A3932222DABE",
Username = "scott",
Password = "password",
Claims = new List<Claim> {
new Claim(JwtClaimTypes.Email, "scott#scottbrady91.com"),
new Claim(JwtClaimTypes.Role, "admin")
}
}
};
}
}
public class Resources
{
public static IEnumerable<IdentityResource> Ids()
{
return new List<IdentityResource>
{
new IdentityResources.OpenId(),
new IdentityResources.Profile(),
new IdentityResources.Address()
};
}
public static IEnumerable<ApiResource> Apis()
{
return new List<ApiResource>
{
new ApiResource("Bd.Web.Api", "Bd Web Api") {
Description = "BD API Access",
//UserClaims = new List<string> {"role"},
ApiSecrets = new List<Secret> {new Secret("secret".Sha256())}
}
};
}
}
public class Clients
{
public static IEnumerable<Client> Get()
{
return new List<Client> {
new Client {
ClientId = "BdWebAppClientId",
ClientName = "Bd web Client Application",
AllowedGrantTypes = GrantTypes.Code,
RequirePkce = false,
ClientSecrets = new List<Secret> {
new Secret("secret".Sha256())},
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.Address,
"Bd.Web.Api"
},
RedirectUris = new List<string>{"https://localhost:44386/signin-oidc"},
PostLogoutRedirectUris = new List<string>{ "https://localhost:44386/sigout-callback-oidc" }
}
};
}
}
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddIdentityServer()
.AddInMemoryClients(Clients.Get())
.AddInMemoryIdentityResources(Resources.Ids())
.AddInMemoryApiResources(Resources.Apis())
.AddTestUsers(Users.Get())
.AddDeveloperSigningCredential();
}
// 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();
}
app.UseRouting();
app.UseIdentityServer();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
//endpoints.MapGet("/", async context =>
//{
// await context.Response.WriteAsync("Hello World!");
//});
});
}
}
My web app startup as follows:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
}
public IConfiguration Configuration { get; }
services.Configure<CookiePolicyOptions>(options =>
{
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = Microsoft.AspNetCore.Http.SameSiteMode.None;
});
services.AddMvc(options => { options.EnableEndpointRouting = false; }).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
JsonConvert.DefaultSettings = () => new JsonSerializerSettings
{
Formatting = Formatting.Indented,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
};
services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());
services.AddHttpContextAccessor();
services.AddTransient<BearerTokenHandler>();
services.AddHttpClient("ApiClient", client =>
{
//client.BaseAddress = new Uri("https://bandapi.azurewebsites.net/api/");
client.BaseAddress = new Uri("https://localhost:44301/api/");
//client.BaseAddress = new Uri("https://192.168.1.25:44301/api/");
client.Timeout = new TimeSpan(0, 0, 30);
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Add(HeaderNames.Accept, "application/json");
}).AddHttpMessageHandler<BearerTokenHandler>();
services.AddHttpClient("IdpClient", client =>
{
client.BaseAddress = new Uri("https://localhost:xxxxx/");
client.Timeout = new TimeSpan(0, 0, 30);
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Add(HeaderNames.Accept, "application/json");
}).AddHttpMessageHandler<BearerTokenHandler>();
services.AddAuthentication(options =>
{
options.DefaultScheme = "BdWebAppCookies";
options.DefaultChallengeScheme = "oidc";
//options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
//options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie("BdWebAppCookies" /*CookieAuthenticationDefaults.AuthenticationScheme*/, options =>
{
options.AccessDeniedPath = "/Authentication/AccessDenied";
})
.AddOpenIdConnect("oidc" /*OpenIdConnectDefaults.AuthenticationScheme*/, options =>
{
options.Authority = "https://localhost:xxxx/";
//options.RequireHttpsMetadata = true;
options.ClientId = "BdWebAppClientId";
options.Scope.Add("openid");
options.Scope.Add("profile");
options.Scope.Add("address");
options.Scope.Add("Bd.Web.Api");
options.ClientSecret = "secret";
options.ResponseType = "code";
options.UsePkce = false;
options.SignInScheme = "BdWebAppCookies";
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseAuthentication();
app.UseAuthorization();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
In IdentityServer4 4.x the handling of api scopes was changed. Now you need to define all available api scopes and provide them to the configuration.
The updated documentation shows how it's done. https://identityserver4.readthedocs.io/en/latest/topics/resources.html#scopes
public static IEnumerable<ApiScope> GetApiScopes()
{
return new List<ApiScope>
{
new ApiScope(name: "read", displayName: "Read your data."),
new ApiScope(name: "write", displayName: "Write your data."),
new ApiScope(name: "delete", displayName: "Delete your data.")
};
}
Then add the scopes to your IdentityServer configuration:
services.AddIdentityServer()
.AddInMemoryApiScopes(Config.GetApiScopes());
Furthermore you need to add the scopes to your already defined ApiResources as described here: https://identityserver4.readthedocs.io/en/latest/topics/resources.html#api-resources
public static readonly IEnumerable<ApiResource> GetApiResources()
{
return new List<ApiResource>
{
new ApiResource("invoices", "Invoice API")
{
Scopes = { "invoice.read", "invoice.pay", "manage" }
},
new ApiResource("customers", "Customer API")
{
Scopes = { "customer.read", "customer.contact", "manage" }
}
};
}
I was had the same problem after updating to .NET Core 3.1 and IndentityServer4 V4.0.0. Only way I could get it to work is to remove the scope parameter on the client API request, using Angular 9 with angular-oauth2-oidc V9.2.1
const header = new HttpHeaders({ 'Content-Type': 'application/x-www-form-urlencoded' });
const params = new HttpParams()
.append('username', userName)
.append('password', password)
.append('client_id', this.clientId)
.append('grant_type', 'password');
this.oauthService.issuer = this.baseUrl;
return from(this.oauthService.loadDiscoveryDocument())
.pipe(mergeMap(() => {
return this.http.post(this.oauthService.tokenEndpoint, params, { headers: header });
}));
This is NOT the way to do this, if you remove the scope then none of the profile information will be returned.

MVC 6 UseOAuthBearerAuthentication

In MVC 6 RCP 6 using Microsoft.AspNet.Security I was able to use a custom SecurityTokenValidator.
In RC Microsoft.AspNet.Security didn't exist in Beta4 so I changed my code to use Microsoft.AspNet.Authentication see below: (Compiles and runs but SecurityTokenValidator never fires.
services.Configure<ExternalAuthenticationOptions>(options =>
{
options.SignInScheme = OAuthBearerAuthenticationDefaults.AuthenticationScheme;
});
app.UseOAuthBearerAuthentication(options =>
{
options.TokenValidationParameters.ValidateAudience = true;
options.TokenValidationParameters.ValidateIssuer = true;
options.TokenValidationParameters.RequireSignedTokens = false;
options.AuthenticationScheme = OAuthBearerAuthenticationDefaults.AuthenticationScheme;
options.AutomaticAuthentication = true;
options.SecurityTokenValidators = new List<ISecurityTokenValidator> { validator };
});
Replace the app.UseOAuthBearerAuthentication code with
app.UseMiddleware<OAuthBearerAuthenticationMiddleware>(new ConfigureOptions<OAuthBearerAuthenticationOptions>(options =>
{
options.AutomaticAuthentication = true;
options.SecurityTokenValidators = new List<ISecurityTokenValidator> { validator };
}));
You got it?
Today occours that CustomSecurityValidationToken not fires because inner exception was throw (a inner validation occurs based in params in my case).
Try to debug Notifications and if it fires 'AuthenticationFailed', you will find in 'context' variable a Property named 'Exception' if any.
app.UseOAuthBearerAuthentication(bearer =>
{
bearer.SecurityTokenValidators = new List<ISecurityTokenValidator>() { new CustomSecurityValidationToken() };
bearer.AutomaticAuthentication = true;
bearer.Notifications = new OAuthBearerAuthenticationNotifications()
{
SecurityTokenReceived = context =>
{
return Task.FromResult(0);
},
MessageReceived = context =>
{
return Task.FromResult(0);
},
SecurityTokenValidated = context =>
{
return Task.FromResult(0);
},
AuthenticationFailed = context =>
{
context.Response.Redirect("Home/Error?message=" + context.Exception.Message);
return Task.FromResult(0);
}
};
});

Resources