In my MVC 4 site, authenticaiton is configured for intranet.
Now, i want to get logged in UserID,
How to fetch the user ID at some common place when accessing any first action (on particular user session) ?
Also, how to fetch User ID existed in context ?
Currently, i wrote session set logic User.Identity.Name on each controller index action.
Is this possible to move that logic for session set into some common place ?
Sorry for confusion.
Got the solutio. Created Action Filter as below and applied at each controller as attribute so, that code execute each time and i added relatd stuff at this place:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class ControllerLogAndAccessFilter : FilterAttribute, IActionFilter
{
public void OnActionExecuting(ActionExecutingContext filterContext)
{
}
Related
I have a provider hosted sharepoint add-in which uses a database at back end. This database has some roles like Employer and Employee in DB marked with a number. For example 1 for Employer and 2 for Employee and corresponding to every row a sharepoint email address.
In my add-in, I want to mark all my actions with [Authorize(Role="Employer")] attribute but I am not sure how to proceed? If I create a custom filter then, does that mean on every action, I need to call SP to get current logged in user email address -> query DB using it -> find role -> proceed or give access denied. It will consume lots of time as there is already a SPContextFilter on every action.
I was initially saving current user details in a cookie (HttpOnly set to true) but got to know that anyone can edit it using browser extension and impersonate users.
I am pretty new to MVC so any help is appreciated.
I don't see any other way around, you will have to make a DB call for the first new request and for the subsequent requests save the user and role details in some persistent object. Consider using ViewState objects and maybe check for null before proceeding to make a database call and populating the ViewState again.
Always avoid saving user details in cookie. Check the user access with the db.
Create User Access Table to check whether the user has access or not
Use Action Filter, which will execute before the Action execute.
In controller
[RoleAccess]
public class AccountController : Controller
{
public ActionResult Index()
{
your code
}
}
The [RoleAccess] is a Action filter function.
In FilterConfig.cs
public class RoleAccessAttribute : ActionFilterAttribute
{
private ApplicationDbContext db = new ApplicationDbContext();
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var controllerName = (string)filterContext.RouteData.Values["controller"];
var actionName = (string)filterContext.RouteData.Values["action"];
var userID = HttpContext.Current.User.Identity.GetUserId();
if (access not accepted)
{
//return the user to access denied page
filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary {
{"controller","Error"},
{"action","Error403"}
});
}
}
}
If the access is accepted then the user is authorized to access the requested Action
hope this helps
I have a super simple Authentication Attribute that I'm trying to implement in an ASP.NET MVC 5 application and I'm having some trouble. I want the attribute to be applied globally, except for specific actions within a controller (for example the login form and the home page).
I've tried decorating the action with the [OverrideAuthentication] attribute with no luck. It gives me a redirect loop error because the application is still running the authentication on the login form, and keeps trying to redirect back to the login form over and over.
Has anyone else seen this behaviour? Any idea what I've stuffed up here?
By way of example, I've created a super simple filter that is currently unimplemented:
public class BasicAuthenticationAttribute
: ActionFilterAttribute, IAuthenticationFilter
{
public void OnAuthentication(AuthenticationContext filterContext)
{
throw new NotImplementedException();
}
public void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext)
{
throw new NotImplementedException();
}
}
If I decorate my controller/action like this:
[BasicAuthentication]
public class AccountController : Controller
{
[HttpGet]
[OverrideAuthentication]
public ActionResult Login()
{
return View();
}
}
I get a not implemented exception when I navigate to the Login action, even though that action shouldn't be running the authentication code at all. Have I misunderstood how overrides are supposed to work?
I think you have confused authentication with authorization (as many people do). It doesn't make sense to make a [BasicAuthenticationAttribute] and register it globally, because authentication only happens upon login, not on every request.
Authorization is what takes place after the user has logged in to check whether the user has the required privileges to do a specific action, and it makes sense to do authorization globally. Authorization in MVC is handled by the [AuthorizeAttribute] and you can inherit it if you need to customize the way the authorization check is done. You can also register it as a global filter.
The [AllowAnonymousAttribute] works in conjunction with [AuthorizeAttribute], and basically tells it to skip the authorization check. It should also be noted that the [AllowAnonymousAttribute] will have no effect unless it is used with the [AuthorizeAttribute].
I have been finding some solution to put security on basis of entity.Like a user can only access to entity to which it has access.
Rather than putting check on each and every action method can i control in centralized way. I am here talking about access entity using ajax call also. For example a user has opened a orderId 10 for that i have an hidden field if by any means if he changes the value of orderId to 11 he can access or modify order with orderId 11 while he was allowed to see only orderId 10 .
There are the time we just send some values along with main entity id for example getOrderByUserId(int userId) as this action method is in OrderController accessing order based on userId.
Please take look at AuthorizeAttribute and the roles in specific
usage :
[Authorize(Roles = "manager,admin")]
public ActionResult myMethod(){
// your code
}
And you can use the Users property and do something like this:
[Authorize(Users = UsersHelper.GetAllowedUsers)]
public ActionResult myMethod(){
// your code
}
where UsersHelper.GetAllowedUsers is a static class with a static method that returns users in format like this : "joe1,admin,momandpop"
update to OP comment :
/// <summary>
/// Checks if the current user is the owner of the Order
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class IsOwnerOfOrderAttribute : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
if (!(filterContext.Result is HttpUnauthorizedResult))
{
// code to check if user has the order he is trying to edit
// if not return this
filterContext.Result = new HttpUnauthorizedResult();
}
}
}
you can place this on top of a controller or a specific action.
you are not talking about entity based security but row-wise security as provided by mssql.
Entity Based security is if a user is allowed to edit, he will be able to edit any other id.
For this you have to maintain hierarchy of user roles and then storing the minimum role that can perform edit or any action on each row in the table.
Or if you want to block user from using query parameter, you can use parameter or session or TempData to transfer data between actions to transfer id and work.
I just wanted to gauge opinions on how I should approach this problem and ultimately looking for a quick win (wrong way to think about things nut time pressures mean I have to think and act quickly!
I've been given a website that has a bit of an issue.
I login using standard forms authentication as User1234 and my url is as follows:
www.mywebsite.co.uk/1234/Contact.
This will take me to User1234's details.
You can put two and two together and correctly assume that 1234 is a user id of some sort.
Once authenticated, I can access the views with [Authorize] attribute present, any anonymous/unathenticated users get redirected.
However, once logged in as User1234, I can then tinker with the url like so:
www.mywebsite.co.uk/1235/Contact.
So I am authenticated as User1234 but can see User1235's data. This is BAD for obvious reasons.
When I log in, I actively set the login ID in session so in theory, I could do a check whenever a user hits an ActionResult, I could cross check the ID present in the URL against the session login ID. However, it is a rather project with lots of action results and as such, I'm reluctant to spend my Saturday afternoon adding something to each and every ActionResult.
Is there an event in the global.asax I could use that is hit on each ActionResult request where I can compare Session login ID with url ID?
Alternatively, can anyone offer some suggestions about how I can achieve this or restrict URL tampering?
You can try and do a base controller
public class BaseController : Controller
{
protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
//Do your stuff here
base.OnActionExecuted(filterContext);
}
}
I assume that you don't want to change your URL routes, as you could retrieve the user id also from the session. A quick solution would be to use an ActionFilter which you can place on the affected controllers or action methods:
public class VerifyUserIdAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var sessionUserId = filterContext.HttpContext.Session["UserId"];
var routeUserId = filterContext.RouteData.Values["UserId"];
if (routeUserId != null && sessionUserId == routeUserId)
filterContext.Result = new RedirectResult("<<url to redirect to>>");
}
}
I don't understand why the URL contains a data entry point. This appears to be a design flaw. I would remove all code that uses a URL parameter and instead make sure the controller looks up what the ID is based on the logged in user.
I want to be able to globally access the logged-in user in (Controllers, HtmlHelpers and other helper classes) throughout the whole application without getting exceptions that User is null and with the ability to handle guests (not-logged-in users).
Should this be handled within my UsersRepository? If so, how to? or is there a better approach?
You can create custom identity and principal classes. Your custom identity class can extend whatever you are currently using and can then simply add the extra information you need.
Then in a global action filter, simply overwrite the current principal with your customized one. Then you can access it from anywhere like a normal identity, but if you need your additional information, you simply cast it to your custom identity class. Which will grant you access to your additional information.
You can write a custom action filter that is executed on every request (you register it as a global filter). This filter would load the user (from the user´s repository for example) and put it the http context for example or in the ViewData.
EDIT:
Ok, the code for the filter could look like this (in this case, it loads the user to the ViewData collection). I didn´t consider anonymous users here.
public class LoadUserToViewDataAttribute : ActionFilterAttribute
{
private IUserRepository _userRepository;
public LoadUserToViewDataAttribute(IUserRepository userRepository)
{
_userRepository = userRepository;
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var controller = filterContext.Controller;
var userName = filterContext.HttpContext.User.Identity.Name;
var user = _repository.GetUser(userName);
controller.ViewData.Add("CurrentUser", user);
}
}