Configure IdentityServerJwt Authentication with Authorization - c#

I have an Blazor webassembly application which uses IdentityServerJwt AddAuthentication and is working with Hangfire. I am trying to configure Hangfire to allow only users who are admins authorization based on the article here but I am getting an No authentication handler is registered for the scheme 'Bearer' error. What should I add as an AuthenticationSchemes. JwtBearerDefaults.AuthenticationScheme` does not work.
What am I missing?
public partial class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
string handfirepolicyname="HangfirePolicyName";
public void ConfigureServices(IServiceCollection services)
{
...Code removed for brevity
services.AddAuthentication().AddIdentityServerJwt();
services.AddAuthorization(options =>
{
options.AddPolicy(handfirepolicyname, builder =>
{ builder.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme).RequireAuthenticatedUser();
builder.RequireRole("admin");
});
});
var hangfireConnectionstring = "SomeHangfireDatabaseConnectionString";
var mySqlStorageOptions = new MySqlStorageOptions();
var mySqlStorage = new MySqlStorage(hangfireConnectionstring, mySqlStorageOptions);
services.AddHangfire(config => config.UseStorage(mySqlStorage));
services.AddHangfireServer();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ApplicationIdentityDbContext identityDbContext)
{
...Code removed for brevity
app.UseIdentityServer();
app.UseAuthentication();
app.UseAuthorization();
//UseAuthentication, UseAuthorization should be before UseHangfireDashboard
app.UseHangfireDashboard();
app.UseEndpoints(endpoints =>
{
endpoints.MapHangfireDashboard("/hangfire", new DashboardOptions()
{
Authorization = new List<IDashboardAuthorizationFilter> { }
}).RequireAuthorization(handfirepolicyname);
});
}
Error:
No authentication handler is registered for the scheme 'Bearer'. The registered schemes are: Identity.Application, Identity.External, Identity.TwoFactorRememberMe, Identity.TwoFactorUserId, idsrv, idsrv.external, IdentityServerJwt, IdentityServerJwtBearer. Did you forget to call AddAuthentication().Add[SomeAuthHandler]("Bearer",...)?

by adding
[Authorize(AuthenticationSchemes = "Bearer")]
public class TestController : ControllerBase{}
on top of the controller

Related

Getting Null from value using IOptionSnapshot<T>

I'm trying to implement Azure App Configuration to my Application that uses the ASP.NET Boilerplate Framework. I'm following this tutorial but when I try to access my settings everything comes null. When the Startup.cs get executed I can see the values in the constructor but when I try to get them else where I get the null.
Program.cs:
public class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args)
{
return WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((config) =>
{
// Retrieve the connection string
IConfiguration settings = config.Build();
string connectionString = settings.GetConnectionString("AppConfig");
// Load configuration from Azure App Configuration
config.AddAzureAppConfiguration(options =>
{
options.Connect(connectionString)
// Load all keys that start with `TestApp:` and have no label
.Select("TestApp:*", LabelFilter.Null)
// Configure to reload configuration if the registered sentinel key is modified
.ConfigureRefresh(refreshOptions => refreshOptions.Register("TestApp:Settings:Sentinel", refreshAll: true));
}).Build();
})
.UseStartup<Startup>()
.Build();
}
}
Startup.cs:
public class Startup
{
private const string _defaultCorsPolicyName = "localhost";
private const string _apiVersion = "v1";
public IConfigurationRoot _appConfiguration;
public IConfiguration Configuration { get; }
public Startup(IWebHostEnvironment env, IConfiguration configuration)
{
_appConfiguration = env.GetAppConfiguration();
Configuration = configuration; //Azure App Configuration
}
public IServiceProvider ConfigureServices(IServiceCollection services)
{
//MVC
services.AddControllersWithViews(
options =>
{
options.Filters.Add(new AbpAutoValidateAntiforgeryTokenAttribute());
}
).AddNewtonsoftJson(options =>
{
options.SerializerSettings.ContractResolver = new AbpMvcContractResolver(IocManager.Instance)
{
NamingStrategy = new CamelCaseNamingStrategy()
};
});
IdentityRegistrar.Register(services);
AuthConfigurer.Configure(services, _appConfiguration);
services.AddSignalR();
// Configure CORS for angular2 UI
services.AddCors(
options => options.AddPolicy(
_defaultCorsPolicyName,
builder => builder
.WithOrigins(
// App:CorsOrigins in appsettings.json can contain more than one address separated by comma.
_appConfiguration["App:CorsOrigins"]
.Split(",", StringSplitOptions.RemoveEmptyEntries)
.Select(o => o.RemovePostFix("/"))
.ToArray()
)
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials()
)
);
options.DocInclusionPredicate((docName, description) => true);
// Define the BearerAuth scheme that's in use
options.AddSecurityDefinition("bearerAuth", new OpenApiSecurityScheme()
{
Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey
});
});
services.AddAzureAppConfiguration();
// Bind configuration "TestApp:Settings" section to the Settings object
services.AddOptions();
services.Configure<Settings>(Configuration.GetSection("TestApp:Settings"));
// Configure Abp and Dependency Injection
return services.AddAbp<RptWebHostModule>(
// Configure Log4Net logging
options => options.IocManager.IocContainer.AddFacility<LoggingFacility>(
f => f.UseAbpLog4Net().WithConfig("log4net.config")
)
);
}
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
{
app.UseAbp(options => { options.UseAbpRequestLocalization = false; }); // Initializes ABP framework.
app.UseCors(_defaultCorsPolicyName); // Enable CORS!
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAbpRequestLocalization();
app.UseEndpoints(endpoints =>
{
endpoints.MapHub<AbpCommonHub>("/signalr");
endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
endpoints.MapControllerRoute("defaultWithArea", "{area}/{controller=Home}/{action=Index}/{id?}");
});
options.IndexStream = () => Assembly.GetExecutingAssembly()
options.DisplayRequestDuration(); // Controls the display of the request duration (in milliseconds) for "Try it out" requests.
});
// Use Azure App Configuration middleware for dynamic configuration refresh.
app.UseAzureAppConfiguration();
}
}
Custom Controller where I get the null values:
[Route("api/[controller]/[action]")]
public class AzureAppConfigTest : AbpControllerBase
{
public Settings _settings { get; }
public AzureAppConfigTest(IOptionsSnapshot<Settings> options
)
{
_settings = options.Value;
}
[HttpPost]
public string Test()
{
return _settings.Message; // The Problem is here
}
}
I need to get the values else where in the Application, I tried changing IOptionsSnapshot for IOptions but I can't make it work, Iv'e been stuck with this about two week but since I'm new in the Microsoft world I can't see clearly where the problem is, Thanks in Advance
Update:
I am able to use the configuration at the Presentation Layer, but If I try to use it on the Application layer I don't get the values.

How to inject own services in Controller

I tried to inject my own service in my api controller, but it throws an InvalidOperationException. It is unable to resolve the service. (.NET 5)
What I am doing wrong?
public class MyController : ControllerBase
{
private readonly MyService _myService;
public ContractsController(MyService service)
{
myService = service;
}
[HttpGet("{id}")]
public Item GetItemById(string id)
{
return _myService.getContract(id);
}
}
This is my Startup file:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddSwaggerGen(c =>
{
c.CustomOperationIds(selector => $"{selector.HttpMethod.ToLower().Pascalize()}{selector.ActionDescriptor.RouteValues["controller"]}");
c.SwaggerDoc("v1", new OpenApiInfo { Title = "My.Portal.Server", Version = "v1" });
});
services.AddCors(options =>
{
options.AddDefaultPolicy(builder =>
{
builder.SetIsOriginAllowed(origin => new Uri(origin).IsLoopback)
.WithOrigins(Configuration.GetSection("AllowedOrigins").Get<string[]>())
.AllowAnyHeader()
.AllowAnyMethod();
});
});
}
// 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.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "My.Portal.Server v1"));
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseCors();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
If i create a new instance in the constructor, then it is working.
thank you in advance!
Example, as per request in comment:
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IInfoStorageService>(c => new InfoStorageService(Configuration["ImageInfoConnectionString"]));
This is telling the application to pass an instance of InfoStorageService in where IInfoStorageService is injected. It is instantiated with a connection string that it reads from configuration.
AddScoped means that the injected service will be the same across the request. You can also use AddTransient() which means it will not match any other uses of the service, or you can use AddSingleton(), which means it will use the same instance through the whole lifetime of the application.

Action routing in .Net Core 3 Web API

I am busy migrating an existing-working WebApi from .Net Core 2.2 to 3, however, the routing stopped working. I keep getting a 404 Not Found message.
Would like to use the action names as part of the route template in my controller, for example:
[Route("/api/[controller]/[action]")]
Call example: /api/Lookup/GetBranchesAsync
I'm just really confused about why it stopped working.
Please see the code below.
Startup:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddScoped<IAuthService, AuthService>();
services.AddScoped<ILookupService, LookupService>();
services.AddScoped<IFranchiseRepo, FranchiseRepo>();
services.AddScoped<ILogRepo, LogRepo>();
services.AddSingleton<IConfiguration>(Configuration);
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
Controller:
[ApiController]
[Route("/api/[controller]/[action]")]
[Produces("application/json")]
public class LookupController : Controller
{
private readonly ILookupService lookupService;
public LookupController(ILookupService lookupService)
{
this.lookupService = lookupService;
}
[HttpGet]
public async Task<IActionResult> GetBranchesAsync()
{
}
[HttpGet("{branchID}")]
public async Task<IActionResult> GetBranchSEAsync(int? branchID)
{
}
}
Any advice on what the issue could be?
According to https://github.com/aspnet/AspNetCore/issues/8998, in .NET Core 3.0 Async is skipped by default in Action name. Your endpoint is available at /api/Lookup/GetBranches. You can change this behaviour by replacing
services.AddControllers();
with
services.AddControllers(options => options.SuppressAsyncSuffixInActionNames = false);
in ConfigureServices method, or just use the new routes

IdentityServer4 500 internal error, misssing EpochTimeExtensions when using authorize endpoint

I am creating a wep api backend for xamarin forms application with ASP.NET,
i'm using identityserver4 for authentication and authorization.
I want to use the authorization code workflow but i'm encountering a problem when i try to start the authorization/authentication request.
The error i receive is :
System.TypeLoadException: Could not load type 'IdentityModel.EpochTimeExtensions' from assembly 'IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=e7877f4675df049f'.
I haven't found a solution to this problem anywhere on the internet.
This is my Startup.cs
public class Startup
{
public IConfiguration Configuration { get; }
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
//services.AddAutoMapper();
services.AddDbContext<SqlDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddScoped<IUnitOfWork, UnitOfWork>();
services.AddIdentityServer()
.AddInMemoryIdentityResources(Config.GetResources())
.AddInMemoryApiResources(Config.GetApis())
.AddInMemoryClients(Config.GetClients())
.AddDeveloperSigningCredential();
services.AddControllers()
.AddNewtonsoftJson();
}
// 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
{
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseIdentityServer();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapGet("/", async context =>
{
await context.Response.WriteAsync("Hello World !");
});
});
}
}
This is my config.cs:
public class Config
{
public static IEnumerable<ApiResource> GetApis()
{
return new List<ApiResource>
{
new ApiResource("Test", "TestService")
};
}
public static IEnumerable<IdentityResource> GetResources()
{
return new List<IdentityResource>
{
new IdentityResources.OpenId()
};
}
public static IEnumerable<Client> GetClients()
{
return new List<Client>
{
new Client
{
ClientId = "client",
AllowedGrantTypes = GrantTypes.Code,
RequireClientSecret = false,
RequireConsent = false,
AllowedScopes = new List<string>{ "Test" , "openid"},
AllowOfflineAccess = true,
RedirectUris = new List<String> {
"https://localhost:44392/account/test/"
}
}
};
}
}
And this is my request url :
https://localhost:44392/connect/authorize?client_id=client&response_type=code&redirect_uri=https://localhost:44392/account/test/&scope=Test openid&nonce=5&state=5
I hope someone here can help me.
Thanks in advance

AuthenticationHandler calls everytime even Controller is not required Authorization

I have added Custom security it is working fine for authrization. I don't know why Task<AuthenticateResult> HandleAuthenticateAsync() is calling for controller that don't needs authorization.
In Startup.cs below is code how I Initilize it .
public void ConfigureServices(IServiceCollection services)
{
services.AddCors();
services.AddMvc();
services.AddAutoMapper();
c.AddSecurityDefinition(MM.AuthenticationScheme, new ApiKeyScheme()
{
Description = "API Key Authorization header using the mm Api Key scheme. Example: \"MM-API-KEY: {MM-API-KEY}\"",
Name = "MM-API-KEY",
In = "header",
Type = "apiKey"
});
auth.AddPolicy(MM.AuthenticationScheme, b =>
{
b.RequireAuthenticatedUser();
b.AuthenticationSchemes = new List<string> { MenulogApiKey.AuthenticationScheme };
});
services.AddAuthentication(options =>
{
// the scheme name has to match the value we're going to use in options.DefaultAuthenticateScheme = MM.AuthenticationScheme;
options.DefaultChallengeScheme = MM.AuthenticationScheme;
})
.AddMenulogApiKeyAuth(o => { });
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.UseAuthentication();
}
In KeyHandler Class I am using like this :
internal class MMApiKeyHandler : AuthenticationHandler<MMApiKeyAuthOptions>
(Blind guess)
The authentication filter may be set up as a global filter.
Search for something like filters.Add(
or examine the code where GlobalFilters.Filters are used.

Categories

Resources