Redirect to browsed url after login(authentication) - asp.net-mvc

I have developed a module which authorizes the roles from the database dynamically. Now, what i want is,when a user comes and browses different actionmethod without logging in, I am able to redirect the user to the login page. As soon as the user logs in, he should be redirected to the actionmethod/view which he was trying to access without login. The following is the code which i am using to extract the URL browsed without logging in. I also have a key defined in my web.config as serverURL which gives me initial url like localhost. How to i make the below returnurl remembered and redirect the user to the desired actionmethod/view after logging in.
returnUrl = HttpContext.Current.Request.RawUrl;
public class AuthorizeUserAttribute : AuthorizeAttribute
{
public string Feature { get; set; }
public string returnUrl { get; set; }
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
//var isAuthorized = base.AuthorizeCore(httpContext);
//if (!isAuthorized)
//{
// return false;
//}
if (httpContext != null && httpContext.Session != null && httpContext.Session["Role"] != null)
{
string userRoles = UserBL.ValidateUsersRoleFeature(httpContext.Session["Role"].ToString(), Feature);
if (!string.IsNullOrEmpty(userRoles))
{
if (userRoles.IndexOf(httpContext.Session["Role"].ToString()) >= 0)
{
return true;
}
}
return false;
}
else
return false;
}
public override void OnAuthorization(AuthorizationContext filterContext)
{
HttpSessionStateBase session = filterContext.HttpContext.Session;
if (session.IsNewSession || session["Email"] == null)
{
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
// For AJAX requests, return result as a simple string,
// and inform calling JavaScript code that a user should be redirected.
JsonResult result = new JsonResult();
result.ContentType = "text/html";
result.Data = "SessionTimeout";
filterContext.Result = result;
//$.ajax({
// type: "POST",
// url: "controller/action",
// contentType: "application/json; charset=utf-8",
// dataType: "json",
// data: JSON.stringify(data),
// async: true,
// complete: function (xhr, status) {
// if (xhr.responseJSON == CONST_SESSIONTIMEOUT) {
// RedirectToLogin(true);
// return false;
// }
// if (status == 'error' || !xhr.responseText) {
// alert(xhr.statusText);
// }
// }
// });
//}
}
else
{
// For round-trip requests,
filterContext.Result = new RedirectToRouteResult(
new RouteValueDictionary { { "Controller", "User" }, { "Action", "Login" } });
returnUrl = HttpContext.Current.Request.RawUrl;
}
}
else
base.OnAuthorization(filterContext);
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
filterContext.Result = new RedirectToRouteResult(
new RouteValueDictionary(
new
{
controller = "Base",
action = "PageNotAccessible"
})
);
}
}

