Redirect to login page when click the tab - asp.net-core

I'm very new in ASP.Net Core.
Let say I have three tabs such as Home, contact and about.
The user can only access contact and about page if they are login. Otherwise, they cannot access the page. My question is, if the user is not login yet, how to redirect to the login page if they click the Contact or about tab?

Before you go into the answer, it might be to your benefit to read through the great documentation available at the official Microsoft Docs.
As a simple solution, I would suggest you add authorization by using the AuthorizeAttribute.
If your project is using MVC
public class HomeController : Controller
{
public ActionResult Index()
{
}
[Authorize]
public ActionResult About()
{
}
[Authorize]
public ActionResult Contact()
{
}
}
Alternatively, if your project is using RazorPages
[Authorize]
public class AboutModel : PageModel
{
...
}

Related

How do I get Route attribute to work in .net core api?

So I added a controller to a blank asp.net CORE Api.
public class IsAliveController : ControllerBase
{
[HttpPost]
[HttpGet]
[Route("isalive")]
public object Get()
{
return "I'm alive";
}
}
Then I try to access it via https://localhost:44361/isalive
and I get no response. Do I need to make some modifications to my Startup.cs?
First why have you declared your method both as a get and a post request? you can remove the post attribute.
By default your routing must start with your controller name, add this:
[Route("[controller]")]
[ApiController]
public class IsAliveController : ControllerBase
{
[HttpGet]
public object Get()
{
return "I'm alive";
}
}
Now when you call https://localhost:44361/isalive you will receive the expected response.
There are two solutions to your problem:
#1 Your controller Name is IsAlive and you have added a route attribute on your action method as isAlive, so this would work only if you call using this Url
https://localhost:44361/isalive/isalive
#2 Remove the Route attribute from the action method
public class IsAliveController : ControllerBase
{
[HttpGet]
public object Get()
{
return "I'm alive";
}
}
and you will be able to access using Url
https://localhost:44361/isalive
Found the issue. The template I choose (using Visual studio 2019) was:
Asp.net core web app > Web Application
The startup file in this template is missing a line that I needed to add:
app.UseEndpoints(endpoints =>
{
//Add this line
endpoints.MapControllers();
});
After adding that line the endpoint works without any changes to the controller.

IdentityServer4 How can I redirect after login to the revious url page without registering all routes at IdP

As recommend I would have register the authorize callback url/redirect_url at IdP, which it works.
But what if a client using MVC app tries to access a page with an unauthorized state, will be redirect to idsrv login page.
The redirect_url is always (Home page entry point) as configured.
To change this behavior I would have to register all possible routes at IdP.
That can not a be solution!
On idsrv Login method I have tried:
Login(string returnUrl)
checking the value from returnUrl it gives /connect/authorize/callback?client_id=...
Shouldn't returnUrl have the url of the previous page? Like in a normal mvc app has..
I have tried to get Referer store it on session and then redirect..
if (!string.IsNullOrEmpty(Request.Headers["Referer"].ToString()))
{
this.httpContextAccessor.HttpContext.Session.SetString("Referer", Request.Headers["Referer"].ToString());
}
But that doesn't work Referer comes null...
I have checked what's coming on context from interation services
var context = await _interaction.GetAuthorizationContextAsync(model.ReturnUrl);
context.RedirectUri
And returns /signin-oidc/ this is the automated way for returning (Home page entry point).
Any chance to get the previous url, so that the user can be redirect?
So what can I do else?
I'm using Hybrid flow to manage the following clients : mvc-app, classic-asp, web api
Here's an example of implementation allowing you to achieve what you want. Keep in mind that there's other ways of doing it.
All the code goes on your client, the server never knows anything about the end url.
First, you want to create a custom attribute that will be decorating all your actions/controllers that you want to protect:
using System;
using System.Web.Mvc;
namespace MyApp
{
internal class MyCustomAuthorizeAttribute : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
if (filterContext.Result is HttpUnauthorizedResult)
{
filterContext.RequestContext.HttpContext.Session["oidc-returnUrl"] = filterContext.RequestContext.HttpContext.Request.UrlReferrer?.PathAndQuery;
}
}
}
}
And then you are going to create a login route/action that will handle all your authorize requests:
using System.Web.Mvc;
namespace MyApp
{
public class AccountController : Controller
{
[MyCustomAuthorize]
public ActionResult Login()
{
returnUrl = Session["oidc-returnUrl"]?.ToString();
// clean up
Session["oidc-returnUrl"] = null;
return Redirect(returnUrl ?? "/");
}
}
}
The login path can be changed in your startup code:
public class Startup
{
public void Configure(IApplicationBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
LoginPath = "/my-login"
});
app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions
{
// setting up your client
});
}
}

How can I implement multiple forms using a single view?

