MVC Url not pathing correctly - asp.net-mvc

I have a link going to
<a class="k-link" href="/UserView/EditByName?UserName=MVCTest6">Profile</a>
When the link it is clicked it goes to this
URL: http://localhost:3256/MVCTest6/Create
which works when i am logged in as an admin user. (The folder has no security in a web.config setting it apart). This link actually works on another part of the page.
The user also already exist and has been authenticated.
Can this please be explained?

I get it ! This is where the problem is,
return RedirectToAction("Create", User.Identity.Name);
you are using this overload RedirectToAction("Action", "Contoller");
So the later part is taken as the controller. Try other overloads that matches your requirement, if you are trying to pass values to another action, which must be like
return RedirectToAction("Create", new {UserName = User.Identity.Name});

I forgot I had logic in place to redirect if user profile was not created. This was causing the problem. My test user didnt have profile already setup so it was redirecting to the create page
public ActionResult EditByName(string userName)//EditByName
{
if (User.Identity.IsAuthenticated)
{
UserModel usermodel = repository.Get(User.Identity.Name);// db.UserModels.Find(id);
if (usermodel == null)
{
return RedirectToAction("Create", User.Identity.Name);
}
return View(usermodel);
}
else { return RedirectToAction("Login", controllerName: "AccountView"); }
}

Related

ASP NET MVC5 randomly redirects to my login page

I have an ASP.NET MVC application with ActionFilters for Authentication and no Forms Authentication. "SegurancaAction" is the attribute responsible for validating authentication and exists in every controller endpoint except in the login ones (as expected).
I'm facing a problem in which sometimes I try to access one of my controllers and the GET request goes to my login endpoint. In the method Application_BeginRequest at Global.asax, I can see the very first attempt is at 'security/login' (the route to my login endpoint) instead of the one I want. I can also see this endpoint being called in debugging apps such as Fiddler, or ASP.NET Trace or Glimpse MVC5.
Besides calling the wrong action, once I login again this issue keeps happening for the same endpoint I was trying to access, redirecting my site to the login page over and over.
SegurancaAction:
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
Autenticacoes autenticacao = _authApp.IsAutenticado(filterContext.HttpContext.Session.SessionID);
if (autenticacao == null)
{
if (filterContext.HttpContext.Request.IsAjaxRequest())
filterContext.Result = new HttpStatusCodeResult(System.Net.HttpStatusCode.Unauthorized);
else
{
filterContext.HttpContext.Response.RedirectPermanent("/security/login");
return;
}
}
else
{
// other stuff
}
}
SecurityController:
[HttpPost]
[ConfigAction]
public ActionResult Login(vm_Login login)
{
if (ModelState.IsValid)
{
if (!String.IsNullOrEmpty(login.Login) && !String.IsNullOrEmpty(login.Senha))
{
Entidades entidade = _entidadeApp.GetByUsuarioSenha(login.Login, login.Senha);
if (entidade == null)
{
ViewBag.FalhaAutenticacao = "As credenciais informadas não conferem!";
return View("Login");
}
else
{
string encryptionKey = System.Configuration.ConfigurationManager.AppSettings["EncryptionKey"];
var a = _autenticacaoApp.Autenticar(entidade.Id, encryptionKey, login.Senha, HttpContext.Session.SessionID);
}
Response.RedirectPermanent("~/principal/index");
}
}
else
{
ViewBag.FalhaAutenticacao = "É necessário informar o usuario e a senha!";
}
return View();
}
All _autenticacaoApp.Autenticar(...) method does is to create an authentication entry on the database, it's a completely custom code.
Does anyone know why this issue happens? Sometimes I can reproduce it by deleting the cookies that contain ASP.NET_Session ID and RequestVerificationToken. So far I know those cookies are automatically generated and I notice that sometimes when I login again they are not re-generated.
I figured out the issue. It was this "RedirectPermanent" method being used here:
filterContext.HttpContext.Response.RedirectPermanent("/security/login");
It tells the browser that the resource I'm trying to access is no longer available and is now located at this new Url. The browser records this information and always redirects to the new resource.
I just changed it to use "Redirect" instead.

