I have an API REST .NET 7 and the attribute [OutputCache] is not caching even in a endpoint without authorization
I added this:
services.AddOutputCache(options =>
{
options.AddBasePolicy(builder => builder.Cache()); //removing this line doesn't work either
});
And then in Configure():
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
app.UseOutputCache(); //putting it higher doesn't work either
My endpoint looks like this:
[AllowAnonymous]
[OutputCache(Duration = 99999)]
[HttpGet]
public async Task<IActionResult> GetAsync([FromQuery] Dto dto) => ReturnDataFromDataBase();
But it doesn't work.
I followed the documentation https://learn.microsoft.com/en-us/aspnet/core/performance/caching/output?view=aspnetcore-7.0
Edit:
I add more information, this project was an .net 5 and recently updated to .net 7 ([OutputCache] was introduced in .net 7, that is what I understood). It doesn't work because every time I make a request (with Postman) to this endpoint it enters the ReturnDataFromDataBase method (I put a breakpoint).
I can't share my project because it's not mine, but this is the Configure method of startup (feel free to correct me):
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IApiVersionDescriptionProvider provider)
{
//app.UseCors(builder => builder.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod());
app.UseCors();
app.UseAuthentication();
app.UseExceptionHandler("/Error");
app.UseIpRateLimiting();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
var pathBase = Configuration["APPL_PATH"];
if (pathBase == "/")
pathBase = "";
if (!string.IsNullOrEmpty(pathBase))
{
app.UsePathBase(pathBase);
}
ServiceProviderResolver.ServiceProvider = app.ApplicationServices;
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
app.UseOutputCache();
}
Edit 2:
If I move app.UseOutputCache() to the first place in Configure() it works, but the documentation says that it must be placed after UseCors() and UseRouting(), in that case it doesn't work.
Edit 3 (Solution for unauthenticated endpoints):
The problem was app.UseMvc(), for some reason all controllers were inheriting from Controller(mvc) and not from ControllerBase, I changed it and then I could remove app.UseMvc() that made it works. I also changed the order like this:
Public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IApiVersionDescriptionProvider provider)
{
app.UseIpRateLimiting();
var pathBase = Configuration["APPL_PATH"];
if (pathBase == "/")
pathBase = "";
if (!string.IsNullOrEmpty(pathBase))
{
app.UsePathBase(pathBase);
}
ServiceProviderResolver.ServiceProvider = app.ApplicationServices;
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors();
app.UseAuthentication();
app.UseAuthorization();
app.UseOutputCache();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
The next problem is that it doesn't work in endpoints that require authentication (jwt token).
The default OutputCache policy don't cache any method with authorize end point. If you want to cache authorized api, you should customered policy to indicate what you want to cache.
the example of output cache policy
public class OutputCacheWithAuthPolicy : IOutputCachePolicy
{
public static readonly OutputCacheWithAuthPolicy Instance = new();
private OutputCacheWithAuthPolicy() { }
ValueTask IOutputCachePolicy.CacheRequestAsync(OutputCacheContext context, CancellationToken cancellationToken)
{
var attemptOutputCaching = AttemptOutputCaching(context);
context.EnableOutputCaching = true;
context.AllowCacheLookup = attemptOutputCaching;
context.AllowCacheStorage = attemptOutputCaching;
context.AllowLocking = true;
// Vary by any query by default
context.CacheVaryByRules.QueryKeys = "*";
return ValueTask.CompletedTask;
}
private static bool AttemptOutputCaching(OutputCacheContext context)
{
// Check if the current request fulfills the requirements to be cached
var request = context.HttpContext.Request;
// Verify the method, we only cache get and head verb
if (!HttpMethods.IsGet(request.Method) && !HttpMethods.IsHead(request.Method))
{
return false;
}
// we comment out below code to cache authorization response.
// Verify existence of authorization headers
//if (!StringValues.IsNullOrEmpty(request.Headers.Authorization) || request.HttpContext.User?.Identity?.IsAuthenticated == true)
//{
// return false;
//}
return true;
}
public ValueTask ServeFromCacheAsync(OutputCacheContext context, CancellationToken cancellation) => ValueTask.CompletedTask;
public ValueTask ServeResponseAsync(OutputCacheContext context, CancellationToken cancellation) => ValueTask.CompletedTask;
}
and then register your policy:
builder.Services.AddOutputCache(options =>
{
options.AddBasePolicy(builder => builder.Cache());
options.AddPolicy("OutputCacheWithAuthPolicy", OutputCacheWithAuthPolicy.Instance);
});
then when you cached output , you should mark it with this policy:
[Authorize] // the end point is authorized
[OutputCache(Duration = 600, PolicyName = "OutputCacheWithAuthPolicy")] // incicate policy name
[HttpGet("GetWeatherForecastWithAuth/{id}/{second}")]
public IEnumerable<WeatherForecast> GetWithAuth([FromRoute] string id, [FromRoute] string second)
ASP.NET Core middlewares process request in order of registration (see more here), so having app.UseOutputCache(); as last element of processing pipeline does not make sense, you should move it before the middleware which output you want to cache (so app.UseOutputCache(); should be called at least before app.UseEndpoints(...)):
app.UseOutputCache();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
Related
In my .net core project, I need to show a maintenance page when we do deployment. so, I have decided to write an action filter and registered globally and set the config value to check when maintenance is on, I will redirect to my maintenance page. The problem is that redirection is happening, but the web page keeps reloading. Please find below code
MyActionFilterAttribute.cs
public class MyActionFilterAttribute: ActionFilterAttribute {
private readonly IConfiguration _config;
public OfflineActionFilterAttribute(IConfiguration config) {
_config = config;
}
public override void OnActionExecuting(ActionExecutingContext filterContext) {
if (filterContext == null) return;
if (bool.Parse(_config.GetSection("Maintenance:Mode").Value) && filterContext.HttpContext ? .Request ? .Path.Value != "/Maintenance") {
// Some logic goes here to satisfy conditions then only the below code should be executed.
filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(new {
controller = "Maintenance",
action = "Index"
}));
}
base.OnActionExecuting(filterContext);
}
}
Startup.cs
In Configure Method,
services.AddMvc(options =>
{
options.Filters.Add(new OfflineActionFilterAttribute(_configuration));
});
Maintenance Controller
public class MaintenanceController : Controller
{
public IActionResult Index()
{
return View();
}
}
The url https://localhost:XXXXX/Maintenance keeps loading.
The question is:
How can I stop redirecting too many times issue. [Please Note: I have checked other stack overflow questions. There it suggests to check specific controller, that does not help in my case].
Is there any other approach to be considered? I have a thought of using Middleware, we can send the response, but I am not sure how I redirect to my .net razor page with dynamic content.
Any help much appreciated.
According to your description, I suggest you could try to use custom middleware. You could directly set the response context path after you checked the config.
More details, you could refer to below codes:
app.Use(async (context, next) =>
{
if ("condition")
{
context.Response.Redirect("/Maintenance/Index");
return;
}
else
{
// Call the next delegate/middleware in the pipeline
await next();
}
});
Update:
Startup.cs Configure method:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseMigrationsEndPoint();
app.UseRewriter(new RewriteOptions().AddRedirectToNonWww());
}
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.UseExceptionHandler("/Home/Error");
app.UseCors(options => options.AllowAnyOrigin().AllowAnyMethod());
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseSession();
app.UseAuthentication();
app.UseAuthorization();
app.Use(async (context, next) =>
{
if (Condition && context.Request.Path != "/error/404")
{
context.Response.Redirect("/error/404");
return;
}
else
{ // Call the next delegate/middleware in the pipeline
await next();
}
});
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
endpoints.MapRazorPages();
});
}
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 have MiniProfiler set up in an ASP.NET Core application. Profiling works fine.
However, I only want Admins to be able to profile.
I have the following in ConfigureServices:
services.AddMiniProfiler(options =>
{
options.ShouldProfile = request =>
request.HttpContext.User.IsInRole("Admin");
});
The problem is, the user identity does not seem to be loaded in that method.
The User.Identity.Name property is null, and there are no claims.
My guess is that this call happens before that info is populated?
How can I profile based on the user identity?
You need to know that according to the docs the ClaimsPrincipal.IsInRole() method checks for Claims of type ClaimsIdentity.RoleClaimType.Be sure you have added the role claims.
Here is a working demo you could follow:
1.Register the user with name a#qq.com successfully.
2.Generate the role and add the role with claims to the user:
public async Task CreateRolesandUsers()
{
bool x = await _roleManager.RoleExistsAsync("Admin");
if (!x)
{
// first we create Admin role
var role = new IdentityRole();
role.Name = "Admin";
await _roleManager.CreateAsync(role);
//must add the claim,otherwise IsInRole would always be false..
_roleManager.AddClaimAsync(role, new Claim(ClaimTypes.AuthorizationDecision, "Admin")).Wait();
}
var user = _userManager.FindByNameAsync(User.Identity.Name).Result;
if (user != null)
{
var result1 = await _userManager.AddToRoleAsync(user, "Admin");
}
}
2.Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<IdentityUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>().AddDefaultUI();
services.AddMiniProfiler(options =>
{
options.RouteBasePath = "/profiler";
options.ShouldProfile = request =>
request.HttpContext.User.IsInRole("Admin");
options.SqlFormatter = new StackExchange.Profiling.SqlFormatters.InlineFormatter();
});
services.AddControllersWithViews();
services.AddRazorPages();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication(); //be sure add this
app.UseAuthorization();
app.UseMiniProfiler(); //add this before UseEndpoints
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
endpoints.MapRazorPages();
});
}
Result:
I´m working on a ASP.NET Core Web API. I´m using the newest version 3.0.0-preview4.19216.2.
I have the problem, that my API-Controller ignores the Authorize-Attribute but on another controller the Attribute works fine.
[Route("api/[controller]")]
[ApiController]
[Authorize(AuthenticationSchemes =JwtBearerDefaults.AuthenticationScheme)]
public class SuppliersController : ControllerBase
{
[HttpGet("GetAll")]
public IActionResult GetAll()
{
var companyId = int.Parse(User.Claims.FirstOrDefault(c => c.Type == "Company_Id").Value); // throws nullreference exception
return Ok();
}
}
But on another controller I have something similar but there the attribute works as expected
[Route("api/[controller]")]
[ApiController]
[Authorize]
public class UsersController : ControllerBase
{
[HttpGet("{id}")]
public IActionResult GetById(int id)
{
var test = User.Claims.FirstOrDefault(c => c.Type == "Company_Id").Value;
}
}
In the user controller works everything fine.
I also tried it in the SupplierController without the
AuthenticationSchemes
but no different.
This is my AddAuthentication in the Startup.cs
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(x =>
{
x.Events = new JwtBearerEvents
{
OnTokenValidated = context =>
{
var userService = context.HttpContext.RequestServices.GetRequiredService<IUserService>();
var userId = int.Parse(context.Principal.Identity.Name);
var user = userService.GetById(userId);
if (user == null)
{
// return unauthorized if user no longer exists
context.Fail("Unauthorized");
}
return Task.CompletedTask;
},
OnAuthenticationFailed = context =>
{
Console.WriteLine(context);
return Task.CompletedTask;
},
OnMessageReceived = context =>
{
return Task.CompletedTask;
}
};
x.RequireHttpsMetadata = false;
x.SaveToken = true;
x.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = false,
ValidateAudience = false
};
});
here is my complete 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 appSettingsSection = Configuration.GetSection("AppSettings");
services.Configure<AppSettings>(appSettingsSection);
AuthenticationService.ConfigureSchoolProjectAuthentication(services, appSettingsSection);
DependencyInjectionService.Inject(services);
services.AddMvcCore()
.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.UseAuthorization();
app.UseAuthentication();
app.UseRouting();
app.UseEndpoints(routes =>
{
routes.MapControllers();
});
}
}
The strange thing is, when my SupplierController is called my authorization logic is not called (checked it with debugger) and when I call my UserController the logic is executed.
I think this is the reason why the claim is null. But why is the logic not called when the controller have a authorization attribute?
It´s seem like my authentication doesn't work entirely because I can access all my controller simply by using no authentication in Postman. What I´m doing wrong here?
Ok I found the anwser in this blog post ASP.NET Core updates in .NET Core 3.0 Preview 4
I have to change the order of my authentication registration from
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseHttpsRedirection();
app.UseAuthorization();
app.UseAuthentication();
app.UseRouting();
app.UseEndpoints(routes =>
{
routes.MapControllers();
});
}
to
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseRouting();
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(routes =>
{
routes.MapControllers();
});
}
So this solve my problem.
In my configuration method, I have the following
...
app.UseStatusCodePagesWithRedirects("/home/login");
app.UseMvcWithDefaultRoute();
When I decorate a method with [Authorize], I get redirected to /home/login. However, I'd also like the user to be sent back to where they came from and in order to do that, I need to pass the origin to the login page like this.
...
string origin = ???
app.UseStatusCodePagesWithRedirects("/home/login?origin=" + origin);
app.UseMvcWithDefaultRoute();
Is is possible to obtain origin somehow there or is my call to UseStatusCodePagesWithRedirects poorly suited? How should I approach it?
first, set up your startup class as shown below
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.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
//-----
services.AddAuthentication(
CookieAuthenticationDefaults.AuthenticationScheme
).AddCookie(CookieAuthenticationDefaults.AuthenticationScheme,
options =>
{
options.LoginPath = "/Account/Login";
options.LogoutPath = "/Account/Logout";
// The ReturnUrlParameter determines the name of the query parameter
// which is appended by the handler
// when during a Challenge. This is also the query string parameter
// looked for when a request arrives on the
// login path or logout path, in order to return to the original url
// after the action is performed.
options.ReturnUrlParameter=origin;//the default value is returnUrl
});
services.AddAuthentication(options =>
{
options.DefaultScheme =CookieAuthenticationDefaults.AuthenticationScheme;
});
//----
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseAuthentication();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
AccountController
public IActionResult Login(string origin)
{
//save original url
ViewBag.Origin = origin;
return View();
}
//get the original url from hide input
[HttpPost]
public IActionResult Login(LoginViewModel model)
{
//if (login successfull)
//{
return Redirect(model.Origin);
//}
// else
//{
return View(model);
//}
}