In attribute return the url on which user was in routes:
filterContext.Result = new RedirectToRouteResult(
new RouteValueDictionary
{
{ "Controller", "User" },
{ "Action", "Login" },
{"returnUrl",HttpContext.Current.Request.RawUrl}
});
and in your action:
[AllowAnonymous]
public virtual ActionResult Login()
{
ViewBag.returnUrl = Request.QueryString["returnUrl"];
return View();
}
In View:
#using(Html.BeginForm("Login","User",new{returnUrl = ViewBag.returnUrl},FormMethod.Post))
{
<input type="submit" value="Login" />
}
and in Post Action:
[AllowAnonymous]
[HttpPost]
public virtual ActionResult Login(User model, string returnUrl)
{
if(ModelState.IsValid)
{
// check if login successful redirect to url from where user came
if(LoginSucessful)
return Redirect(returnUrl); // will be redirected to url from where user came to login
return View();
}

in your html page, create a hidden tag:
<div id="HiddenURL" class="hidden"></div>
the moment the user access a certain page, use Javascript to bind the url the user came from in a hidden value in you web page:
$(document).ready(function ()
{
$('#HiddenURL').text(window.location.href.toLowerCase());
...
}
In your asp.net page assign to action, the url taken from div text:
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
filterContext.Result = new RedirectToRouteResult(
new RouteValueDictionary(
new
{
controller = "Base",
action = HiddenURL.Value
})
);
}

Related

Redirect to external url from OnActionExecuting?

I need to redirect to an external url (let's say "www.google.com") from OnActionExecuting method. Right now I'm using something like this:
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (!HttpContext.Current.User.Identity.IsAuthenticated)
{
var redirectUrl = "www.google.com";
try
{
var isAjaxRequest = filterContext.HttpContext.Request.IsAjaxRequest();
if (isAjaxRequest)
{
filterContext.HttpContext.Response.StatusCode = SessionController.CustomHttpRedirect;
filterContext.HttpContext.Response.StatusDescription = redirectUrl;
filterContext.Result = new JsonResult
{
Data = new { Redirect = redirectUrl },
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
}
else
{
filterContext.Result = new RedirectResult(redirectUrl, true);
}
return;
}
else
{
throw new LoggedOutException();
}
}
catch
{
throw new LoggedOutException();
}
}
}
The problem is that it's not redirecting me to "www.google.com" but it's redirecting to "http://localhost:1234/www.google.com" (I try it locally).
There is any way to solve this ?
Thanks
The problem was verry easy to solve:
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (!HttpContext.Current.User.Identity.IsAuthenticated)
{
var redirectUrl = "http://www.google.com";
try
{
var isAjaxRequest = filterContext.HttpContext.Request.IsAjaxRequest();
if (isAjaxRequest)
{
filterContext.HttpContext.Response.StatusCode = SessionController.CustomHttpRedirect;
filterContext.HttpContext.Response.StatusDescription = redirectUrl;
filterContext.Result = new JsonResult
{
Data = new { Redirect = redirectUrl },
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
}
else
{
filterContext.Result = new RedirectResult(redirectUrl, true);
}
return;
}
else
{
throw new LoggedOutException();
}
}
catch
{
throw new LoggedOutException();
}
}
}
All I had to do was that when I assigned the value to "redirectUrl", I had tu put http before wwww. This mus be put if you use a SSL conenction and you're trying to redirect from mvc to another domain.
Instead of using:
filterContext.Result = new RedirectResult("www.google.com", true);
Try the following:
filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(new { controller = "Home", action = "External" , ReturnURL = "www.google.com"}));
and in your (Home) controller create an action called (External) and from there redirect to your external url:
public class HomeController : Controller
{
[AllowAnonymous]
public ActionResult External(string ReturnURL){
return Redirect(ReturnURL);
}
}
You can't directly perform a server side redirect from an ajax response. You could, however, return a JsonResult with the new url and perform the redirect with javascript. see this answer

I am not able to get the User.Identity.Name after redirected from controller in Mvc

In the 1st example:-
i am assigning User.Identity.Name value to the variable id. i am able to get the value after that i am Redirecting to some other view here i am using Redirect(ReturnUrl) now i am able to get the User.Identity.Name value in the other controller(Redirected view) also
But in the 2nd example :-
i am assigning User.Identity.Name value to the variable id i am able to get the value after that i am Redirecting to some other view here i am using return Redirect(ReturnUrl);when i am using return Redirect(ReturnUrl);am not able to get the User.Identity.Name value in the Redirected url
Example 1:-
public ActionResult SignIn(string ReturnUrl)
{
if (ReturnUrl == "/" || string.IsNullOrEmpty(ReturnUrl))
{
ReturnUrl = "/Dashboard";
}
var id=HttpContext.Current.User.Identity.Name;
Response.Redirect(ReturnUrl);
return View();
}
Example 2:-
public ActionResult SignIn(string ReturnUrl)
{
if (ReturnUrl == "/" || string.IsNullOrEmpty(ReturnUrl))
{
ReturnUrl = "/Dashboard";
}
var id=HttpContext.Current.User.Identity.Name;
return Redirect(ReturnUrl);
}
My Controller:- In this function if i am return Redirect(ReturnUrl); i am not able to get the User.Identity.Name value in CompanyRequired filter if i am using Response.Redirect(ReturnUrl); return View(); then able to get the User.Identity.Name value in CompanyRequired filter but i have to use return Redirect(ReturnUrl);
[HttpPost]
public async Task<ActionResult> SignInCallback()
{
var token = Request.Form["id_token"];
var state = Request.Form["state"];
var claims = await ValidateIdentityTokenAsync(token, state);
string ReturnUrl = state.Substring(state.IndexOf('?') + 1);
var id = new ClaimsIdentity(claims, "Cookies");
Request.GetOwinContext().Authentication.SignIn(id);
if (ReturnUrl == "/" || string.IsNullOrEmpty(ReturnUrl))
{
ReturnUrl = "/Dashboard";
}
var Id = User.Identity.Name;
return Redirect(ReturnUrl);
}
View:- Here i control will go to the CompanyRequired filter there i need a User.Identity.Name value in that i am getting value null
[Authorize,CompanyRequired]
public class DashBoardController : BaseController
{
public ActionResult Index()
{
return View();
}
}
CompanyRequired Filter:-
public class CompanyRequiredAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var coCookie = filterContext.HttpContext.Request.Cookies["CoId"];
if (coCookie == null)
{
var Id= HttpContext.Current.User.Identity.Name.Int(); **//here i need to get the value but i am getting null value**
IdNmList cos = new EmployeeDAL().GetCompany(Id);
if (cos.Count == 0)
{
filterContext.Result = new RedirectToRouteResult(new System.Web.Routing.RouteValueDictionary
{
{ "controller" , "Company"},
{ "action" , "Add"}
});
}
else if (cos.Count == 1)
{
filterContext.HttpContext.Response.Cookies.Add(new HttpCookie("CoId", cos[0].Id.ToString()));
}
else
{
filterContext.Result = new RedirectToRouteResult(new System.Web.Routing.RouteValueDictionary
{
{ "controller", "Company" },
{ "action", "Select" },
{ "ReturnUrl", filterContext.HttpContext.Request.RawUrl }
});
}
}
base.OnActionExecuting(filterContext);
}
}