I am having a scenario where I need to implement two forms using a single view... There will be a home page having a form each for LogIn and SignUp (similar to Facebook homepage). I created a view for my home page (Index.cshtml) that contains the razor code for both my forms.
[#using (Html.BeginForm("LogIn", "Home", FormMethod.Post))]
[#using (Html.BeginForm("SignUp", "Home", FormMethod.Post))]
However, upon clicking the 'Log In' button for LogIn form or clicking 'Sign Up' button for SignUp form, the runtime throws an error basically saying that I still need to create views for both LogIn and SignUp actions, even though I have already implemented the HTML forms in my index.cshtml
[NOTE: I am not using ASP.NET membership provider. And this question is generally for two forms, can be any two forms.]
So my question is: Do I really need to create two more views named LogIn.cshtml and SignUp.cshtml? Won't this cause code duplication? I'm quite new to MVC 4 and I hope you understand what I'm trying to do here, so all I want to know is whether there is any other way to implement this? (jQuery, AJAX or something)
public class HomeController : Controller
{
[HttpGet]
public ActionResult Index()
{
return View();
}
[HttpGet]
public ActionResult LogIn()
{
return View();
}
[HttpPost]
public ActionResult LogIn(Account acc)
{
// some code
return View();
}
[HttpGet]
public ActionResult SignUp()
{
return View();
}
[HttpPost]
public ActionResult SignUp(Account acc)
{
// some code
return View();
}
}
You could specify the view you want to be returned:
[HttpGet]
public ActionResult SignUp()
{
return View("LogIn");
}

Routing GET and POST routes in ASP.NET MVC 4

I am trying to setup a Login form in an ASP.NET MVC 4 app. Currently, I have configured my view as shown here:
RouteConfig.cs
routes.MapRoute(
"DesktopLogin",
"{controller}/account/login",
new { controller = "My", action = "Login" }
);
MyController.cs
public ActionResult Login()
{
return View("~/Views/Account/Login.cshtml");
}
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginModel model)
{
return View("~/Views/Account/Login.cshtml");
}
When I attempt to visit /account/login in the browser, I receive an error that says:
The current request for action 'Login' on controller type 'MyController' is ambiguous between the following action methods:
System.Web.Mvc.ActionResult Login() on type MyApp.Web.Controllers.MyController
System.Web.Mvc.ActionResult Login(MyApp.Web.Models.LoginModel) on type MyApp.Web.Controllers.MyController
How do I setup a basic form in ASP.NET MVC 4? I've looked at the sample Internet App template in ASP.NET MVC 4. However, I can't seem to figure out how the routing is wired up. Thank you so much for your help.
I haven't tried this yet but can you try annotating your Login actions with the appropriate Http Verb - I'm assuming that you're using a GET for viewing the login page and a POST for processing the login.
By adding [HttpGet] for the first action and [HttpPost] for the second action the theory is that ASP.Net's routing will then know which Action method to call based upon which method has been used. Your code should then look something like this:
[HttpGet] // for viewing the login page
[ViewSettings(Minify = true)]
public ActionResult Login()
{
return View("~/Views/Account/Login.cshtml");
}
[HttpPost] // For processing the login
[ViewSettings(Minify = true)]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginModel model)
{
return View("~/Views/Account/Login.cshtml");
}
If this doesn't work, consider having two routes and two differently named actions like below:
routes.MapRoute(
"DesktopLogin",
"{controller}/account/login",
new { controller = "My", action = "Login" }
);
routes.MapRoute(
"DesktopLogin",
"{controller}/account/login/do",
new { controller = "My", action = "ProcessLogin" }
);
There are other similar questions and answers on StackOverflow already, take a look at: How to route GET and DELETE for the same url and there is also the ASP.Net documentation which might also help.

ASP.Net/MVC Authorize Vs Authenticate

So I set this above my Controller:
[Authorize(Roles="Administrator")]
The problem is whether they are not logged in, or don't have the right role, it redirects them to the login page. Is there a way to have it handle authorization and authenticate differently?
I might not understand you clearly, but authentication and authorization are always coming together.. One says which mechanism use to authenticate user (forms, windows etc.), and second which roles or users are allowed to see the content...
As far as authentication method is set in your web config it is fixed, and only think you can use to protect your controller methods is to put those attributes.
Also if you want to use it diffrently, f.e. redirect to diffrent page you can use following code:
public class RedirectAuthorizeAttribute : AuthorizeAttribute
{
public string RedirectUrl { get; set; }
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
filterContext.Result = new RedirectResult(RedirectUrl);
}
}
and then put it onto your controller method like that:
[RedirectAuthorize(Roles = "MyRole", RedirectUrl = "SomeUrl")]
public ActionResult SomeAction()
{
...
}