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
Related
I have a role system where the Admin can create new roles and grant Read, Write, Edit and Delete rights based on the page menu (each page menu has it's own controller) then assign that role to the user.
Users can also have multiple roles but i got that covered. The only problem I am facing is this: since Role assigning can be done dynamically from within the application i can't use the [Authorize(Roles = Role.Admin)] attribute over controller actions.
Instead i was thinking of creating [Read], [Write], [Edit] and [Delete] attributes that i would put over the actions to let me know what that action is for and then allow or deny users to call that action.
Would this be the correct approach? What would i need to have in those custom attributes and how would i allow/deny user to call them? Anyone have any similar experience?
Let's say i have Home and Admin controller and Role1 and Role2 with following rights:
Would something like the above approach works? How do I define custom access for controller actions?
I want to avoid having all the actions in the database and simplify the administration on the site.
In this way administration can be done on R/W/E/D flags on controller level instead of Role1 can all Home/Index, Home/GetRecords etc... action level.
I have same requirement for my project. In my project I have to allow user to access some pages and some pages to admin. Mostly admin can access everything, but I have to block user to access some pages/Action. I did below thing.
a. Create one class to Authenticate user/admin.
b. Create one class for User and inherited that class from "ActionFilterAttribute", and override the OnActionExecuting method.
c. Create one class for Admin and did samething as mentioned in "b", but for admin.
d. put the Authentication class name above the class name or method depending on access.
see sample code(step b). I removed some code, but you can get the idea.
public class AuthenticateUser : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext context)
{
//Do session check.
if (HttpContext.Current.Session["Id"] == null || String.IsNullOrEmpty(HttpContext.Current.Session["Id"].ToString()))
{
HttpContext.Current.Response.StatusCode = HttpStatusCode.Forbidden.GetHashCode();
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
filterContext.Result = new JsonResult { Data = new { Status = HttpStatusCode.Forbidden, LogonRequired = true, result = "Session Expired" }, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
}
else
{
//redirect to login page
UrlHelper oUrl = new UrlHelper(HttpContext.Current.Request.RequestContext);
string s = oUrl.Action("", "UserInfo/");
HttpContext.Current.Response.Redirect(s);
}
}
//If usertype is User then allow it. If user type is admin then return redirect.
//Redirect code if admin
UrlHelper oUrl = new UrlHelper(HttpContext.Current.Request.RequestContext);
string s = oUrl.Action("", "UserInfo/");
HttpContext.Current.Response.Redirect(s);
}
}
I would define it differently, just give each user a set of roles.
Define each user with more than one role, if someone has access to write, you set a role for him to write, if he can also read you can add another role - read.
Now when you define your actions you can use this format[Authorize(Roles = Role.Read)]. Set each action by the access right it requires and you are done.
Use claims. each public controller action claim that you need to define.
Then have your roles defined by the list of claims/operations they can do.
Here's a great explanation here Role-based access control (RBAC) vs. Claims-based access control (CBAC) in ASP.NET MVC
I have three types of roles for each of the menu links.
When the Billing guy is logging into the site
how can I determine dynamically the partial.html file that is shown in the content area?
I can not hardcode the content to the first actionlink in the menu, that means that always the Administration is loaded initially.
What can I do in such a case?
These types of decisions are best made in the Controller.
Example:
public HomeController: Controller
{
public ActionResult Administration()
{
// Determine the user's role.
// "GetRole()" does not really exist on the controller - use your own method.
string role = GetRole();
if (role == "Billing Guy")
return View("AdministrationBillingGuy")
else if (role == "SalesGuy")
return View("AdministrationSalesGuy")
else
return View();
// etc.
}
}
I can think of several ways to do this.
if you need all users to get the same url/action then you could do something like this
public ActionResult Custom(RoleEnum userRole)
{
switch(userRole)
{
case RoleEnum.Admin:
.....
return Partial("_adminPartial", viewModel);
// rest of you cases here
}
}
OR:
public ActionResult Custom(RoleEnum userRole)
{
var view = GetViewByRole(userRole);
// where GetViewByRole takes the enum and
// returns a string with the name of the partial
return Partial(view, viewModel);
}
Another way to do this is, and one that I'd recommend is to make an MVC Area for each user requiring a different layout and then at login you can redirect them to the proper Area, I recommend it because it allows for deeper differentiation between roles in the UI layer.
Another way to achieve the different layouts (am talking about MVC Layout Pages similar to ASP.Net Master pages) is to pass a string Layout to the view, using the ViewBag or any other method you like, then in the Razor code you could do something like this:
#model MyViewModel
#{
Layout = (string)ViewBag.Layout;
}
I leaved this last one for last as it appears a bit hacky to me. Hope this helps you
Well, you haven't provided enough information give any explicit direction, but generally, you should just alter your login post action to redirect to a different place depending on some identifying factor like a role (following is pseudocode)
// do login
if (user is "Billing")
{
// redirect to billing action
}
// etc.
The only reason you should be switching out partials or views is if you're doing a SPA (single page application) and utilizing JavaScript for routing. In that case, you would just need some endpoint you could hit with AJAX to get the user's "role".
However, I don't think that's what you're actually doing. If you're just using MVC directly, then you should be actually changing the URL, not just loading a different Razor 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.
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
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>
}