I have Asp.net core(running on .net framework) web mvc application.
Startup.cs:
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)
{
var aiOptions = new Microsoft.ApplicationInsights.AspNetCore.Extensions.ApplicationInsightsServiceOptions
{
EnableQuickPulseMetricStream = true
};
services.AddMvc();
services.AddApplicationInsightsTelemetry(aiOptions);
services.AddCors(option =>
{
option.AddPolicy("AllowSpecificOrigin", policy => policy.WithOrigins("*"));
option.AddPolicy("AllowGetMethod", policy => policy.WithMethods("GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"));
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
TelemetryClient tc = new TelemetryClient();
tc.TrackTrace("Environment: " + env);
if (env.IsDevelopment())
{
tc.TrackTrace("Development");
app.UseDeveloperExceptionPage();
}
else
{
app.UseDeveloperExceptionPage();
}
app.Use((context, next) =>
{
context.Request.PathBase = new PathString("/Application1");
return next.Invoke();
});
app.UseStaticFiles();
app.UseCors(select => select.AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin());
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
routes.MapSpaFallbackRoute(
name: "spa-fallback",
defaults: new { controller = "Home", action = "Index" });
});
}
}
HomeController Action:
public class HomeController : Controller
{
public HomeController(StatelessServiceContext context){
}
public IActionResult UsernameAuthentication()
{
return View();
}
}
Action Executing:
http://localhost:9040/Home/UserNameAuthentication
Action not Executing:
http://localhost:9040/Application1/Home/UserNameAuthentication
Any other configuration i have to do,to execute Action with PathBase?or any other way to use context path to execute action.How?
Thanks.
As far as I know, if you use Application1/Home/UserNameAuthentication as the url pass to the application, the application context.Request.Path will be the Application1/Home/UserNameAuthentication then you add the pathbase, it will be Application1/Application1/Home/UserNameAuthentication this is the reason why you get 404 error.
To solve this issue, you should check whether the beginning of this Microsoft.AspNetCore.Http.PathString matches the specified Microsoft.AspNetCore.Http.PathString.
More details, you could refer to below codes:
app.Use((context, next) =>
{
string _pathBase = "/Application1";
PathString matchedPath;
PathString remainingPath;
if (context.Request.Path.StartsWithSegments(_pathBase, out matchedPath, out remainingPath))
{
var originalPath = context.Request.Path;
var originalPathBase = context.Request.PathBase;
context.Request.Path = remainingPath;
context.Request.PathBase = originalPathBase.Add(matchedPath);
var re = context.Request.PathBase;
return next.Invoke();
}
else
{
return next.Invoke();
}
});
Result:
Related
I have a dotnet 5 web API with an Angular2+ front end, which I'm building from a previous 3.1 MVC version of the app. I'm having an issue with CORS while looking to authenticate with Yahoo that I did not have with the MVC version. The error I am getting is:
"Access to XMLHttpRequest at 'https://api.login.yahoo.com...' (redirected from 'https://localhost:5003/api/draft/yahooauth/') from origin 'https://localhost:5003' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource."
My API Controller:
[EnableCors("MyPolicy")]
[HttpPost("yahooauth")]
public void YahooAuth()
{
string leftUrl = string.Format("{0}://{1}", HttpContext.Request.Scheme, HttpContext.Request.Host);
string returnUrl = $"{leftUrl}/api/draft/yahooexchange";
string id = configuration["YahooClientId"];
string secret = configuration["YahooClientSecret"];
string url = $"https://api.login.yahoo.com/oauth2/request_auth?client_id={id}&redirect_uri={returnUrl}&response_type=code&language=en-us";
Response.Redirect(url);
}
[HttpGet("yahooexchange/{code}")]
public IActionResult yahooexchange(string code)
{
// Code that is supposed to be triggered with returnUrl from Yahoo
}
Startup.cs:
public class Startup
{
public Startup(IConfiguration configuration) => Configuration = configuration;
public IConfiguration Configuration { get; }
readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
// 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.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential
// cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
// requires using Microsoft.AspNetCore.Http;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddDbContext<IdentityDbCxt>(options => options.UseSqlServer(Configuration.GetConnectionString("IdentityDb")));
services.AddDbContext<DraftContext>(options => options.UseSqlServer(Configuration.GetConnectionString("FSDraftDb")));
services.AddIdentity<AppUser, IdentityRole>(opts =>
{
opts.User.RequireUniqueEmail = true;
})
.AddEntityFrameworkStores<IdentityDbCxt>()
.AddDefaultTokenProviders();
services.AddTransient<IEmailSender, EmailSender>();
services.AddTransient<IAPICall, APICall>();
services.AddTransient<IDraftService, DraftService>();
services.AddCors(options =>
{
options.AddPolicy("MyPolicy",
builder =>
{
builder.WithOrigins("*")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
services.AddMvc()
.AddRazorRuntimeCompilation();
services.AddMemoryCache();
services.AddSession();
services.AddSingleton<IHtmlSanitizer, HtmlSanitizer>();
services.AddControllersWithViews(/*options =>
options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute())*/);
services.AddRazorPages();
services.AddSwaggerGen(options =>
{
options.SwaggerDoc("v1",
new OpenApiInfo { Title = "API", Version = "v1" });
});
services
.AddControllers()
.AddNewtonsoftJson();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostEnvironment env, IServiceProvider services)
{
//app.UseMiddleware<GCMiddleware>();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
}
app.UseStatusCodePages();
//app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseAuthentication();
app.UseSession();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}");
endpoints.MapControllerRoute(
name: "angular_fallback",
pattern: "{target:regex(draft|data|keeper|adminapi|admin`):nonfile}/{*catchall}",
defaults: new { controller = "Home", action = "Index" });
endpoints.MapRazorPages();
});
app.UseSwagger();
app.UseSwaggerUI(options =>
{
options.SwaggerEndpoint("/swagger/v1/swagger.json", "API");
});
app.UseSpa(spa =>
{
string strategy = Configuration.GetValue<string>("DevTools:ConnectionStrategy");
if (strategy == "proxy")
{
spa.UseProxyToSpaDevelopmentServer("http://127.0.0.1:4200");
}
else if (strategy == "managed")
{
spa.Options.SourcePath = "../ClientApp";
spa.UseAngularCliServer("start");
}
});
}
}
I've looked at a few sources, including one quite hopeful post here, but this did not solve my problem: Problems with CORS Response to preflight in dotnet core 3.1
In case it's helpful, I'm looking to do step 2: https://developer.yahoo.com/oauth2/guide/flows_authcode/
Edit: This is the documentation I used regarding CORS: https://learn.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-5.0#attr
Try to use this syntax and move AddCors to the top of ConfigureServices. Assign name to UseRouting.
services.AddCors(o => o.AddPolicy("MyPolicy", builder =>
{
builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
}));
.......
....
app.UseRouting();
app.UseCors("MyPolicy");
app.UseAuthentication();
app.UseAuthorization();
.....
So I ended up figuring out a workaround and just created a new MVC controller, as my previous MVC app worked fine.
In addition, I realized that I had not updated my Yahoo Developer App for the new return URI. This did not fix my CORS problem, but it was preventing this from properly working.
Code from Angular to go to the new controller.
window.location.href = "https://localhost:5003/yahoo/index";
My MVC Controller:
public class YahooController : Controller
{
private IAPICall apiCall;
public YahooController(IAPICall aCall)
{
apiCall = aCall;
}
// getting session data on player values
private DraftService GetDS()
{
DraftService draftService = HttpContext.Session.GetJson<DraftService>("DraftService") ?? new DraftService();
return draftService;
}
// saving session data on player values
private void SaveDS(DraftService ds)
{
HttpContext.Session.SetJson("DraftService", ds);
}
[HttpGet]
public void Index()
{
string returnUrl = Url.Action("yahooexchange",
"yahoo", new
{
},
protocol: HttpContext.Request.Scheme);
string url = apiCall.YahooAuthUrl(returnUrl);
Response.Redirect(url);
}
public void yahooexchange(string code)
{
string content = apiCall.YahooGetToken(code);
var jContent = JsonConvert.DeserializeObject<JObject>(content);
string accessToken = jContent.GetValue("access_token").ToString();
string refreshToken = jContent.GetValue("refresh_token").ToString();
string leftUrl = string.Format("{0}://{1}", HttpContext.Request.Scheme, HttpContext.Request.Host);
DraftService ds = GetDS();
ds.YahooAccessToken = accessToken;
ds.YahooRefreshToken = refreshToken;
SaveDS(ds);
string url = leftUrl + "/draft/" + ds.DraftId;
Response.Redirect(url);
}
}
I am using an Custom Action Filter attribute to check if session is null or not..
Authenticate.cs
public class Authenticate : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
var data = context.HttpContext.Session.GetString("UserSession");
if (data == null)
{
bool isAjax = context.HttpContext.Request.Headers["X-Requested-With"] == "XMLHttpRequest";
if (isAjax)
{
context.Result = new JsonResult("Session Expired!");
}
else
{
context.Result = new RedirectResult("/Account/Login");
}
}
}
public override void OnActionExecuted(ActionExecutedContext context)
{
// our code after action executes
}
}
I am calling this attribute on all controllers except Account Controller
AccountController.cs
public class AccountController : Controller
{
UserFunctions userFunctions;
public AccountController(ARSContext context)
{
userFunctions = new UserFunctions(context);
}
public IActionResult Index()
{
return View();
}
public IActionResult Login()
{
return View();
}
[HttpPost]
public IActionResult Login(AccountViewModel viewModel)
{
User user = userFunctions.Login(viewModel.Username, viewModel.Password);
if (user != null)
{
HttpContext.Session.SetString("UserSession", JsonConvert.SerializeObject(user));
return Json(true);
}
return Json(false);
}
}
My Startup.cs
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.AddControllersWithViews().AddRazorRuntimeCompilation();
services.AddDbContext<MyDBContext>(item => item.UseSqlServer(Configuration.GetConnectionString("MyDBEntities")));
services.AddScoped<CountryFunctions>();
services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromHours(1);
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseSession();
app.UseDeveloperExceptionPage();
if (env.IsDevelopment())
{
}
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.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
Now the main problem is that all of this is working perfectly on my local computer when I run it through Visual Studio. But when I deploy it on IIS what happens is that when I call '/Account/Login' without 'HttpPOST' it shows you view.
But when I submit the form and call '/Account/Login' 'HttpPost' action then My Authenticate filter is called which redirects me back to '/Account/Login' View Action. I also tried to use ServiceFilters but same problem persists.
I've created a new controller in a brand new web api project in .net core 3.1. Whenever I try to post to the route I get a 404.
The controller is set as so:
[ApiController]
[Route("[controller]")]
public class AuthCodeController : Controller
{
private readonly ApplicationContext _context;
public AuthCodeController(ApplicationContext context)
{
_context = context;
}
[HttpPost]
[Consumes("application/x-www-form-urlencoded")]
public JsonResult GetAuthCode(AuthCode authCode)
{
try
{
var theCodes = _context.AuthCodes.ToList();
var tmpCode = new Random();
var myNum = tmpCode.Next(100000, 999999999);
while (theCodes.Any(tc => tc.AuthCodeRnd == myNum))
{
myNum = tmpCode.Next();
}
if (authCode.AuthCodeRnd > 0)
{
var removeCode = _context.AuthCodes.FirstOrDefault(c => c.AuthCodeRnd == authCode.AuthCodeRnd);
if (removeCode != null) _context.AuthCodes.Remove(removeCode);
}
Guid authGuid = Guid.NewGuid();
var tmpRec = new AuthCode
{
Guid = authGuid,
AuthCodeRnd = myNum,
Address = authCode.tAddress,
SmallLogoAddress = authCode.SmallLogoAddress,
ClientFolder = authCode.ClientFolder,
CompanyFolder = authCode.CompanyFolder,
Folder = authCode.Folder
};
_context.AuthCodes.Add(tmpRec);
_context.SaveChanges();
var retVals = new AuthResponse
{
Guid = authGuid,
ReturnAuthCode = myNum
};
return Json(retVals);
}
catch (Exception ex)
{
var message = new ErrorResponse();
message.Status = "An Error Has Occured";
message.Message = ex.ToString();
return Json(message);
}
}
}
When I POST to this method I receive a 404. I'm using the url https://localhost:44328/AuthCode/GetAuthCode
The only modifications I made in the startup.cs are adding the dbcontext service options. Everything else is default. I can get the weatherforecast to show.
EDIT - added startup.cs
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.AddDbContext<ApplicationContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddControllers();
}
// 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.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
Solved: I needed to disable SSL Verification in POSTMan
You should set attribute: [HttpPost] → [HttpPost("GetAuthCode")] since your original route will be simple POST to 'https://localhost:44328/AuthCode'. Core Controller does use reflection to Your Controller name 'AuthCodeController' to form prefix for Your path ('/AuthCode' part). But it does not use reflection to form postfix from function name - You should form it yourself by parameter in HttpPost attribute.
I was working with KOA 2.0 and started to test asp.net core. But can't find a way to handle request/url specific middleware
Say in Koa, with router I can achieve the below:
.post("/api/v1/user", Middleware1, Middleware2, RequestValidationMiddleware, SpecificAction);
.get("/api/v1/user", Middleware1, Middleware2, RequestValidationMiddleware, SpecificAction1);
.post("/api/v1/role", Middleware1, Middleware4, RequestValidationMiddleware2, SpecificAction2);
How to achieve it with asp.net core?
Tried the below:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
//app.UseApiLog();
app.Map("/api", ApiLogApps);
app.Map("/exlog", ExceptionLogApps);
//app.UseMvc(routes =>
//{
// routes.MapRoute(
// name: "default",
// template: "apilog/{controller}/{action}");
// routes.MapRoute(
// name: "default2",
// template: "exlog/{controller=Home}/{action=Index}/{id:int}");
//});
}
private static void ApiLogApps(IApplicationBuilder app)
{
//app.Run(() => )
app.UseApiLog();
app.UseMvc();
}
And in controller I have
[Route("api/[controller]")]
public class ValuesController : Controller
{
// GET api/values
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET api/values/5
[HttpGet("test/get/{id}")]
public string Get(int id)
{
return "value";
}
}
But I am lost here.
What I want is, I want to have DataValidation to be handled in a middleware - that forces me to have per url (almost) specific middleware.
PS - I know, model validation can be done in action, but I don't want that.
Thanks in advance for your help :)
To use middlewares like Koa2 , you can configure a sequence of middlewares to build a route :
public IRouter BuildRouter(IApplicationBuilder applicationBuilder)
{
var builder = new RouteBuilder(applicationBuilder);
// use middlewares to configure a route
builder.MapMiddlewareGet("/api/v1/user", appBuilder => {
// your Middleware1
appBuilder.Use(Middleware1);
appBuilder.Use(Middleware2);
appBuilder.Use(RequestValidationMiddleware);
appBuilder.Run(SpecificAction);
});
builder.MapMiddlewarePost("/api/v1/user", appBuilder => {
// your Middleware1
appBuilder.Use(Middleware1);
appBuilder.Use(Middleware2);
appBuilder.Use(RequestValidationMiddleware);
appBuilder.Run(SpecificAction1);
});
// ....
return builder.Build();
}
and then use RouterMiddleware via UseRouter(router) :
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
// ...
app.UseRouter(BuildRouter(app));
// ...
app.UseMvc();
}
a screenshot:
[Update]:
To integrate with attribute routing, just add a UseMvc() insteand of Run() as below :
public IRouter BuildRouter(IApplicationBuilder applicationBuilder)
{
var builder = new RouteBuilder(applicationBuilder);
// use middlewares to configure a route
builder.MapMiddlewareGet("/api/v1/user", appBuilder => {
appBuilder.Use(Middleware1);
appBuilder.Use(Middleware2);
appBuilder.Use(RequestValidationMiddleware);
appBuilder.UseMvc(); // use a MVC here ...
});
builder.MapMiddlewarePost("/api/v1/user", appBuilder => {
appBuilder.Use(Middleware1);
appBuilder.Use(Middleware2);
appBuilder.Use(RequestValidationMiddleware);
appBuilder.UseMvc();
});
// ....
return builder.Build();
}
Just for a demo , the Middleware1 is a dummy middleware that adds a HttpContext.Items['mw-message1']:
private Func<RequestDelegate, RequestDelegate> Middleware1 = next=> {
return async context =>
{
context.Items["mw-message1"] = "mw1";
await next(context);
};
};
the Controller is a plain controller that will retrieve the HttpContext.Items["mw-messages1"]:
[Route("api/v1/[controller]")]
[ApiController]
public class UserController : ControllerBase
{
public IActionResult Index()
{
var x = (string)HttpContext.Items["mw-message1"];
return new JsonResult(new {
MW1 = x,
Hello= "Hello",
});
}
}
and now , when make a Get request to /api/v1/user , the final response is :
{"mW1":"mw1","hello":"Hello"}
I am using below code in for .net core 3 webapi.
add below in startup.cs configure method to add middleware for specific route
//Middleware to check Authorization key is present in the request header
//Map to all routes
_ = app.UseHeaderKeyAuthorization();
//Map to all routes
_ = app.MapWhen(context => context.Request.Path.StartsWithSegments("/api/v1.0"), appBuilder =>
{
_ = appBuilder.UseHeaderKeyAuthorization();
});
create middleware HeaderKeyAuthorizationMiddleware, sample below
//HeaderKeyAuthorizationMiddleware
public class HeaderKeyAuthorizationMiddleware
{
private readonly RequestDelegate next;
public HeaderKeyAuthorizationMiddleware(RequestDelegate next)
{
this.next = next;
}
public async Task Invoke(HttpContext httpContext)
{
var authHeader = httpContext.Request.Headers[ApiConstants.AuthHeaderName];
//check authHeader logic
if (!string.IsNullOrEmpty(authHeader))
{
await next.Invoke(httpContext);
return;
}
//Reject request if there is no authorization header or if it is not valid
httpContext.Response.StatusCode = 401;
await httpContext.Response.WriteAsync("Unauthorized");
}
}
//Middleware extension to register middleware
public static class HeaderKeyAuthorizationMiddlewareExtension
{
public static IApplicationBuilder UseHeaderKeyAuthorization(this IApplicationBuilder app)
{
if (app == null)
{
throw new ArgumentNullException(nameof(app));
}
return app.UseMiddleware<HeaderKeyAuthorizationMiddleware>();
}
}
I am trying to find a way to prevent my aspnetcore application to add "?ReturnUrl=" to the URL. Does anyone know how to do it, using some kind of middleware.
I tried doing it like below but it did not have any effect:
public class RequestHandlerMiddleware
{
private readonly RequestDelegate _next;
public RequestHandlerMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
if(context.Request.QueryString.HasValue && context.Request.QueryString.Value.Contains("?ReturnUrl="))
{
context.Request.QueryString = new QueryString(string.Empty);
}
await _next.Invoke(context);
}
}
public static class RequestHandlerMiddlewareExtension
{
public static IApplicationBuilder UseRequestHandlerMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<RequestHandlerMiddleware>();
}
}
Registration in startup.cs:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/error");
}
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseAuthentication();
app.UseRequestHandlerMiddleware();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller}/{action=Index}/{id?}");
});
}
Lastly, I have also tried some (tweaked) approaches from the older post regarding the same issue for .NET frameworks here (on stackoverflow) but also failed
Edit: I am not using any additional AuthorizationAttribute / Handler other then the 'standard' [Authorize] attribute. Only:
services.AddAuthorization();
Edit 2: I totally forgot that I also register a portion of the startup elsewhere in the application since it is shared:
public static IServiceCollection Load(IServiceCollection services, IConfiguration config)
{
services.AddDbContext<SqlContext>(options =>
{
options.UseSqlServer(config.GetConnectionString("DefaultConnection"));
});
services.AddIdentity<User, Role>(options =>
{
options.Lockout = new LockoutOptions
{
AllowedForNewUsers = true,
DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30),
MaxFailedAccessAttempts = 5
};
})
.AddEntityFrameworkStores<SqlContext>()
.AddDefaultTokenProviders()
.AddUserStore<UserStore<User, Role, SqlContext, Guid>>()
.AddRoleStore<RoleStore<Role, SqlContext, Guid>>()
.AddUserManager<ApplicationUserManager>();
services.Configure<IdentityOptions>(options =>
{
options.Password.RequireDigit = false;
options.Password.RequiredLength = 5;
options.Password.RequireLowercase = true;
options.Password.RequireUppercase = false;
options.Password.RequireNonAlphanumeric = true;
});
services.ConfigureApplicationCookie(options =>
options.Events = new CookieAuthenticationEvents
{
OnRedirectToLogin = ctx =>
{
if (ctx.Request.Path.StartsWithSegments("/api") &&
ctx.Response.StatusCode == (int)HttpStatusCode.OK)
{
ctx.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
}
else if (ctx.Response.StatusCode == (int)HttpStatusCode.Forbidden)
{
ctx.Response.StatusCode = (int)HttpStatusCode.Forbidden;
}
else
{
ctx.Response.Redirect(ctx.RedirectUri);
}
return Task.FromResult(0);
}
});
return services;
}
The first thing that comes to mind is :
[HttpGet]
public IActionResult LogIn()
{
if (!string.IsNullOrEmpty(Request.QueryString.Value))
return RedirectToAction("Login");
return View();
}
Which will remove QueryString part from the URL so that "ReturnUrl" will not stay on user address-bar for long and will reject any QueryString.
Better workaround would be creating your own version of AuthorizeAttribute which will not put a ReturnUrl in QueryString but it seems with new policy based authorization approach coming around, customizing AuthorizeAttribute is discouraged. more
It might be also possible with policy based approach and creating a custom AuthorizationHandler.
(I will post an update as soon as I try it out)