How to handle authorization in the view layout - c#

Authorize attribute are good to do some access control base on Action but suppose that I have some UI element in the layout that should note be output unless the user is authorize.
I could possibly set some boolean in the ViewBag but that is not the good solution I guess.
Somewhere in the Layout.cshtml:
#if (ViewBag.IsAuthorized)
{
<li>#Html.ActionLink("Index", "Admin")</li>
}
Let me know if there is a better solution.
Thanks.

Use the WebPageRenderingBase.User object; assuming you've earlier set the user into the HttpContext, or on the Controller (which you really should be). Since you're using the Authorize attribute I'm thinking there must be a User - so hopefully the following should work.
This User can be accessed in Razor very easily:
#User.Identity.Name
Would output the current user's name. So an if block that runs only if the user is authenticated would be:
#if(User.Identity.IsAuthenticated)
{
Hello
}
Outputs "Hello" if the user is authenticated.
Thanks to James below for reminding me that you can check IsAuthenticated off the User object - I couldn't find it initially - but then remembered it's on the Identity!

You can make a helper method and call that from the layout.
#Helper.IsAuthorize()

you can call a function that verifies if the user is authenticated:
Helper:
public bool checkUser(string user)
{
//User is allowed?
return true/false;
}
Layout:
#if (checkUser(User.Identity.Name)
{
<li>#Html.ActionLink("Index", "Admin")</li>
}

Related

How does WebSecurity.IsAuthenticated check if you're logged in or not?

This is probably a stupid question, but I've looked pretty hard on Google and couldn't come up with the answer.
I'm creating a website where the database is in another continent, so speed is a crucial issue.
From what I understand,
WebSecurity.Login(form.userName, form.password))
initially checks the database it's initially set up with and logs you in if the username and pw are correct.
Now for every backend function I'm writing, I'm sticking a
[Authorize]
attribute and a
if (WebSecurity.IsAuthenticated)
{ .... }
before performing any action. So does the WebSecurity.IsAuthenticated check the database at all to check if it is logged in or not? I just need to know for speed reasons.
Also is it redundant to put the [Authorize] and WebSecurity.IsAuthenticated in EVERY backend method?
Thanks for any help and opinions
So does the WebSecurity.IsAuthenticated check the database at all to check if it is logged in or not?
No, it just checks if the principal object in current request has the authentication flag set to true.
Usually the principal object is set by an authentication module, there are few different modules. Most use cookies to persist the information of the authenticated user (e.g. Forms, SessionAuthentication) and if the cookie is present and it's valid, the module sets the principal for the request which you can get by calling:
HttpContext.Current.User
in any method of your code (assuming the call is made from a web app that sets the HttpContext.Current).
Some authentication modules can rely on other authentication factors, for example the Windows authentication relies on NTLM/Kerberos protocols which in turn rely on specific headers rather than cookies.
Also is it redundant to put the [Authorize] and WebSecurity.IsAuthenticated in EVERY backend method
Yes and no.
What you most probably mean by "every backend method" is you mean a controller/action method in an MVC app. If this is so then, yes, you don't have to repeat both in a controller/action method.
But in any other method in your backend that is not a controller/action, the WebSecurity.IsAuthenticated still works while the Action attribute doesn't.
Thus, if by "every method" you literally mean every possible method, then the answer is no, these two are not redundant. One works always, the other - only in MVC controllers.
In addition to what #Wiktor Zychla has said, it is useful to note that WebSecurity.IsAuthenticated is functionally identical to Request.IsAuthenticated; to be precise, it's a wrapper:
namespace WebMatrix.WebData
{
//other class content omitted for brevity
public static class WebSecurity
{
//Context
internal static HttpContextBase Context
{
get { return new HttpContextWrapper(HttpContext.Current); }
}
//Request
internal static HttpRequestBase Request
{
get { return Context.Request; }
}
//WebSecurity.IsAuthenticated
public static bool IsAuthenticated
{
get { return Request.IsAuthenticated; }
}
}
}
So if you put all of the above together, WebSecurity.IsAuthenticated is equal to HttpContextWrapper(HttpContext.Current).Request.IsAuthenticated under the hood.
Aside: As correctly stated in the other answers and comments, [Authorize] is used to specify access to controller and action methods:
Specifies that access to a controller or action method is restricted to users who meet the authorization requirement. (source)
So IsAuthenticated works on both action methods and non-action methods, while [Authorize] only works on controllers and action methods, making it indeed redundant to use both on action methods.

MVC Display Authenticated User Information on Authenticated pages