Overriding Authorize Attribute

I have a need to override authorize attribute.
Basically if its an ajax request and the user is not logged in or is not in specified roles then i want to return a JSON. The JSON will tell the caller the reason as not logged in or not in role and needs to return the redirect to url. In case of not signed it, it also needs to give back ReturnUrl.
If its not an ajax request then i want the default processing by Authorize attribute to kick in.
We are using forms authentication and the sign in url and error pages are specified in the web.config file.
Following is my take at it but i am not getting the following right
missing roles processing in case of an ajax request
in case of not an ajax request (else block), i am redirecting the user to the sign in page. i want the default autorize attribute to kickin in this case
I just need the push in the right direction... tutorial or a blog pointer is all i need to learn and accomplish this....
public class AuthorizePartnerProgramsAttribute : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
HttpContext httpContext = HttpContext.Current;
var url = new UrlHelper(filterContext.RequestContext);
var request = filterContext.HttpContext.Request;
if (request.IsAuthenticated == false)
{
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
if (request.Url != null)
filterContext.Result = CommonUtilities.AddJsonUtf8Encoding(new JsonResult { Data = new { error = true, singinerror = true, message = "Sign in required!", returnUrl = request.UrlReferrer.AbsolutePath.ToString() } });
else
filterContext.Result = CommonUtilities.AddJsonUtf8Encoding(new JsonResult { Data = new { error = true, singinerror = true, message = "Sign in required!" } });
}
else
{
if (request.UrlReferrer != null)
{
filterContext.Result = new RedirectResult(url.Action("Index", "SignIn", new { Area = "Account", ReturnUrl = filterContext.RequestContext.HttpContext.Request.UrlReferrer.AbsolutePath.ToString() }));
}
else
{
filterContext.Result = new RedirectResult(url.Action("Index", "SignIn", new { Area = "Account"}));
}
}
}
}
}
Here is my second stab at it. I think i am now more confused than before and need help setting it up properly
public class AuthorizeCustomAttribute : AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
var request = filterContext.RequestContext.HttpContext.Request;
if (request.IsAjaxRequest())
{
var url = new UrlHelper(filterContext.RequestContext);
var urlReferer = request.UrlReferrer != null
? request.UrlReferrer.ToString()
: String.Empty;
var signInUrl = url.Action("Index", "SignIn", new { Area = "Account", ReturnUrl = urlReferer });
var accessDeniedUrl = url.Action("PageAccessDenied", "Error", new { Area = "" });
if (!request.IsAuthenticated)
{
//not authenticated
filterContext.Result =
CommonUtilities.AddJsonUtf8Encoding(new JsonResult
{
Data =
new {error = true, singinerror = true, message = "Sign in required!", url = signInUrl},
JsonRequestBehavior = JsonRequestBehavior.AllowGet
});
}
}
else
{
base.HandleUnauthorizedRequest(filterContext);
}
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (httpContext.Request.IsAjaxRequest())
{
//Use [AuthorizeCustom(Roles="MyRole1,MyRole2")]
//or [AuthorizeCustom]
//roles may not have been applied here
//checking authentication will be done by the HandleUnauthorizedRequest?????
//if no roles are specified then it is true = so give access to the resource
//user may have multiple roles or single role assigned, check and if not in role then return json back.
//....
}
else
{
return base.AuthorizeCore(httpContext);
}
}
}
This helped me setting up mine
http://www.dotnet-tricks.com/Tutorial/mvc/G54G220114-Custom-Authentication-and-Authorization-in-ASP.NET-MVC.html
use
[AuthorizeCustom(Roles = RoleNames.Admin)]
Here is the full working attribute for me without any cleanup.
public class AuthorizeCustomAttribute : AuthorizeAttribute
{
#region CONSTANTS
public const string SectionStemFuture = "StemFuture";
#endregion
#region PROPERTIES
private string Section { get; set; }
#endregion
#region Constructor
public AuthorizeCustomAttribute()
{
Section = String.Empty;
}
public AuthorizeCustomAttribute(string section)
{
Section = section;
}
#endregion
#region Overrides
public override void OnAuthorization(AuthorizationContext filterContext)
{
var request = filterContext.HttpContext.Request;
var url = new UrlHelper(filterContext.RequestContext);
/*
var urlReferer = request.UrlReferrer != null
? request.UrlReferrer.ToString()
: String.Empty;
*/
var urlReferer = request.Url.PathAndQuery;
var signInUrl = url.Action("Index", "SignIn", new { Area = "Account", ReturnUrl = urlReferer });
var accessDeniedUrl = url.Action("PageAccessDenied", "Error", new { Area = "" });
//overwrite the default sign in URL according to the section
if (!String.IsNullOrWhiteSpace(Section))
{
switch (Section)
{
case SectionStemFuture:
signInUrl = url.Action("Index", "StemFutureHome", new { Area = "StemFuture", ReturnUrl = urlReferer });
break;
}
}
if (!request.IsAuthenticated)
{
//not authenticated
if (request.IsAjaxRequest())
{
filterContext.Result =
CommonUtilities.AddJsonUtf8Encoding(new JsonResult
{
Data =
new {error = true, signinerror = true, message = "Sign in required", url = signInUrl},
JsonRequestBehavior = JsonRequestBehavior.AllowGet
});
}
else
{
//this is not an ajax request
if (!String.IsNullOrWhiteSpace(Section))
{
filterContext.Result = new RedirectResult(signInUrl);
}
else
{
//let the base authorization take care of it
base.OnAuthorization(filterContext);
}
}
}
else if (!String.IsNullOrWhiteSpace(base.Roles))
{
var isRoleError = true;
var rolesAllowed = base.Roles.Split(',');
//authenticated and we have some roles to check against
var user = filterContext.HttpContext.User;
if (user != null && rolesAllowed.Any())
{
foreach (var role in rolesAllowed)
{
if (user.IsInRole(role))
{
isRoleError = false;
}
}
}
if (isRoleError)
{
if (request.IsAjaxRequest())
{
filterContext.Result =
CommonUtilities.AddJsonUtf8Encoding(new JsonResult
{
Data =
new
{
error = true,
signinerror = true,
message = "Access denied",
url = accessDeniedUrl
},
JsonRequestBehavior = JsonRequestBehavior.AllowGet
});
}
else
{
//here we will need to pass to the access denied
filterContext.Result = new RedirectResult(accessDeniedUrl);
}
}
}
}
#endregion
}

