ASP .NET Core CORS issue with Google authentication on redirect - asp.net-core

Been following this tutorial in order to implement Google authentication in my web API but on the client side (using React and axios to do the request) the authentication process gets interrupted with this CORS issue and I'm struggling to sort it out:
Access to XMLHttpRequest at 'https://accounts.google.com/o/oauth2/v2/auth?(etc)' (redirected from 'https://localhost:44320/Photo/b997d788-3812-41d0-a09d-1a597eee9bad') from origin 'https://localhost:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
This is the Startup.cs file:
namespace rvc
{
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.AddCors(options =>
{
options.AddDefaultPolicy(builder =>
{
builder.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod();
});
});
services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
}).AddCookie(options =>
{
options.LoginPath = "/account/google-login";
}).AddGoogle(options =>
{
options.ClientId = "clientId";
options.ClientSecret = "secret";
});
services.AddScoped<PhotoService>();
services.AddScoped<TagService>();
services.AddScoped(_ => new BlobServiceClient(Configuration.GetConnectionString("AzureBlobStorage")));
services.AddDbContext<Data.DataContext>(x => x.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddControllers().AddJsonOptions(options =>
{
options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles;
});
services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "rvc", Version = "v1" }); });
}
// 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", "rvc v1"));
}
app.UseHttpsRedirection();
if (env.IsProduction())
{
app.UseSpa(spa => { });
app.UseFileServer(new FileServerOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(env.ContentRootPath, "client")),
EnableDefaultFiles = true
});
}
app.UseRouting();
app.UseCors();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
}
}
}
The Route("google-login") gets called but the Url.Action("GoogleResponse") is not reached. These are the Google Authentication methods:
namespace rvc.Controllers;
[AllowAnonymous, Route("account")]
public class AccountController : Controller
{
[Route("google-login")]
public IActionResult GoogleLogin()
{
var properties = new AuthenticationProperties {RedirectUri = Url.Action("GoogleResponse")};
return Challenge(properties, GoogleDefaults.AuthenticationScheme);
}
[Route("google-response")]
public async Task<IActionResult> GoogleResponse()
{
var result = await HttpContext.AuthenticateAsync(CookieAuthenticationDefaults.AuthenticationScheme);
var claims = result.Principal?.Identities.FirstOrDefault()
?.Claims.Select(claim => new
{
claim.Issuer,
claim.OriginalIssuer,
claim.Type,
claim.Value
});
return Json(claims);
}
}

This is probably because from the server you use redirect, which triggers CORS (even if from your server you allow it).
you have to return the redirect URL to your front-end in some other way, capture it from the front-end app and then call the URL you need to invoke.

Related

Visual studio's ASP.NET core with angular template always returns 401