I have an ASPX MVC 4 C# web application that has user forms authentication. Once the user logs in, I would like to display a Welcome [user] message on any authenticated page. I know that User.Identity.Name pulls the user name, but I want to grab info from an additional field which would require a custom query.
How do I go about displaying the Welcome message on all pages?
I made an attempt at using a Partial file, but that got me no where. This should be one of the easier things... to variably pass a string onto every page based off logged in user, but from my searching it is not.
I would normally provide some of my code but I'm not sure there is really much to show, more or less I need a pointer or good example in the right direction.
Much appreciated
To get additional fields on a user object you can use the following:
Membership.GetUser(UserName)
and stores the message in a viewbag which you can use on all you views.
You can store the information in Session, screw ViewBag. You can set the Session Propert in the Global.asax file. You should see and OnSessionStart method inside the Global.asax.
So you can say
protected void Session_OnStart()
{
//Whatever is defaulted here
System.Web.HttpContext.Current.Session["blah"] = "Your User Name"
}
and then in the Shared Layout folder _Layout which is the default "Master Page" if you wanna call it that. You can call it like this whereever you like
#String.Format("{0}",System.Web.HttpContext.Current.Session["blah"]);
Edit:
An easy way you can use session variables is to create a Session variable class.
namespace YourSession
{
public static class SessionProperties
{
public static UserAccount UserAccountx
{
get
{
return (UserAccount)HttpContext.Current.Session["UserAccount"];
}
set
{
HttpContext.Current.Session["UserAccount"] = value;
}
}
}
}
And then in your onStart() method you can say
YourSession.SessionProperties.UserAccountx = "Get User Account Method or w.e";
Then in your view it would be
#String.Format("{0}",YourSession.SessionProperties.UserAccountx);
Although C Sharper pointed out a potential solution, that at first I thought worked, I decided it wasn't the exact solution I was looking for. Reason being if I logged out and then back in as a new user in the same session, the session was not updating as the session was already loaded.
Here is what I did:
Layout Master File
<% if (Request.IsAuthenticated) { %>
<div class="welcome">Welcome, <%: Html.Action( "GetUserInfo", "Member" ) %></div>
<% } %>
GetUserInfo is an ActionResult within the Member Controller
Member Controller
public ActionResult GetUserInfo()
{
string userInfo = "";
using (EntityObject db = new EntityObject())
{
var account = db.table_name.FirstOrDefault(u => u.UserID == User.Identity.Name);
userInfo = account.UserDataToDisplay;
}
return Content(userInfo);
}
*I did change actual item names to be more generic for description purposes.
Upon doing this it worked exactly as I wanted. I have one method under one controller, and one line of code on the master page that upon a user being authenticated, displays the relevant information.
Simple and Easy. Just took a while to figure it out.
Well you can use Cookies instead, they work same as session just they do not overload the server side. you can make them go expire when desired as well

Best Way To Access User Permissions From View

In my ASP.NET MVC site, my set up allows users to have roles, and roles have permissions. Generally, these permissions are set for a controller. In my site's main navigational menu, an Authenticated user can see all items, even if they aren't authorized to access that page.
Currently I can only configure the menu based off if the user is authenticated:
#if (Request.IsAuthenticated){ }
I'm wondering, what's the best way to pass the user's permissions to a view, only for the sake of configuring the menu for that user? Is there some common way of doing it, or will I have to implement this myself? I haven't found much information on it, but maybe I'm using the wrong search terms.
Thanks for any advice.
EDIT
Sorry I may not have been clear enough. This is my main nav menu, in the _Layout page. Also, permissions assigned to a role are very configurable by an admin (they can also create and delete roles), so checking if the user is in a role won't meet my needs.
You could create an action in say, the CommonController, which returns a partial view containing your navigation. This partial view can have its own model which can be populated from the controller. This allows you to use dependency injection for instance.
The action could look like this:
[ChildActionOnly]
public ActionResult Navigation()
{
var model = new NavigationModel();
// populate the model..
return PartialView("_Navigation", model);
}
You can render this partial in your view (_Layout.cshtml in your case) like this:
#Html.Action("Navigation", "Common")
For most cases, Request.IsAuthenticated is just fine. Only use this if you need something more advanced.
You can use Roles class static method IsUserInRole:
#if (Roles.IsUserInRole("Admin"))
{
// ...
}
The best way would be to have a property on the viewmodel that the view uses.

How do I check to make sure the customer has done a task before they visit any page

