Allow razor page to be viewed anonymously, but authorize post - c#

I want to allow a page to be viewed by anyone, but only authorized users to be able to submit forms i.e using the post method(s) of a razor page.
However authorize attribute is only applicable at PageModel level, I can either make get + post authorizable or both anonymously accessible.
What is the recommended approach in this scenario?

First, I would only render the form if the user is authenticated:
#if (User.Identity.IsAuthenticated)
{
<partial name="_CommentForm" />
}
Then I would perform the same check in the OnPost handler before processing the form submission to prevent automated or other nefarious submissions:
public async Task<IActionResult> OnPostAsync()
{
if(User.Identity.IsAuthenticated)
{
if(Modelstate.IsValid)
{
// blah blah
}
}
else
{
return BadRequest();
}
}
Or you could post to a different page which is only designed to process the submission and can have the Authorize attribute applied to it

Related

ASP net MVC5 "view validation if only routed from another controller not by typing in address bar"

I have controller where inside are 2 methods , the validation is a code, if it is correct then call the another method in different controller, but there is a problem if someone write in the address bar the controller for example home/sdata/display then it retrieve the data without writing the password(code) how can i prevent to display the data until he writes the code
public ActionResult predata()
{
return View();
}
[Authorize]
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult prerest(string paswd)
{
if (paswd == "123456852")
{
return RedirectToAction("sdata","displays");
}
return View();
}
Do the validation check in the sdata Controller's displays method. If the password not right, redirect to some other page or just display an empty view.
If you add [Authorize] this problem will not exist. Probably you made something wrong with authorization. You should check more about authorization patterns for example Token Based Authentication - OWIND etc.

Custom Authentication and ASP.NET MVC

I have an internal web app being built in ASP.NET 4. We are stuck with using an authentication API built by another team. If a user to the site is authenticated successfully for the site I would like to give them access to the entire site.
In ASP.NET WebForm days I just used to keep a custom User object in session. If that object was null I knew the user wasn't authenticated. Is there a similar but improved method for this in MVC. I don't want to have to build my own provider of the ASP.NET Membership model if possible. What is the simplest way of doing this?
You can use Forms Authentication in conjuction with Authorize attibute as follows,
To restrict access to a view :
Add the AuthorizeAttribute attribute to the action method declaration, as shown below,
[Authorize]
public ActionResult Index()
{
return View();
}
Configuring Forms Authentication in web.config
<authentication mode="Forms">
<forms loginUrl="~/Account/Login" timeout="2880" />
</authentication>
Login Post Action:
Set Authentication cookie if user is valid
[HttpPost]
public ActionResult Login(User model, string returnUrl)
{
//Validation code
if (userValid)
{
FormsAuthentication.SetAuthCookie(username, false);
}
}
Log off Action:
public ActionResult LogOff()
{
FormsAuthentication.SignOut();
return RedirectToAction("Index", "Home");
}
You probably want to have a custom authorization filter. Here's an example: Custom filters in MVC. You can then apply this filter globally on app start (using RegisterGlobalFilters).
public class LegacyAuthorize : AuthorizeAttribute
{
public override void OnAuthorization(HttpActionContext actionContext)
{
if (HttpContext.Current.Session["User"] == null)
base.HandleUnauthorizedRequest(actionContext);
}
}
Then in your global.asax you'd have something like this:
GlobalFilters.Filters.Add(new LegacyAuthorize());
You can try with something like this:
FormsAuthentication.SetAuthCookie(username, rememberMe);
to set the cookie for authenticated user, then just use the [Authorize] attribute on the Controller or Action that need authentication.
Try googling on the subject for further info, you will find a lot of stuff on authentication and authorization in MVC.
Everything you could do in forms you can do in MVC, just set the session variable in the controller login action.
Or you can do this:
In the login action add formsauthentication.setauthcookie("username")
After this any action with the [Authorize] keyword will allow the current user in.
You can do the Session Authentication by simply putting a session variable value when the login is successful. Eg
public ActionResult Index(Models.Login login)
{
if (ModelState.IsValid)
{
Dal.Login dLogin = new Dal.Login();
string result = dLogin.LoginUser(login);
if (result == "Success")
Session["AuthState"] = "Authenticated";
}
return View();
}
Now the trick is that you should have a common layout page of all the views to which you have to check for authentication. And in this layout page just do a razor check like this -
<body>
#if (Session["AuthState"] != "Authenticated")
{
Response.Redirect("~/login");
}
// other html
</body>
I have been using this method in my application admin panel.

ASP.NET MVC Roles and Security