How can I set the ReturnUrl when I am using RedirectToAction?

I have a controller that redirects to another action, e.g.
mysite.com/food/3
This action does a RedirectToAction to an action called Cake and passes in id=3.
If the user is not authenticated at that point, you go back to the loginpage, but the RedirectUrl is /Cake (without any mention of the id) and not /food/3. This causes an error once you log in because firstly it shouldn't be accessed via that url in the browser, and secondly because the parameters have vanished.
Is there a simple way to make sure it redirects to the original URL in the browser, or do I have to write a custom authorize attribute and store a lookup table to get the parent page?
Gonna take a stab at this one.
Food and Cake take id values and redirect parameters and just pass them around freely where they can be used as you see fit.
Food
public ActionResult Food (int id, string returnUrl = string.Empty)
{
// Do work
return RedirectionToAction("Cake", new { id, returnUrl })
}
Cake
[Authorize]
Cake (int id, string returnUrl = string.Empty)
{
// Do work
if (returnUrl != string.Empty)
return Redirect (returnUrl);
return View();
}
A problem arises when a View is finally returned to the client because then you have to somehow get that returnUrl into the form posted when they submit their login info because you want to use it later. So the first step is getting it into the View's form so it's included in the model that gets posted. One way to do that is the ViewBag; another way is pulling it from the query string. I've shown an example of both below.
Option 1:
Login
Login (string returnUrl = string.Empty)
{
ViewBag.ReturnUrl = returnUrl;
return View();
}
Login.cshtml
Model.ReturnUrl = ViewBag.ReturnUrl;
Option 2:
Login
Login ()
{
return View();
}
Login.cshtml
Model.ReturnUrl = Request.QueryString["ReturnUrl"];
If this doesn't suffice, comment and I can try to modify this answer further.
The simplest way to make this work is to put the AuthorizeAttribute onto the action method that calls RedirectToAction to short circuit the nonsense of building the wrong URL. The FormsAuthenticationModule uses the RawUrl of the request when it adds the ReturnUrl parameter, so it not possible to modify without building your own custom FormsAuthenticationModule (which you could consider option B). But if you check authorization before you redirect the RawUrl will be correct.
// This ensures it builds the correct ReturnUrl.
[Authorize]
public ActionResult Food (int id)
{
// Do work
return RedirectionToAction("Cake", new { id = id })
}
// This ensures the final destination cannot be accessed
// without authorization.
[Authorize]
public ActionResult Cake (int id)
{
// Do work
return View();
}

Pass Value from View To Controller in Asp.net MVC

I am trying to pass a message to another view (actually same controller) I can do it well but there is a problem for me..
I am new on web and it doesnt seem good ..
and here my c# code
if (createStatus == MembershipCreateStatus.Success)
{
string registrationMessage = "You have registered successfully";
return RedirectToAction("KurumsalGiris", new { message = registrationMessage });
}
[AllowAnonymous] //sonradan eklendi
public ActionResult KurumsalGiris(string message="")
{
if (User.Identity.IsAuthenticated)
return Content("Zaten giriş yapmışsınız");
ViewBag.RegistrationMessage = message;
return View();
}
and here html side
#model E_Cv.Models.LogOnModel
#{
ViewBag.Title = "Kurumsal Giriş";
}
<h2>Kurumsal Giriş</h2>
<h2>#ViewBag.RegistrationMessage</h2>
<p>
Please enter your user name and password.
#Html.ActionLink("Yeni Kurum Kaydı", "KurumsalKayit")
if you don't have an account.
</p>
so I dont know how to pass value to another view with different way.. I dont want to show this kind of message on address bar and user musnt change it.
Secondly Could I do it with "Get" Method?
Why don't you just return a different view rather than redirecting? In fact, the code the posted in the first place should be posting to a controller that returns a view for a successful login.
In fact, why are you redirecting to a page that asks the user to login if they've just logged in?
Other possible options include encrypting the string in the URL, or just passing a flag in the URL that the controller translates into the corresponding string.
What you would do is instead of returning a RedirectToAction
you could return the View directly: (second parameter is a model, where you can use the same model class E_Cv.Models.LogOnModel adding a RegistrationMessage property to it)
return View("<name of the view>",
new E_Cv.Models.LogOnModel {
RegistrationMessage = "You have registered successfully"
});
or keep the data in the ViewBag like you have done:
ViewBag.RegistrationMessage = "You have registered successfully";
return View("<name of the view>");
regarding your last question, give the message is showing in your URL, you are using the GET method, if you return a View instead of a redirect, it'll avoid showing anything in the URL
You should use TempData in this scenario
if (createStatus == MembershipCreateStatus.Success)
{
TempData["Message"] = "You have registered successfully";
return RedirectToAction("KurumsalGiris");
}
And then in your view
#if (TempData["Message"] != null)
{
<h2>#TempData["Message"]</h2>
}
Or if you want to do it in the controller, just keep your view the same as it is at the moment and set ViewBag.RegistrationMessage in the controller
ViewBag.RegistrationMessage = TempData["Message"];
If the question is how to pass data between controllers without using the querystring, then one option is the Session object.
if (createStatus == MembershipCreateStatus.Success)
{
Session["Message"] = "You have registered successfully";
return RedirectToAction("KurumsalGiris");
}
[AllowAnonymous] //sonradan eklendi
public ActionResult KurumsalGiris(string message="")
{
if (User.Identity.IsAuthenticated)
return Content("Zaten giriş yapmışsınız");
ViewBag.RegistrationMessage = (string) Session["Message"];
return View();
}
However, I agree with #Jonathan Wood below that this is not necessarily the best approach to the particular problem you are attempting to solve. Still, as a general technique, it is worth knowing about.

