Determine security on shared layout - asp.net-mvc

In my ASP MVC 3 website, I need a way to determine user security on a shared layout page. This layout page houses a navbar that needs to display drop down items based on a user's security level.
Originally I had thought I could make an Ajax call and populate a ViewBag item, then use that to determine what to show/not show. However, this won't work unless I want to put that same method in every controller/method.
Given this set up (navbar located on a shared layout), what is the best method for determining which items to show as the user navigates across different controllers/methods?

You could go two ways about this.
You could do a check in the View:
#if (User.Identity.IsAuthenticated){
// show logged in view
}
else{
// show logged out view
}
Or you could build a ViewModel and populate that from a shared action.
Example:
ViewModel
public class VM
{
public string Text{get; set;}
}
Shared Action on Shared Controller:
public class SharedController{
public PartialViewResult GetMenu(){
VM newvm = new VM(Text = "not logged in");
if (User.Identity.IsAuthenticated){
newvm.Text = "logged in";
}
return PartialView("Shared", newvm);
}
}
A partialview to render this action:
#Model VM
<p>
#model.Text
</p>
And lastly in your view:
#{
Html.RenderAction("Shared", "Shared");
}

You could implement your navbar as a PartialView which is returned by a ChildAction and inserted into the layout using a call to the ChildAction (#Html.Action(...)).
Within the ChildAction, you implement what to display or not depending on the logged in user (User.Identity).
The advantages are that there is only a single action which returns the navbar depending on the authenticated user, and you don't have to worry about any of this when working with your other controllers and their actions.

Related

Can we add Models in Layout.cshtml?

i have layout of 4 pages and at header i need to access name of logged in admin. how to access that database model in admin in starting of layout i have added
#model ProjectName.Models.Admin
and while accessing name from admin i am writing
#Model.Name
it gives error how to do it in proper way to access that attribute in Layout and it cant be partial view it should be layout so kindly help
As #Stephen Muecke stated in his comment on your question, there are more ways how you can do that. I would recommend you to keep your Layout view without model. Otherwise as #Stephen Muecke mentions, you would have to make types of models for each view that uses that layout of either the same or derived type, which would add unnecessary complexity to your code.
So the other way is to call HtmlHelper.Action(...) or HtmlHelper.RenderAction() in your layout view at the place when you'd like to render user's name. Example:
Layout page:
...
<div class="admin-name">
#{ Html.RenderAction("AdminName", "Partial"); }
</div>
...
Add a controller:
public class PartialController : Controller {
[ChildActionOnly] // action cannot be requested directly via URL
public ActionResult AdminName() {
string adminName = ...; // assign value to adminName variable
return Content(adminName);
}
}
You need logged in user details in so many pages in application, so better to store logged in user details in Session and you can retrieve session value in any view/partial view.
Other Solution:
Make your header partial view and call from Layout
Html.RenderAction("actionName", "controllerName")
Create an action method in your controller which returns partial view
Controller Action Method
[HttpGet]
public ActionResult Header()
{
HeaderModel HM = new HeaderModel()
// Your user information in HeaderModel
return PartialView("Header", HM)
}
_layout.cshtml
<body>
<div>
#{Html.RenderAction("Header", "ControllerName");}
</div>
</body>
I hope this will resolve your problem.

using update panel in ASP.NET MVC 4

Please explain me how to create update panel in ASP.NET MVC4 application. I looked for many blogs... but can not find any useful way.
This is my view
How I can separate these actions in same view?
Your two panels don't allow the user to switch between one or the other so I assume that you have an "intro" view with the option to either Sign in or Register. Right? In that case there is no real need for client side panel switching using Javascript/Ajax. Your "intro" view can pass a parameter to the controller action defining whether it needs a Sign In or Register view back.
For instance:
// RouteConfig.cs
routes.MapRoute(
name: null,
url: "login-register/{action}",
defaults: new { controller = "Authentication"},
constraints: new { action = #"(SignIn|Register)" }
);
// AuthenticationController.cs
public ActionResult SignIn()
{
...
return View(); // Will return the Authentication\SignIn.cshtml view
}
public ActionResult Register()
{
...
return View(); // Will return the Authentication\Register.cshtml view
}
Update panel does not really exist in ASP.NET MVC. It used to be there in ASP.NET Web form develeopment world before people actually realized it is better to use hand written jQuery ajax for doing the partial page update.
You may use jQuery ajax methods to post your form data to an action method and do partial page update to the page as needed. You may also consider using Partial view (to return a part of a page) as required.
In your case you can create 2 partial views for Sign in and Register and include those in your main view, to make your code more reusable.
<h1>Login or Register</h1>
<div>
#Html.Partial("Login")
</div>
<div>
#Html.Partial("Register")
</div>

What's a clean/DRY way to show available operations on user content?

Working on an ASP.NET MVC 3 (Razor) application, that's mainly concerned with UGC (user generated content).
I'm working on a "Q&A" area - where users can ask questions, others can answer, vote, etc.
As such, i'm trying to figure out a clean way to handle the available operations a user can do on any given page, based on their role and other factors.
Take the scenario of the "Question Detail Page" (like this page on Stack Overflow).
Any (authenticated) user can:
Vote for question/answer
Answer
Question owner can:
Edit
Delete
Mark answer
And so forth.
Now, i have a QuestionViewModel, that is used to display the question and relevant answers for this particular View.
I create it using AutoMapper.
How can i display "stickies" (e.g hyperlinks) on the page, based on the available operations?
My current thinking is:
I create an enum: QuestionOperation (Answer, Edit, Disable, Vote, Answer, etc)
I add a property of type IEnumerable<QuestionOperation> to my ViewModel
I set this property in my action method (HTTP GET), checking if the user is authenticated and the roles they are a part of.
I then use an editor template to render out each operation as a hyperlink, using Html.ActionLink
Is that considered a clean approach - or can anyone suggest a better one?
Keeping in mind i am re-using this QuestionViewModel on three pages:
The question detail page
The "Ask a question" page
The "Edit a question" page
So because these operations are page/user dependant, it can't really be done with AutoMapper.
I would setup a separate controller and action which will be returning a partial view containing the necessary links. Then I would use the Html.Action helper to include it from the main view.
Something among the lines:
public class UserLinksController: Controller
{
// TODO: ctor DI of a repository, etc...
public ActionResult Index(string questionId)
{
string username = User.Identity.IsAuthenticated
? User.Identity.Name : string.Empty;
var roles = _repository.GetRolesForQuestion(username, questionId);
var model = Mapper.Map<UserRoles, RolesViewModel>(roles);
return PartialView(model);
}
}
and in the corresponding partial you would check the view model and render the necessary links:
#model RolesViewModel
#if(Model.CanEdit)
{
#Html.ActionLink("Edit", "Edit", "Questions")
}
#if(Model.CanDelete)
{
#Html.ActionLink("Delete", "Delete", "Questions")
}
...
Now somewhere in your main view simply include this action using the Html.Action method:
#Html.Action("Index", "UserLinks", new { questionId = Model.QuestionId })

Same view using different master pages - ASP.NET MVC

I'm new to ASP.net MVC and I want to use a view but with a different Master Page depending on the user Role.
For now, i'm leaning to use one controller who return View1 if the user is in Role1 and View2 is in Role2. View1 and View2 contains the same partial view inside to render the content that is share by both but have a different master page.
I want to know if it's a good practice or if you recommend another design. My solution seems a little bit complicated to do something simple. Maybe I am missing something
Thanks !
You could have a function which returns the master name based on the user role and then write a custom action filter which will execute after the action and set the corresponding master page based on the currently connected user role:
public class MasterChooserAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
base.OnActionExecuted(filterContext);
var result = filterContext.Result as ViewResult;
if (result != null)
{
var user = filterContext.HttpContext.User;
result.MasterName = GetMaster(user);
}
}
private string GetMaster(IPrincipal user)
{
// TODO: based on the current user roles return the proper master page
throw new NotImplementedException();
}
}
and then simply decorate your base controller with this action filter or if this is an ASP.NET MVC 3 application simply declare it as global filter.
Simply select the layout in your view.
You can dynamically change #{Layout = XXX} in mvc 3.
see: http://weblogs.asp.net/scottgu/archive/2010/10/22/asp-net-mvc-3-layouts.aspx
Your controller could check the roles, and assign the layout to use, which then is assigned to #Layout in your view, but you could just as well keep this code in your view to determine the layout to use, since after all it is 'view logic'
There are various ways to select the master page each having their merits.
The simplest would probably be to return the Master page name using the controller View method
public ViewResult Index() {
var masterName = getMasterPageNameForUser(); //get you master page/layout name here
return View("Index", masterName, model);
}
However this will lead to some repetitive code so an alternative could be to create a custom IViewEngine and set the master name there. Scott Hanselman's post and this coder journal post will give you an idea of how to create a custom view engine. From there it's a mater of setting the master name.
What happens if you come up with a third role? Fourth role? Instead of putting that kind of logic in your controller, what if the master page displays different things depending on their role? You could hide whole chunks of <div> or whatnot in the master. Then, you've only got one place to change it whenever the role dependency changes. Is the master page going to be that different based upon the role?
In your controller do
this.ViewBag.Layout = something
in your view
Layout = this.ViewBag.Layout