How can I use an action filter in ASP.NET MVC to route to a different view but using the same URL?

Is it possible to make a filter that, after a controller action has been (mostly) processed, checks for a certain test condition and routes to a different view transparently to the user (i.e., no change in the URL)?
Here would be my best guess at some pseudocode:
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
// If some condition is true
// Change the resulting view resolution to XYZ
base.OnResultExecuting(filterContext);
}
filterContext.Result = new ViewResult
{
ViewName = "~/Views/SomeController/SomeView.cshtml"
};
This will short-circuit the execution of the action.
also you can return view as from your action
public ActionResult Index()
{
return View(#"~/Views/SomeView.aspx");
}
This is what I ended up doing, and wrapped up into a reusable attribute and the great thing is it retains the original URL while redirecting (or applying whatever result you wish) based on your requirements:
public class AuthoriseSiteAccessAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
// Perform your condition, or straight result assignment here.
// For me I had to test the existance of a cookie.
if (yourConditionHere)
filterContext.Result = new SiteAccessDeniedResult();
}
}
public class SiteAccessDeniedResult : ViewResult
{
public SiteAccessDeniedResult()
{
ViewName = "~/Views/SiteAccess/Login.cshtml";
}
}
Then just add the attribute [SiteAccessAuthorise] to your controllers you wish to apply the authorisation access to (in my case) or add it to a BaseController. Make sure though the action you are redirecting to's underlying controller does not have the attribute though, or you'll be caught in an endless loop!
I have extended the AuthorizeAttribute of ASP.NET MVC action filter as DCIMAuthorize, in which I perform some security checks and if user is not authenticated or authorized then action filter will take user to access denied page. My implementation is as below:
public class DCIMAuthorize : AuthorizeAttribute
{
public string BusinessComponent { get; set; }
public string Action { get; set; }
public bool ResturnJsonResponse { get; set; }
public bool Authorize { get; set; }
public DCIMAuthorize()
{
ResturnJsonResponse = true;
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
try
{
//to check whether user is authenticated
if (!httpContext.User.Identity.IsAuthenticated)
return false;
//to check site level access
if (HttpContext.Current.Session["UserSites"] != null)
{
var allSites = (VList<VSiteList>)HttpContext.Current.Session["UserSites"];
if (allSites.Count <= 0)
return false;
}
else
return false;
// use Authorize for authorization
Authorize = false;
string[] roles = null;
//get roles for currently login user
if (HttpContext.Current.Session["Roles"] != null)
{
roles = (string[])HttpContext.Current.Session["Roles"];
}
if (roles != null)
{
//for multiple roles
string[] keys = new string[roles.Length];
int index = 0;
// for each role, there is separate key
foreach (string role in roles)
{
keys[index] = role + "-" + BusinessComponent + "-" + Action;
index++;
}
//access Authorization Details and compare with keys
if (HttpContext.Current.Application["AuthorizationDetails"] != null)
{
Hashtable authorizationDetails = (Hashtable)HttpContext.Current.Application["AuthorizationDetails"];
bool hasKey = false;
foreach (var item in keys)
{
hasKey = authorizationDetails.ContainsKey(item);
if (hasKey)
{
Authorize = hasKey;
break;
}
}
}
}
return base.AuthorizeCore(httpContext);
}
catch (Exception)
{
throw;
}
}
public override void OnAuthorization(AuthorizationContext filterContext)
{
try
{
filterContext.Controller.ViewData["ResturnJsonResponse"] = ResturnJsonResponse;
base.OnAuthorization(filterContext);
if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
// auth failed, redirect to login page
filterContext.Result = new HttpUnauthorizedResult();
return;
}
if (!Authorize)
{
//Authorization failed, redirect to Access Denied Page
filterContext.Result = new RedirectToRouteResult(
new RouteValueDictionary{{ "controller", "Base" },
{ "action", "AccessDenied" }
//{ "returnUrl", filterContext.HttpContext.Request.RawUrl }
});
}
}
catch (Exception)
{
throw;
}
}
}
You Can Also Save All Route File Path in a Static And Use it Like This :
public static class ViewPath
{
public const string SomeViewName = "~/Views/SomeViewName.cshtml";
//...
}
And into Your ActionFilter :
context.Result = new ViewResult()
{
ViewName = ViewPath.SomeViewName /*"~/Views/SomeViewName.cshtml"*/
};