I'm using Microsoft Visual Studio Community 2019 Version 16.10.2. I created an ASP.net core 5 project from their template "ASP.net core with Angular" with Authentication checked. But Every time I request an API Method marked with the attribute [Authorize] I get 401.
Their template was supposed to work with no problem but I got some trouble logging in. I fixed them but, the only problem I can't figure out how to fix is the 401 code returned ASP.
I read the doc several times but I could not find any useful information.
The thing is: I can create accounts and login with no problem. When I login, the server returns the token. From the Angular app it shows the name of the logged-in user. But when to access an [Authorize] controller it returns 404.
Here is the link of the project I pushed to github for better debugging.
Here is the startup code:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDatabaseDeveloperPageExceptionFilter();
services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>(op =>
{
// I added these lines because I was getting the error "Error: Client Angular_identity_test is not allowed access to scope Angular."
op.Clients[0].AllowedScopes = new List<string> { "Angular", "identity", "testAPI" };
op.ApiScopes = new Microsoft.AspNetCore.ApiAuthorization.IdentityServer.ApiScopeCollection(new List<ApiScope> { new ApiScope("Angular"), new ApiScope("identity"), new ApiScope("testAPI") });
op.ApiResources.AddApiResource("Angular", conf => conf.WithScopes(new string[] { "Angular", "identity", "testAPI" }));
op.ApiResources.AddApiResource("identity", conf => conf.WithScopes(new string[] { "Angular", "identity", "testAPI" }));
op.ApiResources.AddApiResource("testAPI", conf => conf.WithScopes(new string[] { "Angular", "identity", "testAPI" }));
});
services.AddAuthentication()
.AddIdentityServerJwt();
services.AddControllersWithViews();
services.AddRazorPages();
// In production, the Angular files will be served from this directory
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/dist";
});
}
// In public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
app.UseHttpsRedirection();
app.UseStaticFiles();
if (!env.IsDevelopment())
{
app.UseSpaStaticFiles();
}
app.UseRouting();
// I added this line because some people say that fixed their problems.
app.UseCors(x => x
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader());
app.UseAuthentication();
app.UseIdentityServer();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller}/{action=Index}/{id?}");
endpoints.MapRazorPages();
});
app.UseSpa(spa =>
{
// To learn more about options for serving an Angular SPA from ASP.NET Core,
// see https://go.microsoft.com/fwlink/?linkid=864501
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
spa.UseAngularCliServer(npmScript: "start");
}
});
In the appsettings.json there is:
"IdentityServer": {
"Clients": {
"Angular_identity_test": {
"Profile": "IdentityServerSPA"
}
}
}
And the controller that keeps return 401:
[Authorize()]
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
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)
{
_logger = logger;
}
[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();
}
So you say, But when to access a [Authorize] controller it returns 404. use this below code, instead of [Authorize].
[Authorize(AuthenticationSchemes = "Bearer")]
It will resolve your issue.
UPDATE
Use this below code and i assume that your Token is place of appsettings.development.json file. like "TokenKey":"super secret key",
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options => {
options.TokenValidationParameters=new TokenValidationParameters
{
ValidateIssuerSigningKey=true,
IssuerSigningKey=new SymmetricSecurityKey( Encoding.UTF8.GetBytes(config["TokenKey"]) ),
ValidateIssuer=false,
ValidateAudience=false
};
});
Hope it will resolve your issue.
This will be a proxy issue. In your CLIENTAPP go to the proxy.conf.js and add your controllers route into the PROXY_CONFIG->context array (like "/weatherforecast" is). Then restart your application. You don't need to change .NET Core middleware or services.
UPDATE
I added this DI BASE_URL into my service constructor and it works fine now.
constructor(private http: HttpClient, #Inject('BASE_URL') private bUrl: string) {
this.baseUrl = bUrl + "api/v1/items"; // my endpoint
}

ASP.NET Core 3.1 HttpContext.SignOutAsync does not Redirect

