I have added a new column called CompanyName to my AspNetUsers table. I'm looking to use this in queries within my API.
I have used the [Authorized] attribute to get
User.Identity.Name
This obviously gets the name of the user. I'm looking for a way to get the CompanyName.
Will I have to query the aspnetusers table directly to get this info?
You need to create an instance of your user in order to access user's properties, I use the UserManager class to create the user. There may be other ways to to get this done however this is what I have done in the past.
at the top of the controller class:
private Microsoft.AspNet.Identity.UserManager<YourApplication.Models.ApplicationUser> um = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));//new up a UserManager
now inside the action method:
public ActionResult Index()
{
ApplicationUser user = um.FindById(User.Identity.GetUserId());//Create an instance of the user
ViewBag.CompanyName = user.CompanyName ;//Read the property
return View();
}
The following way will help you to put custom data.
if this doesnt help, please provide more information. like the source code of where you create or where you retrieve it.
string username = HttpContext.Current.User.Identity.Name;
var identity = new MyIdentity(username, true);
var principal = new MyPrincipal(identity, identity.Roles);
HttpContext.Current.User = principal;
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 am trying to query the AspNetUsers table.
I have set up the db variable as follows
public ApplicationDbContext db = new ApplicationDbContext();
However, the intellisense for db does not list any of the Identity tables, but it does the others created for the web site (which are listed in IdenityModels.cs) e.g .......
public System.Data.Entity.DbSet<FeatureRequestMVC.Models.Feature> Features { get; set; }
How can I get the Identity tables (like AspNetUsers) listed in the db intellisense ?
Thanks
You can use the following code to instantiate the UserManager Class,
UserManager<ApplicationUser> userManager;
userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
Once you have added all the using statements required, you can call all sorts of methods to deal with Identity users.
// find user by id, also available for email and username
var user = await userManager.FindByIdAsync(Id param);
// with the user object above you can delete the referenced user
await userManager.DeleteAsync(user);
// Update user
await userManager.UpdateAsync(user);
All methods above use the async and await keyword
MSDN UserManager
Hope this helps.
The identity wants you to go through the UserManager for data, however there are cases where you need to query the identity tables. You can do something like
var sqlQuery = #"SELECT Users.UserName FROM AspNetUserClaims AS Claims
INNER JOIN AspNetUsers AS Users ON Claims.UserId = Users.Id
WHERE Claims.ClaimType = {0} AND Claims.ClaimValue = {1}";
var userName = dbContext.Database.SqlQuery<string>(sqlQuery, "MyClaimType", theClaimValue).ToList().FirstOrDefault();
This is pulling a single UserName and setting the variable as a string. You can create a model and pass that model into SqlQuery<T> as long as the property names match the column or alias names in your query.
My ApplicationUser class has a property called CompanyID.
All users are tied to a specific company. Now I'd like to list user accounts by CompanyID but can't figure out how to do it, UserManager.findxxx seem to be limited to whats built in and I can't seem to query it about custom properties.
Incase you extended the User model class with the CompanyId field:
var context = new ApplicationDbContext();
var usersByCompanyId = context.Users.Where(user => user.CompanyID == 1234).ToList();
use bottom code for get custom ApplicationUser in identity with custom property
var context=new AuthContext();
var result=context.Users.OfType<ApplicationUser>.SingleOrDefault(item => item.NationalCode == "");
(Using VS2013 RTW, ASP.NET MVC5)
I've seen lots of documentation on how to add properties to the ApplicationUser class (and table) when using ASP.NET identity. But I haven't seen any documentation on how to have a separate table with content that maps to the ApplicationUser table via a foreign key.
I've successfully derived my own Microsoft.AspNet.Identity.EntityFramework.IdentityDbContext, and now my own "UserPreferences" table coexists in harmony with the various "AspNet*" tables in my SQL Server database. But I'm not clear on the best way to get the current user's ID so as to write a new row to the "UserPreferences" table. Note that the project is ASP.NET MVC, but I've added (and am working inside of) a Web API controller.
I have a working solution, which is:
var uman = new Microsoft.AspNet.Identity.UserManager<Microsoft.AspNet.Identity.EntityFramework.IdentityUser>(new Microsoft.AspNet.Identity.EntityFramework.UserStore<Microsoft.AspNet.Identity.EntityFramework.IdentityUser>(new App1.Data.App1DbContext()));
var uident = User.Identity;
var userobject = uman.FindByNameAsync(uident.Name);
var userid = userobject.Result.Id;
// (Perform new row creation including the userid we just looked up
Consider that the AspNetUsers table (as defined by the Identity framework) consists of these fields:
-id (PK, nvarchar(128) - seems to contain a GUID, not sure why not an autoincrement integer, but I assume there are reasons for this)
-Username (nvarchar(max))
-PasswordHash (nvarchar(max))
-SecurityStamp (nvarchar(max))
I think that the id field (not the username) is the correct field to reference in this table. (I was thinking that a user may change his/her username, and someone else could then assume the other user's username, which is why both fields are there likely.) So then, I need to get the current user's ID for storage in the "UserPreferences" table, which is what the above code does. But it seems inefficient to have to do this lookup.
An important point is that in the context of a System.Web.Mvc.Controller, I can do:
User.Identity.GetUserId()
(Runtime type of User.Identity: System.Security.Principal.GenericIdentity)
But in the context of a System.Web.Http.ApiController (Web API), I cannot because that method does not exist (runtime type of User.Identity: System.Security.Claims.ClaimsIdentity) which is why I must rely instead on:
User.Identity.Name
and do the extra lookup to convert Name to ID. Does anyone have any suggestions for how this can be improved? Am I approaching the task of writing user data to separate tables in the correct way?
You should be able to get user id on both MVC controller and web api controller by same extension method in identity 1.0 RTW package.
Here is the extensions from identity package:
namespace Microsoft.AspNet.Identity
{
public static class IdentityExtensions
{
public static string FindFirstValue(this ClaimsIdentity identity, string claimType);
public static string GetUserId(this IIdentity identity);
public static string GetUserName(this IIdentity identity);
}
}
The IIdentity is the base interface for all identity types. You may need to add "using Microsoft.AspNet.Identity" in order to see the extension method.
BTW: regarding adding a foreign table for user, why not using ApplicationUser and add navigation property to UserPreference to let EF to handle their relationship? That will be easier.
ClaimsIdentity identity = new ClaimsIdentity(OAuthDefaults.AuthenticationType);
identity.AddClaim(new Claim(ClaimTypes.Name, userName));
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, UserID));
ClaimTypes.NameIdentifier is the claim for the function User.Identity.GetUserId()
I'm using claim base approach:
private ApplicationUser GetCurrentUser(ApplicationDbContext context)
{
var identity = User.Identity as ClaimsIdentity;
Claim identityClaim = identity.Claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier);
return context.Users.FirstOrDefault(u => u.Id == identityClaim.Value);
}
Short description for the best answer:
Install-Package Microsoft.AspNet.Identity.Core -Version 2.2.1
var userId = User.Identity.GetUserId();
Tried #Mastenka answer and it gave me nothing. I checked ClaimsIdentity and there were
claims type "UserName", so as a result, I get username by using "UserName" as ClaimsType.
Hope someone will give more info about it. It looks strange that "ClaimTypes.NameIdentifier" had no effect. (ApiController, ASP MVC API)
var userName = ((ClaimsIdentity)RequestContext.Principal.Identity).Claims.FirstOrDefault(cl => cl.Type == "UserName")?.Value;
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