Redirect a user to a specific view when authorization fails?

I have the following code:
[AcceptVerbs(HttpVerbs.Post), Authorize(Roles = RoleKeys.Administrators)]
public ActionResult Edit(int id, FormCollection collection)
{
User user = userRepository.GetUser(id);
try
{
this.UpdateModel(user);
userRepository.Save();
return this.RedirectToAction("Details", new { id = user.UserId });
}
catch
{
this.ModelState.AddModelErrors(user.GetRuleViolations());
return View(new UserFormViewModel(user));
}
}
If the currently logged in user is not in the Administrators role, it kicks them back to the login screen. The user is already logged in, they are just not authorize to perform the requested action.
Is there any way to have them redirected to a specific view, for example, AccessDenied?
You can define your own attribute:
public class MyAuthorizeAttribute: AuthorizeAttribute
{
public override void OnAuthorization( AuthorizationContext filterContext )
{
base.OnAuthorization(filterContext);
if (filterContext.Result is HttpUnauthorizedResult)
{
filterContext.Result = new RedirectToRouteResult(
new RouteValueDictionary
{
{ "controller", "Login" },
{ "action", "AccessDenied" }
});
}
}
}
and use
[AcceptVerbs(HttpVerbs.Post), MyAuthorize(Roles = RoleKeys.Administrators)]

Resources