Form Authentication IsOnline method does not retrieve the correct status

I am using Form Authentication in an ASP.NET MVC project.
When the current user click on the Exit link the code execute an action that does in sequence:
System.Web.Security.FormsAuthentication.SignOut();
Session.Abandon();
The second call is not properly needed because I am not using session at all.
The problem is that if I login with an Admin account I can see the user still Logged In.
Where I am doing wrong?
thanks for helping!
EDIT:
Added the Login code just to be complete
if (ModelState.IsValid) {
if (MembershipService.ValidateUser(model.UserName, model.Password)) {
System.Web.Security.FormsAuthentication.SignIn(model.UserName, model.RememberMe);
if (!String.IsNullOrEmpty(returnUrl)) {
return Redirect(returnUrl);
}
else {
return RedirectToAction("Index", "Home");
}
}
else {
ModelState.AddModelError("", "Error....");
}
}
Ok. I have found the problem.
I was using, to show the current loggein users the following call
MembershipUser user = Membership.GetUser(userKey, true)
if ( user.IsOnline ) {
...
}
and I have realized that the second parameter of the GetUser method sets the User status to online and updates the LastActivity field in the data store.
I dont know why this is working this way but that's it...

ASP.NET MVC check if user belongs to [x] group

Maybe I'm approaching this the wrong way and should be doing everything in action filters, in which case please point me in the right direction!
I'm setting up my ASP.NET MVC application so that the one HomeController Index action delivers two different types of content, like so:
if(Request.IsAuthenticated)
return View("IndexRegistered");
else
return View("IndexGuest");
This is fine but say I want to split it into three so Administrator members get their own page...
if(Request.IsAuthenticated)
{
if( /* user is a member of administrators */)
return View("IndexAdministrator");
else
return View("IndexCustomer");
}
else
return View("IndexGuest");
Can someone enlighten me as to the missing piece of this puzzle?
Use the Roles property of the Authorize Action Filter:
[Authorize(Roles="Administrators,Moderators")]
public ActionResult SomeAction(){
}
Or use the User.IsInRole() method:
if(User.IsInRole("Administrator")) { ... }
If you look at the Authentication provider which comes out-of-the-box in the default MVC project templates it's easy to add your own role support there and track it in session, so your code above would become:
if(Request.IsAuthenticated)
{
if(Session["Role"] == "Administrator")
return View("IndexAdministrator");
else
return View("IndexCustomer");
}
else
return View("IndexGuest");
and then opens possibilities like:
if(Request.IsAuthenticated)
return View("Index" + Session["Role"]);
else
return View("IndexGuest");

Resources