MVC - unable to query Identity tables - asp.net-mvc

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.

Related

Add property to Identity in MVC 5, using Entity framework

I'm using MVC 5 and EF 6 (Datafirst),using msssql management studio.
I created a new mvc project, which came up with built database (AspNetUsers etc)
I also created a new table called UserDetails, which it purpose to contain more details about the user by it's Id (so I created a link between AspNetUsers id column to UserDetails UserId column)
therefore I added the following code
public class ApplicationUser : IdentityUser
{
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
userIdentity.AddClaim(new Claim("FirstName", FirstName.ToString()));
return userIdentity;
}
//Extended Propeties
public string FirstName { get; set; }
}
But of course it's not working, I looked over the internet for over 4 hours now, can someone please guide me ? I'm new to MVC, everything seems to be complicated much.
I also have the following static method :
public static class IdentityExtensions
{
public static string GetFirstName(this IIdentity identity)
{
var claim = ((ClaimsIdentity)identity).FindFirst("FirstName");
// Test for null to avoid issues during local testing
return (claim != null) ? claim.Value : string.Empty;
}
}
in order to get it in the view and display it..
my goal is to display data from another table (UserDetails) in the view based on connection of 1-1 from AspNetUsers (UserDetails.UserId == AspNetUsers.Id)
All you have to do is extend the IdentityUser class, then add your custom properties like FirstName etc.. then since you are using EntityFramework Database first you need to enable the migrations with this command in your package manager console enable-migrations, then add an initial migration like add-migration initialMigration, after that update the database using migrations with this command update-database, the AspNetUsers table in your database will now have the new columns you added. Use migration to keep your database in sync with your models
if there is correct connection between both table you can use Eagerly Loading to get the details of one entity from another.

MVC6 Identity Custom Field Retrieval

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;

How to query existing table when using code first in entity framework

I am using Entity Framework 6 Code First. I created a separate table to contain the UserId from the aspnet_Users table and a field for Department. So the user listed with the departments have only access to those departments.
Since all of my table are generated via code first and is using the db.context. The membership and roles are pre-generated table from MVC. How to I get a list of UserId from the aspnet_Users table when it's not in the db.context? The aspnet tables are pre-generated via a script in the entity framework.
How do I query tables in MVC outside of my db.context?
Your DbContext will have a Database property. Off of that you will find two overloads for general SQL queries:
DbRawSqlQuery SqlQuery (Type elementType, string sql, params object[] parameters);
DbRawSqlQuery<T> SqlQuery<T>(string sql, params object[] parameters);
For example:
var result = ctx.Database.SqlQuery<Foo>("select * from foo");
More information here
Since you are using .Net Membership, you could always call the
MembershipProvider.GetAllUsers(int pageIndex, int pageSize, out int totalRecords)
Then from that result, generate a list of UserIds. The role provider also offers similar functionality with a Roles.GetAllRoles() method.
The membership provider and role provider offer many more useful methods to hopefully get you the data you are looking for. If they still don't have what you are after you have a couple of more options. You can use your db context to execute raw SQL. See MSDN for more info.
Another option is to create additional entity classes that match the DB structure of those tables, and add them to your DB Context. The downside to this approach is it could allow another developer, or even yourself to create and update users and roles without going through the proper providers, in which case you would lose some functionality. If that is a concern, you could always create a DB View and map to that to ensure read only access. It's a bit more overhead, but does give you type safety and a familiar way to query the data.
Here is what I did to get the complete solution I wanted:
To query the data:
string sql = "Select UserId, UserName from aspnet_users where applicationid='" + Config.Instance.AppId() + "'";
using (var context = new NameSystemContext())
{
var users = context.Database.SqlQuery<AspnetUser>(sql);
ViewBag.UserId = new SelectList(users, "UserId", "UserName").ToList();
}
In your view models or somewhere define a class:
class AspnetUser
{
[Key]
//[Column(Order = 1)]
public Guid UserId { get; set; }
//[Key]
//[Column(Order = 2)]
public string UserName { get; set; }
}
//ViewBag.UserId could be use in the view
#Html.DropDownList("UserId", null, "Select...", htmlAttributes: new { #class = "form-control" })

ASP.NET MVC - How does WebSecurity work?

I have an ASP.NET MVC 4 project which I have successfully connected to a MySQL database. I have done this by adding a ADO.NET/EntityFramework class which created a Model.edmx object.
Within the database, I have created a table called user which holds what you should expect in a User table such as Email, UserName, Password, FirstName. etc etc.
I have created some dummy records and added the following code to the Login method within the AccountController:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginModel model, string returnUrl)
{
if (ModelState.IsValid)
{
var database = new Database();
user user = database.SelectByUserName(model.UserName).FirstOrDefault<user>();
var hash = Utilities.HashPassword(model.Password, user.Salt);
if (hash == user.Password && WebSecurity.Login(user.UserName, user.Password))
{
//Correct Login Details!
RedirectToAction("About", "Home");
}
}
// If we got this far, something failed, redisplay form
ModelState.AddModelError("", "The user name or password provided is incorrect.");
return View(model);
}
For some reason, the WebSecurity.Login method returns false and the user isn't redirected to the Home page.
Why is it returning false? What am I missing and how would the WebSecurity.Login even know what credentials are required i.e. How does it even know that it should look inside the user table which I created?
WebSecurity doesn't default to looking at your database, it will actually make it's own tables using the DefaultConnection that is defined in Web.Config. To work around this you need to add a new connection string Web.Config and then during app initialization force WebSecurity to look at that connection.
The easiest way to accomplish this, assuming you have a MySQL specific connection string in your Web.Config named "AccountConnection" is by adding the following to your Application_Start()
LazyInitializer.EnsureInitialized(ref _initializer, ref _isInitialized, ref _initializerLock);
And then you'll need the following fields and function:
private static SimpleMembershipInitializer _initializer;
private static object _initializerLock = new object();
private static bool _isInitialized;
private class SimpleMembershipInitializer
{
public SimpleMembershipInitializer()
{
Database.SetInitializer<UsersContext>(null);
try
{
using (var context = new UsersContext())
{
if (!context.Database.Exists())
{
// Create the SimpleMembership database without Entity Framework migration schema
((IObjectContextAdapter)context).ObjectContext.CreateDatabase();
}
}
// Overload is: Web.Config Connection string by name, user table name, user id column name, user name column name, auto create missing tables
WebSecurity.InitializeDatabaseConnection("AccountConnection", "UserProfile", "UserId", "Email", autoCreateTables: true);
}
catch (Exception ex)
{
throw new InvalidOperationException("The Membership database could not be initialized.", ex);
}
}
}
Whether you can make WebSecurity work with MySQL I have no idea, though I believe I've read some place that it is supported.
Note: the UserContext should have been auto generated when you installed WebSecurity into your solution. If not it's a CodeFirst model that you can easily add.
There are one of two reasons your code will not work. Understand that WebSecurity and SimpleMembershipProvider (assuming you are using it) uses PBKDF2 algorithm to populate the password field when you call WebSecurity.CreateUserAndAccount or WebSecurity.CreateAccount.
So Either:
You did not use one of these two methods to create the user, in which case WebSecurity.Login will almost always fail (99.99%).
or
You did use one of the methods above and the code in Utilities.HashPassword() (which seems redundant since the Create Account methods listed above hash passwords anyway...) does not hash the password Exactly the same way WebSecurity does so hash == user.Password will always fail.

ASP.NET (OWIN) Identity: How to get UserID from a Web API controller?

(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;

Resources