how to use session to avoid some user to view some pages? - c#

Thank You very much for answer my question, because i am very new in asp.net, I am really appreciated
I have a Session to identity the user in the controller
Session["UserId"] = UserNo;
Session["UserType"] = UserType;
What can i do to avoid the User such as the Session["UserType"] is "3" and then avoid him/her to login to some web pages?
I need to control that in the controller, view of filter config?

Create a BaseController and all the other controllers that you want to check User, should inherit it. Before a ActionResult requested, first the BaseController's constructor will work, so at constructor of BaseController you can do this,
public BaseController()
{
try
{
int UserID = 0;
if (System.Web.HttpContext.Current.Session["UserId"] != null)
UserID = Convert.ToInt32(System.Web.HttpContext.Current.Session["UserId"]);
if (!(UserID > 0))
{
System.Web.HttpContext.Current.Response.Redirect("controller/view");
}
}
catch (Exception ex)
{
throw ex;
}
}
Hope helps,

While all other answers are right and working, i would like to lead you to the more 'asp-ish' style of solving this problem, which also reduces your code because you do not have to write a if else in every of your controller.
In ASP.NET there is a Identity Concept which does exactly what you want to archive by hand.
Have a look here: https://learn.microsoft.com/de-de/aspnet/core/security/authentication/identity
Once you implemented the Identity, you can just mark your controller methods with [Authorize].
https://learn.microsoft.com/de-de/aspnet/core/security/authorization/introduction

Simply you have redirect the user if
public ActionResult Method()
{
if( Session["UserType"] = 3)
{
return View([forbidden page URL here]);
}
else
{
return View("controller/view");
}
}
Hope it Helps.

You just need to check your sessions value everytime a user tries to access a certain page.
EDIT:
Try this
public ActionResult Details(int id)
{
var details = context.checkIfUserExist(userID);
if (details == null)
{
return RedirectToAction("takeHimSomewhere");
}
return View(details);
}

Related

Authorize user based on model property ASP.NET MVC 4