I am using the Membership provider on a MVC Razor website.
After the customer creates an account and then logs in, I need to make sure they add a system account(s) to their login otherwise the following pages will have issues.
Here is what my page looks like:
As you can see, they can click on any of the tabs at the top and circumvent this screen.
What is the best way to handle this?
Should I disable the tabs? If so, where would I disable them? Or should I do a check on each page and redirect them back to this page?
Thanks for the help!
You should check whether that information has been entered before loading any other page. (probably in an action filter)
If you just disable the links, malicious users can navigate directly to the URLs.
Use RedirectToAction() if they have not created one e.g.
public ActionResult OrderGas(){
// do check here to see if they have system account
if (!hasSystemAccount()){
// this will re-display the add another account page each time
return RedirectToAction("AddAnotherAccountAction");
}
//other wise continue;
return view("OrderGas");
}
Alternatively you can use javascript to hide the buttons depending on a model
public ActionResult OrderGas(){
// do check here to see if they have system account
Boolean hasAccount = this.hasSystemAccount();
// apply to the model
model.hasSystemAccount = hasAccount;
return view("OrderGas", model);
}
Then your jquery can check this value and hide the links accordingly
if($('#hasSystemAccount').val().toLower() = "false"){
$('.myLinkClass').hide();
}
Have you considered using an additional Membership ROLE which indicates a customer has added the 'system account' information, such as CustomerWithSystemAccountInfo.
Then you can protect the controller actions with [Authorize(Roles = "CustomerWithSystemAccountInfo")]
As far as hiding or disabling the menu options in _layout based on ROLE the following article presents a way of doing it that I quite like:
http://techbrij.com/981/role-based-menu-asp-net-mvc

ASP.NET MVC: What is the correct way to redirect to pages/actions in MVC?

I am fairly new to MVC but not sure exactly which Redirect... replaces the standard redirect used in WebForms is the standard Response.Redirect()
For instance, I need to redirect to other pages in a couple of scenarios:
WHen the user logs out (Forms signout in Action) I want to redirect to a login page.
In a Controller or base Controller event e.g. Initialize, I want to redirect to another page (AbsoluteRootUrl + Controller + Action)
It seems that multiple redirects get called in some cases which causes errors, something to do with the fact a page is already being redirected? How can cancel the current request and just redirect?
Update:
The answer to this question (System.Web.Mvc.Controller Initialize) indicates that Initialize should not be used and OnActionExecuting should be used?
Any comments on why Initialize should not be used or why OnAuthorization is not a better option?
More Info:
This blog post (http://blog.wekeroad.com/blog/aspnet-mvc-securing-your-controller-actions/) indicates that OnActionExecuting is useful for authentication (as indicated in the link above) I guess adding this to that event in the base Controller class is fine as every page runs an Action in MVC so shouldn't make much difference and having the ability to redirect should be easier. This does make sense, but it also seems to make sense to me that things could be done in an event before this event and makes we question what those events are for? Will be giving OnActionExecuting a go..
1) When the user logs out (Forms signout in Action) I want to redirect to a login page.
public ActionResult Logout() {
//log out the user
return RedirectToAction("Login");
}
2) In a Controller or base Controller event eg Initialze, I want to redirect to another page (AbsoluteRootUrl + Controller + Action)
Why would you want to redirect from a controller init?
the routing engine automatically handles requests that come in, if you mean you want to redirect from the index action on a controller simply do:
public ActionResult Index() {
return RedirectToAction("whateverAction", "whateverController");
}
1) To redirect to the login page / from the login page, don't use the Redirect() methods. Use FormsAuthentication.RedirectToLoginPage() and FormsAuthentication.RedirectFromLoginPage() !
2) You should just use RedirectToAction("action", "controller") in regular scenarios..
You want to redirect in side the Initialize method? Why? I don't see why would you ever want to do this, and in most cases you should review your approach imo.. If you want to do this for authentication this is DEFINITELY the wrong way (with very little chances foe an exception)
Use the [Authorize] attribute on your controller or method instead :)
UPD:
if you have some security checks in the Initialise method, and the user doesn't have access to this method, you can do a couple of things:
a)
Response.StatusCode = 403;
Response.End();
This will send the user back to the login page.
If you want to send him to a custom location, you can do something like this (cautios: pseudocode)
Response.Redirect(Url.Action("action", "controller"));
No need to specify the full url. This should be enough.
If you completely insist on the full url:
Response.Redirect(new Uri(Request.Url, Url.Action("action", "controller")).ToString());
RedirectToAction("actionName", "controllerName");
It has other overloads as well, please check up!
Also, If you are new and you are not using T4MVC, then I would recommend you to use it!
It gives you intellisence for actions,Controllers,views etc (no more magic strings)

Categories