How to create different View depending on logged in user's role in ASP.NET MVC?

I am kind of new to ASP.NET MVC, so need your help getting me through a problem:
In my application the LogOn will be done using the Role of the user. I have my custom database schema (like User, Role, UserInRole etc.) and I am using my custom MembershipProvider and RoleProvider to achieve Logon.
BTW I am using the MVC default Account controller itself with some modification. What I am trying to achieve now is that depending upon the Role of logged in user I want to create a different View for the user.
Can I use the returnUrl parameter of LogOn action method in any way? (This parameter is set to null by default). If yes how can I construct and send returnUrl depending on Role?
Or is there any easier way to achieve this?
By default, in your controller methods which return an ActionResult, if you just return "View()" then the page that will be displayed is the page in your Views directory with the name of your controller method. However, you can specify the name of the View which will be returned, or pass on the call to another controller method to return the appropriate view.
As in the following contrived example:
public ActionResult Edit(string id)
{
// get the object we want to edit
IObjectDefinition definedObject = _objectManager.GetObjectById(id);
if (definedObject != null)
{
ViewData.Add("definition", definedObject );// add to view data collection so can display on page
IUser user = GetCurrentUser();// get from session/cookie/whatever
if (!user.IsAccountAdmin)
{
return View("Detail");// a readonly page as has no rights to edit
}
else
{
return View();// same object displayed in editable mode in another view
}
}
else
{
return New();// call to controller method below to allow user to create new record
}
}
public ActionResult New()
{
return View();
}
You decide what view to use (render) in the action - its not dictated directly by the URL
In the code you have access to the user object and from that can determine the roles that user is in - from that it should be straightforward enough to choose the view accordingly.
I think you can do a RedirectToAction on successful login and since you now have a valid login user, in the action method you can use IsInRole property of the of the LoggedIn User and render an appropriate partial view.

Resources