I'm trying to prevent a user from being able to delete unless they created the model. (my models store the name of their creator) Right now a user clicks the "Delete" button which takes them to the delete page where they click the DeleteConfirmed button. How can I stop a user who hasn't created the model from deleting it?
I know I can get the current user's name with Context.User.Identity.Name
public ActionResult Delete(int? keyId)
{
Task mydata = db.MyDatas.Find(keyId);
...
return View(mydata);
}
[HttpPost, ActionName("Delete"), Authorize(Users = #"DOMAIN\Admin1 , DOMAIN\Bread")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(int keyId)
{
Task mydata = db.MyDatas.Find(keyId);
...
Easiest method is to use SingleOrDefault instead of Find and query based on the user at the same time:
Task myData = db.MyDatas.SingleOrDefault(m => m.Id == keyId && m.CreatedBy == User.Identity.Name)
Then, a user will only get a non-null thing if they created it.
Two viable answers here:
MVC access restriction for logged in users
Either create a custom AuthorizationFilter to encapsulate that check/logic.
Or, you can build it into your db.MyDatas.Find(keyId);
That is, add something to the effect of:
&& Creator == Context.User.Identity.Name
(If it doesn't return an object then the current user doesn't have permission to delete it.)
You Can use ActionFilters thats what they are here for :
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if((string)filterContext.RouteData.Values["action"]=="Delete") //check if its delete action
{
if (db.MyDatas.Find(a=>a.ModelCreator.trim()==Context.User.Identity.Name.trim())==null)
{
Response.Redirect("~/Home"); //or whatever u want to give for unauthorized
}
}
}
Enjoy!
You will need to pass an instance of the model record that is going to be deleted into your cshtml, and then in your cshtml perform some basic logic like { if( Context.User.Identity.Name == model_var.user_that_created.Name){<a>Delete</a>}}

Caching user information once user logs-in

I have users with different Roles. I want to deliver restricted view according to roles of the users. I have something in my Code which checks roles:
bool isAdmin = UserManager.IsInRole(currentUser.Id,"admin");
bool isEmployee = UserManager.IsInRole(currentUser.Id,"employee");
For above code to work, I need to instantiate currentUser. In other words I need to catch the information of the current user that is logged in. I tried something like var user = User.Identity.GetUserId(); and many other but can't find the working code. I would appreciate any help. Thank you!
Update:
here's my complete method code. y'all might wanna see until i check the above example.
public ActionResult Index()
{
var user = User.Identity.GetUserId();
bool isAdmin = UserManager.IsInRole(user, "admin");
bool isEmployee = UserManager.IsInRole(user, "employee");
if (isAdmin)
{
return View(db.Customers.ToList());
}
else
{
var restricted = db.Customers.Where(c => c.FirstName == "John");
return View(restricted);
}
}
[Authorize] attribute should be implemented in the desired restricted actionController method. The example is below.
[Authorize(Roles="Admin")]
public ActionResult Index()
{
return View();
}
This controller method is limited to the User with Role Admin. Furthermore, same action controller method could be included twice with different authorize tag.
I somehow figured out the solution. Here's the working code.
if(User.IsInRole("Admin"))
{
return View(db.Customers.ToList());
}
else
{
return View(db.MyUserInfo.ToList());
}

How to add Html.AntiForgeryToken to ActionLink and RedirectToAction?

I have a problem with adding AntiForgeryToken. This is my code:
<%:Html.ActionLink("Text", "Action", new { ID = "Hello")})%>
and
RedirectToAction("Action", "Controller", new { ID = "HelloFromMe"});
Controller:
[ValidateAntiForgeryToken]
public ActionResult Action(String ID){
return View();
}
Does anybody have idea how to do it ?
It is impossible to use an AntiForgeryToken into a GET method.
GET methods should only be used for read-only operation on your server. If you want to do something else than a read-only operation, then, you should use a POST method.
Here the reason why this token is useful, how and when to use it. http://haacked.com/archive/2009/04/02/anatomy-of-csrf-attack.aspx
The idea of antiforgery token is to prevent attacker to generate POST / GET request on behalf of the user. Thats why we add something special to every POST / GET request, that is unknown to attacker.
The simplest implementation of custom antiforgery would look like this.
And it will be exactly safe as ValidateAntiForgeryToken.
public class ProfileController : AuthorizedAccessController
{
// GET
public ActionResult Details(int userId)
{
User user = this.Entities.User.First(u => u.Id == userId);
this.Session["ProfilePageAntiforgery"] = Guid.NewGuid(); // use RandomNumberGenerator to generate strong token
this.ViewBag.ProfilePageAntiforgery = this.Session["ProfilePageAntiforgery"];
return View(user);
}
public ActionResult DeleteMyProfile(int userId, string profilePageAntiforgery)
{
if ((string)this.Session["ProfilePageAntiforgery"] != profilePageAntiforgery)
{
return this.RedirectToAction("Details", new { userId });
}
User user = this.Entities.User.First(u => u.Id == userId);
this.Entities.User.Remove(user);
this.Entities.SaveChanges();
return this.RedirectToAction("ProfileDeleted");
}
}
View:
<div>
#Html.ActionLink("Delete my profile", "DeleteMyProfile", new {userId = this.Model.Id, profilePageAntiforgery = this.ViewBag.ProfilePageAntiforgery })
</div>
Making custom attributes out of this is a matter of technique.
Lets say one attribute to store token in session and viewbag and the other to validate.
If using Session is not OK (Web farm etc.) you can simply replace it by DB or other store.

Determine which ASP.NET MVC View to return when not using return View(model) but return View("viewName", model)

I have my mvc site working well with mobile and non-mobile browsers; the issue I'm having is this. I have a couple Actions that (for logging reasons) I don't want to do a return RedirectToAction(...); on so instead I had been using return View("OtherView", model); this worked until I tried it on mobile, and it doesn't find OtherView.Mobile.cshtml. Is there a way to make this work?
Thise are the views
Views/Account/Create.cshtml
Views/Account/Create.Mobile.cshtml
Views/Account/CreateSuccess.cshtml
Views/Account/CreateSuccess.Mobile.cshtml
This is the Action
public ActionResult Create(FormCollection form)
{
TryUpdateModel(model);
if(!ModelState.IsValid) { return View(); } // this works correctly
var model = new Account();
var results = database.CreateAccount(model);
if(results) return View("CreateSuccess", model); // trying to make this dynamic
return View(model); // this works correctly
}
Normally I would just do return RedirectToAction(...); to the account detail page, but this will generate an additional log entry (for this user being read) as well as the detail page does not have access to the password. Since ActionResult Create had the password originally, it can show it to the user for confirmation, before its never seen again.
To be clear, I do not want to do if (Request.Browser.IsMobileDevice) mobile else full because I may end up adding another set of mobile views for for iPad or whatever:
Views/Account/Create.cshtml
Views/Account/Create.Mobile.cshtml
Views/Account/Create.iPad.cshtml
Views/Account/CreateSuccess.cshtml
Views/Account/CreateSuccess.Mobile.cshtml
Views/Account/CreateSuccess.iPad.cshtml
I would just set a session variable on their first usage that would be a "delivery type" identifying all supported views.
public enum DeliveryType
{
Normal,
Mobile,
Ipad,
MSTablet,
AndroidTablet,
Whatever
}
Then you could have a property or extension method somewhere
public DeliveryType UserDeliveryType
{
get
{
return (DeliveryType)Session["DeliveryType"];
}
set
{
Session["UserDeliveryType"] = value;
}
}
You could even put in a different method to delivery the View "add on":
public string ViewAddOn(string viewName)
{
return (UserDeliveryType != DeliveryType.Normal) ?
string.Format("{0}.{1}", viewName, UserDeliveryType.ToString()) :
viewName;
}
Then your ultimate call could be:
if (results) return View(ViewAddOn("CreateSuccess"), model);
Then you'd just have to make sure that for every delivery type you have a corresponding view. It may be prudent to build some kind of checker to verify you have a matching view and if not return the standard view.
you can create a pseudo-view that has a Partial with a ViewData variable. #Html.Partial will find the correct view.
something like this:
CustomView.cshtml:
if (ViewData.ContainsKey("PartialViewName")) {
#Html.Partial(ViewData[PartialViewName]);
}
Controller.cs:
public ActionResult Create(FormCollection form)
{
TryUpdateModel(model);
ViewData[PartialViewName] = "CreateSuccess";
if(!ModelState.IsValid) { return View(); } // this works correctly
var model = new Account();
var results = database.CreateAccount(model);
if(results) return View("CustomView", model); // trying to make this dynamic
return View(model); // this works correctly
}
you can have now CreateSuccess.cshtml and CreateSuccess.Mobile.cshtml.
note: you only need ONE CustomeView.cshtml in your all your application.
note2: you can always pass parameters in another fashion like viewbag, or whatever technique makes you feel more confortable :D
It's more a bit of hack than a solution. Let us know if you came up with something prettier.

How do I maintain ModelState errors when using RedirectToAction?

I have some code that saves a ticket in our system. If there is an error it does a RedirectToAction(). The problem is that I don't seem to have my errors in the new action. How can I fix this?
ModelState.AddModelError("_FORM", "Unable to save ticket");
ModelState.AddModelError("_FORM", "Phone number was invalid.");
ModelState.AddModelError("_FORM", "Lane number is required.");
return RedirectToAction("CreateStep", "Ticket");
I know some have suggested using TempData, but how would I get each error out of the ModelState?
Thanks.
The PRG pattern is ok, but I did this:
Base controller:
protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (TempData["ModelState"] != null && !ModelState.Equals(TempData["ModelState"]))
ModelState.Merge((ModelStateDictionary)TempData["ModelState"]);
base.OnActionExecuted(filterContext);
}
Action (I'm using xVal):
try
{
user.Login();
AuthenticationManager.SignIn(user);
}
catch (RulesException rex)
{
// on bad login
rex.AddModelStateErrors(ModelState, "user");
TempData["ModelState"] = ModelState;
return Redirect(Request.UrlReferrer.ToString());
}
The action throws an exception, adds the ModelState to TempData and redirects back to the referrer. Since the action is caught, OnActionExecuted is still executed, but the first time around the ModelState is the same as TempData["ModelState"], so you don't want to merge with yourself. When the redirect action is executed, OnActionExecuted fires again. This time, if there's anything in TempData["ModelState"], it merges with this action's ModelState.
You could expand it to multiple models by using TempData["ModelState.user"] = ModelState and then merging every TempData object that starts with ModelState..
I know this thread is old, but this blog about ASP.NET Best Practices has some excellent suggestions.
#13 on the page deals with using 2 Action filters to save and restore ModelState between redirects.
This is the pattern that my work uses, and I love it.
Here's the simplified example:
[ImportModelStateFromTempData]
public ActionResult Dashboard()
{
return View();
}
[AcceptVerbs(HttpVerbs.Post), ExportModelStateToTempData]
public ActionResult Dashboard(string data)
{
if (ValidateData(data))
{
try
{
_service.Submit(data);
}
catch (Exception e)
{
ModelState.AddModelError(ModelStateException, e);
}
}
return RedirectToAction("Dashboard");
}
this blog post describes how you could implement the PRG-Pattern in MVC
http://blog.simonlovely.com/archive/2008/11/26/post-redirect-get-pattern-in-mvc.aspx
hth
Use the TempData[] Collection
The tempdata is stored from one request to the next, then its gone.
What I did to maintain my ModelState no matter where I go with redirects is the following:
In your model, add:
public ModelStateDictionary modelstate { get; set; }
In your model's constructor, add:
this.modelstate = new System.Web.Mvc.ModelStateDictionary();
Sample Post with my model called Models.ContactInformation:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult contact(Models.ContactInformation con)
{
if (string.IsNullOrEmpty(con.SelectedAgencySelectorType))
{
ModelState.AddModelError("", "You did not select an agency type.");
}
con.modelstate = ModelState;
TempData["contact"] = con;
if (!ModelState.IsValid) return RedirectToAction("contactinformation", "reports");
//do stuff
return RedirectToAction("contactinformation", "reports");
}
So now your tempdata has your model and modelstate as is.
The following is my view that is agnostic to the state of anything, unless it has something. Here's the code:
[HttpGet]
public ActionResult contactinformation()
{
//try cast to model
var m = new Models.ContactInformation();
if (TempData["contact"] is Models.ContactInformation) m = (Models.ContactInformation)TempData["contact"];
//restore modelstate if needed
if (!m.modelstate.IsValid)
{
foreach (ModelState item in m.modelstate.Values)
{
foreach (ModelError err in item.Errors)
{
ModelState.AddModelError("", err.ErrorMessage.ToString());
}
}
}
return View(m);
}

Categories