When I use HttpContext.SignOutAsync with AuthenticationProperties together with a RedirectUri I expect to be redirected to a URL, but instead I am not redirected.
How can I debug this? I do not see any Exception or Warning.
Is this my implementation swallowing this?
HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme,
new AuthenticationProperties { RedirectUri = "/" });
Here is the Logout Implementation:
[AllowAnonymous]
public async Task Logout()
{
var oidcAuth = false;
// clear the auth cookies
if (HttpContext.Request.Cookies.Count> 0)
{
foreach (var (key, _) in HttpContext.Request.Cookies)
{
if (key.Contains(Startup.COOKIE_NAME_BASIC))
{
Response.Cookies.Delete(key);
} else if (key.Contains(Startup.COOKIE_NAME_OIDC))
{
oidcAuth = true;
Response.Cookies.Delete(key);
}
}
}
HttpContext.Session.Clear();
if (oidcAuth)
{
await HttpContext.SignOutAsync(Startup.COOKIE_NAME_OIDC);
await HttpContext.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme);
}
else
{
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme,
new AuthenticationProperties { RedirectUri = "/" });
}
}
Firstly,you can refer to the official doc,and you can see RedirectUri is only used on a few specific paths by default, for example, the login path and logout paths.
So if you want to redirect,you need to make sure your current path is login or logout path.Here is a demo:
Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options =>
{
options.LoginPath = "/Home/Login";
options.LogoutPath = "/Home/Logout";
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
// 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.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseSession();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
HomeController:
[HttpPost]
public async Task Logout()
{
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme,new AuthenticationProperties { RedirectUri="/"});
}
result:
The official documentation does not mention what the "special" conditions are, but the source code does. No Exception or warning is given when the Redirect URI is being ignored.
The source code located here explains it all:
// Only redirect on the login path
var shouldRedirect = Options.LoginPath.HasValue && OriginalPath == Options.LoginPath;
await ApplyHeaders(shouldRedirect, signedInContext.Properties);
Logger.AuthenticationSchemeSignedIn(Scheme.Name);
Some important bits:
In Startup make sure the options.LogoutPath matches the path of
your actual LogoutController's Logout Action.
Secondly the Logout Action should not perform the redirect and
should return a Task and not a Task<IActionResult>
Also not to handle the OnRedirectToReturnUrl yourself.
LogoutController: Sign-out and set the Redirect URI The Path = "Logout/Logout"
[AllowAnonymous]
[HttpPost]
public async Task Logout()
{
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme,
new AuthenticationProperties { RedirectUri = "/" });
}
Startup: Configure the path
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme,"Cookie",options => {
// must match path of Logout Controller
options.LogoutPath = new PathString("/Logout/Logout");
// do not handle the event yourself
// options.Events.OnRedirectToReturnUrl = async context =>
// {
// await Task.CompletedTask;
// };

ASP.NET Core returns InternalServerError while using Identity server

I trying to add identity server for my web API as its identity server4 documentation. when I was trying to call API from my console application it's every time returns InternalServerError.
Here is My Identity server Config.cs
public static class Config
{
// register api
public static IEnumerable<ApiScope> ApiScopes => new List<ApiScope>
{
// in here add your api name
new ApiScope("api1", "My API")
};
// register client which is going to access api. eg: front-end application, mobile apps etc. can add multiple client.
public static IEnumerable<Client> Clients => new List<Client>
{
new Client
{
// which is going to access
ClientId = "client",
// no interactive user, use the clientid/secret for authentication
AllowedGrantTypes = GrantTypes.ClientCredentials,
// secret for authentication
ClientSecrets =
{
new Secret("secret".Sha256())
},
// scopes that client has access to
AllowedScopes = { "api1" }
}
};
}
and here the identity server startup file configuration service and configure functions
public void ConfigureServices(IServiceCollection services)
{
// uncomment, if you want to add an MVC-based UI
services.AddControllersWithViews();
var builder = services.AddIdentityServer()
.AddInMemoryApiScopes(Config.ApiScopes)
.AddInMemoryClients(Config.Clients);
builder.AddDeveloperSigningCredential();
builder.AddDeveloperSigningCredential();
}
public void Configure(IApplicationBuilder app)
{
if (Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
// uncomment if you want to add MVC
app.UseStaticFiles();
app.UseRouting();
app.UseIdentityServer();
// uncomment, if you want to add MVC
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
});
}
and here is my API startup file's congurationService and configure functions
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddAuthentication("Bearer")
.AddJwtBearer("Bearer", options =>
{
options.Authority = "https://localhost:14030/";
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = false
};
}
);
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
here is my API controller
[Route("identity")]
public class IdentityController : ControllerBase
{
[HttpGet]
[Authorize]
public IActionResult Get() => Ok(new JsonResult(from c in User.Claims select new { c.Type, c.Value }));
}
and here is my console application client request a api
static async System.Threading.Tasks.Task Main(string[] args)
{
// discover endpoints from metadata
var client = new HttpClient();
var disco = await client.GetDiscoveryDocumentAsync("http://localhost:14030");
if (disco.IsError)
{
Console.WriteLine(disco.Error);
return;
}
// request token
var tokenResponse = await client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest
{
Address = disco.TokenEndpoint,
ClientId = "client",
ClientSecret = "secret",
Scope = "api1"
});
if (tokenResponse.IsError)
{
Console.WriteLine(tokenResponse.Error);
return;
}
Console.WriteLine(tokenResponse.Json);
Console.WriteLine("\n\n");
// call api
var apiClient = new HttpClient();
apiClient.SetBearerToken(tokenResponse.AccessToken);
var response = await apiClient.GetAsync("https://localhost:5001/identity");
if (!response.IsSuccessStatusCode)
{
Console.WriteLine(response.StatusCode);
}
else
{
var content = await response.Content.ReadAsStringAsync();
Console.WriteLine(content);
}
}
what are the mistakes should I have to fix. Im really appreciates your valuable answers and efforts.
Thank
I got the code working, I would do the following:
use HTTPS here, not HTTP:
var disco = await
client.GetDiscoveryDocumentAsync("http://localhost:14030");
Remove the duplicate lines of in IdentityServer startup class:
builder.AddDeveloperSigningCredential();
I would add in your API startup.cs
services.AddAuthorization();
Remove the trailing / at the end of the URL here:
options.Authority = "https://localhost:14030/";
To get more debugging output from your API, you can add the following two trace lines to your appsettings.Development.json file:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information",
"Microsoft.AspNetCore.Authentication": "Trace",
"Microsoft.AspNetCore.Authorization": "Trace"
}
}
}
If you want to validate the Audience (and using IdentityServer4 v4.00) you can add:
services.AddControllers();
services.AddAuthentication("Bearer")
.AddJwtBearer("Bearer", options =>
{
options.Authority = "https://localhost:14030";
options.TokenValidationParameters = new TokenValidationParameters
{
ValidAudiences = new[] {"https://localhost:14030/resources"},
ValidateAudience = true
};
}
);

