I am using MVC 5 and have a View that contains a jQuery Ajax call to the controller and retrieve some data. Previously I was unable to make this Ajax GET because the controller is marked [Authorize], so I marked the method as [AllowAnonymous].
At this point I have a need to determine the authenticated user, but User.Identity shows IsAuthenticated = false. This makes sense, but I am needing to know how I can obtain the user's identity within this method. Here is the method:
[AllowAnonymous]
[AcceptVerbs(HttpVerbs.Get)]
public JsonResult GetDesignParams(string countrycode)
{
ApplicationUser user = UserManager.FindById(User.Identity.GetUserId());
if (user != null)
{
... do something ...
}
... do something else ...
return Json(rules, JsonRequestBehavior.AllowGet);
}
Is there a way of obtaining the user's identity within this routine without passing the user id from the client side Ajax GET?
You need to go through bearer tokens in order to make your API-like method secure
See this: Secure a Web API with Individual Accounts and Local Login
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
Hello guys I have a MVC actions that have Authorize attribute set on them. For each one of these actions there is a password/ security pin which is only valid for that Action.
public ActionResult Action_1()// generic pin 1
{
Return RedirectToAction("PinCheck", new { returnUrl = "Action_1" });
...
}
[Authorize]
public ActionResult Action_2()// generic pin 2
{
...
}
[Authorize]
public ActionResult PinCheck(string returnUrl)// generic pin 1
{
// request three characters of the pin in random.
...
}
[Authorize]
[HttpPost]
public ActionResult PinCheck(string a, string b, string c, string returnUrl)// generic pin 1
{
// check the three chars.
...
// How do I store pin check for the controller was a success and don't ask the user unless he closes browser or logout
}
My plan of action is checking pins stored by the Admin for the particular User for that particular Action in the Database. So far I have achieved checking PinCheck() routine but the problem I face is that the User has to enter the pin every time he requests that particular action. I made a way around this by saving an encrypted cookie on PinCheck success. But is there a way to modify the Authorize attribute and the Authentication cookie itself to achieve What I am doing?
You can also represent each Pin verified as a claim stored as part of the ClaimsIdentity in the cookie so that you can just query against the user's claims looking for the appropriate PinClaim in each Action. If you are using the ASP.NET Identity, you can do something like so when you verify the pin:
await manager.AddClaimAsync(User.Identity.GetUserId(), new Claim("<mypinclaim>", "<value>"))
await SignInAsync() // And then resign the user in to regenerate the cookie with the claim
One ways of doing this is by creating a custom role provider. You could create one by inheriting from RoleProvider. Then override IsUserInRole and optionally FindUsersInRole, GetAllRoles, GetUsersInRole to reflect your pin management logic.
Once done, register the custom role provide via the web.config.
A good article on custom role providers (http://bojanskr.blogspot.com.au/2011/12/custom-role-provider.html)
Given that the FormsAuthentication module fires before a custom http module that handles the OnAuthenticateRequest, I'm curious if one can cancel or invalidate the forms authentication based on my own criteria.
Basically I have a process where the user logs in. After that they get a token. I get the token back after the forms authentication fires upon subsequent requests. What I want to do is then validate that the token hasn't expired against our back end server. If it's expired I need to do something so that they are forced to log back in. My thought was to do something in my OnAuthenticateRequest handler that would get picked up later in the pipeline and force a redirect back to login page or something. Is that possible?
In an ASP.NET MVC application in order to handle custom Authentication and Authorization people usually write custom Authorize attributes. They don't deal with any OnAuthenticateRequest events. That's old school. And by the way if you are going to be doing some custom token authentication why even care about Forms Authentication? Why not replace it?
So:
public class MyAuthorizeAttribute: AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
string token = GetTokenFromHttpContext(httpContext);
if (IsTokenValid(token))
{
// The user has provided a valid token => you need to set the User property
// Obviously here based on the token value you already know which is the
// associated user and potential roles, so you could do additional checks
var identity = new GenericIdentity("john.smith");
var user = new GenericPrincipal(identity, new string[0]);
httpContext.User = user;
return true;
}
// Notice that here we are never calling the base AuthorizeCore method
// but you could call it if needed
return false;
}
private string GetTokenFromHttpContext(HttpContextBase httpContext)
{
// TODO: you know what to do here: get the token from the current HTTP Context
// depending on how the client passed it in: HTTP request header, query string parameter, cookie, ...
throw new NotImplementedException();
}
private bool IsTokenValid(string token)
{
// TODO: You know what to do here: go validate the token
throw new NotImplementedException();
}
}
Now all that's left is to decorate your controllers/actions with this custom attribute instead of using the default one:
[MyAuthorize]
public ActionResult SomeAction()
{
// if you get that far you could use the this.User property
// to access the currently authenticated user
...
}
Is that possible?
This is definitely possible. You could even set your autehtication scheme to None so that forms module isn't there in the pipeline and have only your own module.
However, even if forms is there, your custom module can override the identity set for the current request. Note also that until the forms cookie is issued, forms module doesn't set the identity. This was quite common to use both forms module and the SessionAuthenticationModule - forms does the job of redirecting to the login page and the session auth module handles its own authentication cookie.
This means that you can safely mix the two: the forms module and your own custom module for a similar scenario.
Darin suggests another approach and this of course is valid too. An advantage of an authentication module (versus the authentication filter) is that the authentication module could support other ASP.NET subsystems (web forms / wcf / webapi).
I hope someone will be able to put me on the right track, been trying to resolve this now for hours.
I am currently in the process of redeveloping a web application and I would like to use the MVC4 attributes for managing access to the various parts of the application.
The issue I am having is that the Authentication & Permissions are all handled by middle-ware applications that the web app has to interface with.
I was wondering if even with this restriction would I be able to use the security attributes & letting the web app know that the user is Authenticated.
Yes, you will be able to use existing Authorize attribute. All you have to do is write a custom Membership and Role providers that will use your existing services instead of relying on the default SQL database.
If you don't want to go through all this hassle you could also write a custom authorization attribute (deriving from AuthorizeAttribute) and inside the AuthorizeCore method call your service to check whether the current user has the desired roles.
Definitely. Not only is it possible, but also it's pretty easy. And if you can think of ASP.NET Roles as "activities", then you don't need to derive anything; everything you need is built in.
These examples assume securityService is the service that communicates with your middle-ware applications, and has two methods, GetUser and GetUserRoles:
Your Login action method
[HttpPost]
public ActionResult Login(LoginModel model, string returnUrl)
{
if (!ModelState.IsValid) return View();
var user = securityService.GetUser(model.Username, model.Password);
if (user == null)
{
ModelState.AddModelError("", "Username or password are incorrect.");
return View();
}
FormsAuthentication.SetAuthCookie(user.Username, model.Remember);
return Redirect(returnUrl);
}
In your Global.asax.cs
protected void Application_AuthenticateRequest()
{
if (Request.IsAuthenticated)
{
string username = User.Identity.Name;
string[] roles = securityService.GetUserRoles(username);
IIdentity identity = new GenericIdentity(username);
Context.User = new GenericPrincipal(identity, roles);
}
}
That's it. Login handles the authentication (when the user logs in), while Application_AuthenticateRequest handles the authorization (on every request). You then proceed to decorate your action methods with Authorize(Roles = "XYZ") making sure "XYZ" matches what comes back from your GetUserRoles method.
I write a controller like below:
public class AccountController : Controller
{
public ActionResult Login(/*---*/)
{
GenericIdentity identity = new GenericIdentity("userName");
GenericPrincipal principal = new GenericPrincipal(identity, new string[] { "role1", "role2" });
this.HttpContext.User = principal;
/*---*/;
}
}
After login, I can get user name by User.Identity.Name in other controller.
But User.IsInRole("role1") always return false.
How can I assign a value to User, I don't want to use Membership...
You need to persist the user data somewhere so that all subsequent page requests have access to it. Usually you would create an authentication ticket and store it in a cookie. Then for each request you extract the data and create your IPrincipal. This can be done in the Application_AuthenticateRequest method of Global.ascx,
MVC - How to store/assign roles of authenticated users has more information on a simple way to do what you want.
Hm.
Using membership?
At least the lower level API. You need to assign it a principal in some event (which basically turns into a cookie and is deserialized with every call).
Details are in http://support.microsoft.com/kb/306590
Or also in http://msdn.microsoft.com/en-us/library/aa302399.aspx