Assume like this is my SampleController action method
public ActionResult AdminView()
{
return View()
}
If want this controller method to be called if the logged in user belongs to admin role, otherwise this method call should be blocked and the user should get an some custom unauthorized access error page.
In my asp .net mvc web application, when the user logs in, I am storing the user role in a session as a string. And whenever there is a need to validate the user role, I compare the value stored in the session against a constant say "ADMIN_ROLE". But I am writing that piece of code to check for the user role in almost every controller action method and then either return an appropriate view for the user or an unauthorized access page view if the user role is restricted for the controller action method.
I googled and read that we can use something like this.
[Authorize(Roles="admin")]
public ActionResult AdminView()
{
return View()
}
But I am not sure how the Authorize and the Roles keyword works. How when putting Roles = "Admin", is going to help in checking my user role string stored in the session, or how I can redirect a user to unauthorized page, in case the role does not match the role tagged for the action method.
As per my thinking you need to code for authorization.
public class AuthorizeAttribute : FilterAttribute, IAuthorizationFilter
{
private readonly RoleEnum[] _acceptedRoles;
public AuthorizeAttribute(params RoleEnum[] acceptedroles)
{
_acceptedRoles = acceptedroles;
}
public AuthorizeAttribute(params bool[] allowAll)
{
if (allowAll[0])
_acceptedRoles = new RoleEnum[] { RoleEnum.Admin, RoleEnum.user};
}
public void OnAuthorization(AuthorizationContext filterContext)
{
if (SessionHelper.UserInSession == null)//user not logged in
{
FormsAuthentication.SignOut();
filterContext.Result =
new RedirectToRouteResult(new System.Web.Routing.RouteValueDictionary {{ "controller", "Home" },
{ "action", "Index" },
{ "returnUrl", filterContext.HttpContext.Request.RawUrl } });//send the user to login page with return url
return;
}
if (!_acceptedRoles.Any(acceptedRole => SessionHelper.UserInSession.UserRoles.Any(currentRole => acceptedRole == currentRole.Role)))
//allow if any of the user roles is among accepted roles. Else redirect to login page
throw new UnauthorizedAccessException();
}
}
This is also work for return URL.
As per comments, if you are using custom authentication/authorization mechanism then you need to implement custom authorize attribute where you can put custom logic to check if user has admin role or not. Something like below:
public class CustomizedAuthorizeAttribute : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
//check for role in session variable "ADMIN_ROLE"
//if not valid user then set
filterContext.Result = new RedirectResult(URL)
}
}
There is a small nice explanation in this link:
http://weblogs.asp.net/jgalloway/archive/2011/04/28/looking-at-how-asp-net-mvc-authorize-interacts-with-asp-net-forms-authorization.aspx
as per this:
ASP.NET MVC includes an [Authorize] attribute, which when placed on any controller actions will forbid unauthorized access. The AuthorizeAttribute allows you to specify a list of roles or users.
You can also place the AuthorizeAttribute on a controller, in which case it will apply to all actions in the controller. Attempting to access an action secured by the AuthorizeAttribute when you're not logged in will take you to a standard LogOn screen, with a link to register if you don't already have an account.
How does the [Authorize] attribute redirect me to Log On?
The AuthorizeAttribute is an ActionFilter, which means that it can execute before the associated controller action. The AuthorizeAttribute performs its main work in the OnAuthorization method, which is a standard method defined in the IAuthorizationFilter interface. Checking the MVC source code, we can see that the underlying security check is really just looking at the underlying authentication information held by the ASP.NET context:
IPrincipal user = httpContext.User;
if (!user.Identity.IsAuthenticated)
{
return false;
}
If the user fails authentication, an HttpUnauthorizedResult ActionResult is returned, which produces an HTTP 401(Unauthorized) status code. If it weren’t for ASP.NET Forms Authentication, an HTTP 401 status code would be sent to the browser, which would show the browser’s default login prompt.

ASP.NET MVC 4 Make a page not directly reachable

I have a ASP.NET MVC 4 Blog which is 90% done but i need one thing - i have a webpage lets say index/secretPage but i want to be able to navigate to this webPage only after i am redirected from another - lets say index/redirect . If the adress is hardcoded it should not navigate, if the visitor is coming from a different link like blog/post/24 it should not be able to navigate too.
I hope my question was clear, than you for all help.
You could also mask the secret page with an action that shows another page if direct called.
In this example there are 2 actions. 'Secret' for returning a bogus view and the 'Check' for the real call. In this action the bool variable 'allowSecret' ist checked an then the user sees the view 'secret.cshtml' if allowed or 'index.cshtml' if not.
Here's an example code for a simple controller with that functionality:
using System.Web.Mvc;
namespace Test.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
return View("Index");
}
public ActionResult Check()
{
// check if user is allowed to show secret page
if(allowSecret == true)
return View("Secret");
// Otherwise return view 'index.cshtml'
return View();
}
public ActionResult Secret()
{
// Always shows view 'index.cshtml' if url is ".../secret"
return View("Index");
}
}
}
You could also redirect to another action after the check fails instead of calling a 'fake-view':
return RedirectToAction("Index")
The difference is the url the user sees in the browser. Returning a view does not change the url, redirecting to another action changes the url to the changed route.
Of course you can place the check in another class behind the controller.
Another option is to use the 'NonAction' attribute:
[NonAction]
public ActionResult Check()
{
...
}
Hope that helps with kind regards,
DD
You can UrlReferrer to get to know who refred to this current page and throw and exception or redirect back
HttpContext.Current.Request.UrlReferrer
http://msdn.microsoft.com/en-IN/library/system.web.httprequest.urlreferrer.aspx
But for what ever reason you need this. It dosenot look like a good design to me.
Hope this helps

Back button takes you back to authenticated page after logout

When user hits back button after logout, they get Document Expired. However, when user click on this message
Click Try Again to re-request the document from the website,
in browser, they are able to access an authenticated page again.
It is because the page is cached. For all secure requests you will need to manually kill the cache. You can do something like this:
public class SecurePageAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
filterContext.HttpContext.Response.Cache.SetExpires(DateTime.UtcNow.AddMinutes(-1));
filterContext.HttpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);
filterContext.HttpContext.Response.Cache.SetNoStore();
}
}
You would then use it in your controllers like so:
[SecurePage]
public ActionResult Index() {
return View();
}
You could also annotate your entire controller or register this globally if the majority of your site is secure.
For a GET Request, you'd expect them to still see the authenticated page on "back" but not be able to interact with it (assuming you use POST for actions).
Since you're talking about a POST Request though (as it's giving you the expired message), it's possible that you're missing the [Authorize] attribute from your controller/action which will allow any unauthenticated user to access it, have you checked this?

Categories