AspNetCore 2.2 as API - How to logout using Identity methods?

I created web application with Angular 7 as front-end,
DotNetCore 2.2 as back-end API (SQL Server for db).
When I initially created the project, I didn't add Authentication, because
there is no need of UI pages. I plan to use Identity authentication with cookies.
While Login and [Authorize] work well, Logout doesn't work with signInManager.SignOutAsync().
Microsoft states:
"SignOutAsync clears the user's claims stored in a cookie.
Don't redirect after calling SignOutAsync or the user will not be signed out."
Seems that the cookie is not deleted and it is accepted as valid from API (except when it is expired).
I tried with Response.Cookies.Delete() and HttpContext.SignOutAsync() without success.
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy("CORS", builder =>
{
builder.WithOrigins("http://localhost:42000")
.AllowAnyHeader()
.AllowCredentials();
});
});
services.Configure<CookiePolicyOptions>(options =>
{
options.CheckConsentNeeded = context => false;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddDbContext<NGDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<NGUser, IdentityRole>()
.AddEntityFrameworkStores<NGDbContext>()
.AddDefaultTokenProviders();
services.Configure<IdentityOptions>(options =>
{
// some options...
});
services.ConfigureApplicationCookie(options =>
{
options.Cookie.HttpOnly = true;
options.ExpireTimeSpan = TimeSpan.FromMinutes(1);
options.SlidingExpiration = true;
//options.CookieName = "MyCookie";
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddScoped<NamesService, NamesService>();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
InitialSeeder.Seed(app);
}
else
{
app.UseHsts();
}
app.UseCors("CORS");
app.UseHttpsRedirection();
app.UseCookiePolicy();
app.UseAuthentication();
app.UseMvc();
}
[Route("api/[controller]")]
[ApiController]
public class AuthController : ControllerBase
{
private UserManager<NGUser> userManager;
private SignInManager<NGUser> signInManager;
public AuthController(UserManager<NGUser> userManager, SignInManager<NGUser> signInManager)
{
this.userManager = userManager;
this.signInManager = signInManager;
}
[HttpPost("Login")]
public async Task<ActionResult> Login(LoginModel model)
{
var user = await this.userManager.FindByNameAsync(model.Username);
if (user == null)
{
return Unauthorized();
}
var signInResult = await this.signInManager.PasswordSignInAsync(user, model.Password, false, false);
if (!signInResult.Succeeded)
{
return Unauthorized();
}
return Ok();
}
[HttpPost("Logout")]
public async Task<ActionResult> Logout()
{
await this.signInManager.SignOutAsync();
return Ok();
}
}
Is it possible to benefit from Identity sign-in sign-out methods?
Or should use custom methods?
For successful logout signInManager.SignOutAsync() just needs a cookie.
Which I didn't supply with Angular HttpClient.post() method - I missed null as second argument.
Working Angular Side:
login(model: LoginModel){
return this.http.post("https://localhost:50000/api/auth/login", model, { withCredentials: true });
}
logout(){
return this.http.post("https://localhost:50000/api/auth/logout", null, { withCredentials: true });
}
Working .Net Side:
Both logout approaches work:
this.HttpContext.Response.Cookies.Delete(".AspNetCore.Identity.Application");
await this.signInManager.SignOutAsync();
The first deletes only selected cookie, while the second deletes three .AspNetCore.Identity.Application, Identity.External ,Identity.TwoFactorUserId.
SignOutAsync calls three methods:
await Context.SignOutAsync(IdentityConstants.ApplicationScheme);
await Context.SignOutAsync(IdentityConstants.ExternalScheme);
await Context.SignOutAsync(IdentityConstants.TwoFactorUserIdScheme);
Yes, it is possible to use Identity in API.

.Net Core 2.0 Web API OpenIddict Authorization: redirecting to index instead of returning json data

So, the problem is that when I use the AuthorizeAttribute on top of my api controller, it stops working the expected way.
When I call a getAllUsers action, instead of returning the users in json format, the Identity somehow redirects to index.html and then I get a json parser error in my Angular client app, because html is not valid json data that can be parsed.
This started to happen after upgrading to Asp.Net Core 2.0.
I think that perhaps I have to change something in my Startup.cs or Program.cs. But I can't figure out what.
I have followed the Refresh Token Sample on OpenIddict for the new Core 2.0, and everything seems to be ok.
So here is my code...
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options => {
options.UseSqlServer(Configuration.GetConnectionString("LocalDB"))
.UseOpenIddict();
});
services.AddScoped<IUserRepository, UserRepository>();
services.AddScoped<IRoleRepository, RoleRepository>();
services.AddScoped<IManadRepository, ManadRepository>();
services.AddScoped<IManadRubricaRepository, ManadRubricaRepository>();
services.AddScoped<IManadSistemaRepository, ManadSistemaRepository>();
services.AddScoped<IRestituicaoRepository, RestituicaoRepository>();
services.AddTransient<ApplicationDbSeedData>();
services.AddIdentity<ApplicationUser, ApplicationRole>(options =>
{
options.User.RequireUniqueEmail = true;
options.ClaimsIdentity.UserNameClaimType = OpenIdConnectConstants.Claims.Name;
options.ClaimsIdentity.UserIdClaimType = OpenIdConnectConstants.Claims.Subject;
options.ClaimsIdentity.RoleClaimType = OpenIdConnectConstants.Claims.Role;
})
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.AddOpenIddict(options =>
{
options.AddEntityFrameworkCoreStores<ApplicationDbContext>();
options.AddMvcBinders();
options.EnableTokenEndpoint("/connect/token");
options.AllowPasswordFlow();
options.AllowRefreshTokenFlow();
if (!_env.IsProduction())
options.DisableHttpsRequirement();
});
// Add framework services.
services.AddMvc();
services.AddAuthentication()
.AddOAuthValidation();
services.AddAuthorization();
services.AddTransient<IMailSender, MailjetSender>();
services.AddScoped<IManadParser, ManadParser>();
}
public void Configure(IApplicationBuilder app, ApplicationDbSeedData dbDataSeeder)
{
if (_env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions
{
HotModuleReplacement = true
});
}
else
{
app.UseExceptionHandler("/Home/Error");
}
Mapper.Initialize(cfg =>
{
cfg.AddProfile<AutoMapperProfile>();
});
app.UseStaticFiles();
app.UseAuthentication();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
routes.MapSpaFallbackRoute(
name: "spa-fallback",
defaults: new { controller = "Home", action = "Index" });
});
dbDataSeeder.EnsureSeedData().Wait();
}
UsersController.cs
[Route("api/[controller]")]
[Authorize]
public class UsersController : Controller
{
[HttpGet]
[Authorize(Roles = "Administrador")]
public IActionResult GetAllUsers()
{
try
{
var result = _repository.GetAllUsers();
return Ok(result);
}
catch (Exception ex)
{
_logger.LogError($"Failed to get all users: {ex}");
return BadRequest(ex.Message);
}
}
}
If I put a breakpoint in the GetAllUsers method, it never gets hitted. Somehow because of authorization, the application redirects to index.html before.
Program.cs
public class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.Build();
}
By the way, authentication is working. I am able to get the tokens, but unable to authorize the controller access.
Solved it. Just needed some bit of configuration just like I thought. Just add DefaultAuthenticateScheme option like this:
services.AddAuthentication(options => options.DefaultAuthenticateScheme = OAuthValidationDefaults.AuthenticationScheme)
.AddOAuthValidation();
After adding this, the controller started to work correctly, resulting json data and not index.html.