I am getting UserId not found error after registring a user and also after login.Moreoever, after registration, data is saved to database and in dbo.AspNetUsers table, id column is auto incremented and return type is int.
There is UserId Column in AspNetUserClaims table.It has 4 Col---Id,UserId,ClaimType,ClaimValue.It has Id column as auto incremented not the userId.
I was initially successfully changed Primary key from string to int by following this link---http://www.asp.net/identity/overview/extensibility/change-primary-key-for-users-in-aspnet-identity.
It was running succesfully before but now it is giving me error at this line---
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser, int> 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
return userIdentity;
}
Exception Details: System.InvalidOperationException: UserId not found.
This is the complete stack trace. you can see it here----http://pastebin.com/0hp5eAnp
It was working fine earlier but now when i added foreign key relationship with other tables, i don't know what is missing there. In the database all the tables are created properly with proper relationship between them but something is missing here.
My ApplicationUser class is something like this-------
public class ApplicationUser : IdentityUser<int, CustomUserLogin, CustomUserRole, CustomUserClaim>
{
public ApplicationUser()
{
this.Posts = new HashSet<Post>();
}
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public virtual ICollection<Post> Posts { get; set; }
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser, int> 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
return userIdentity;
}
public class CustomUserRole : IdentityUserRole<int> { }
public class CustomUserClaim : IdentityUserClaim<int> { }
public class CustomUserLogin : IdentityUserLogin<int> { }
public class CustomRole : IdentityRole<int, CustomUserRole>
{
public CustomRole() { }
public CustomRole(string name) { Name = name; }
}
public class CustomUserStore : UserStore<ApplicationUser, CustomRole, int,
CustomUserLogin, CustomUserRole, CustomUserClaim>
{
public CustomUserStore(ApplicationDbContext context)
: base(context)
{
}
}
public class CustomRoleStore : RoleStore<CustomRole, int, CustomUserRole>
{
public CustomRoleStore(ApplicationDbContext context)
: base(context)
{
}
}
and my IdentityConfig.cs class file is something like this-------
// Configure the application user manager used in this application. UserManager is defined in ASP.NET Identity and is used by the application.
public class ApplicationUserManager : UserManager<ApplicationUser, int>
{
public ApplicationUserManager(IUserStore<ApplicationUser, int> store)
: base(store)
{
}
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
{
var manager = new ApplicationUserManager(new CustomUserStore(context.Get<ApplicationDbContext>()));
// Configure validation logic for usernames
manager.UserValidator = new UserValidator<ApplicationUser, int>(manager)
{
AllowOnlyAlphanumericUserNames = false,
RequireUniqueEmail = true
};
// Configure validation logic for passwords
manager.PasswordValidator = new PasswordValidator
{
RequiredLength = 1,
//RequireNonLetterOrDigit = true,
//RequireDigit = true,
//RequireLowercase = true,
//RequireUppercase = true,
};
// Configure user lockout defaults
manager.UserLockoutEnabledByDefault = true;
manager.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5);
manager.MaxFailedAccessAttemptsBeforeLockout = 5;
// Register two factor authentication providers. This application uses Phone and Emails as a step of receiving a code for verifying the user
// You can write your own provider and plug it in here.
manager.RegisterTwoFactorProvider("Phone Code", new PhoneNumberTokenProvider<ApplicationUser, int>
{
MessageFormat = "Your security code is {0}"
});
manager.RegisterTwoFactorProvider("Email Code", new EmailTokenProvider<ApplicationUser, int>
{
Subject = "Security Code",
BodyFormat = "Your security code is {0}"
});
manager.EmailService = new EmailService();
manager.SmsService = new SmsService();
var dataProtectionProvider = options.DataProtectionProvider;
if (dataProtectionProvider != null)
{
manager.UserTokenProvider =
new DataProtectorTokenProvider<ApplicationUser, int>(dataProtectionProvider.Create("ASP.NET Identity"));
}
return manager;
}
}
// Configure the application sign-in manager which is used in this application.
public class ApplicationSignInManager : SignInManager<ApplicationUser, int>
{
public ApplicationSignInManager(ApplicationUserManager userManager, IAuthenticationManager authenticationManager)
: base(userManager, authenticationManager)
{
}
public override Task<ClaimsIdentity> CreateUserIdentityAsync(ApplicationUser user)
{
return user.GenerateUserIdentityAsync((ApplicationUserManager)UserManager);
}
public static ApplicationSignInManager Create(IdentityFactoryOptions<ApplicationSignInManager> options, IOwinContext context)
{
return new ApplicationSignInManager(context.GetUserManager<ApplicationUserManager>(), context.Authentication);
}
}
i have seen many stackoverflow answers but not getting it to work.Can someone plzz plzz see what is missing, what should i do now.thanks in advance.
Here, in the applicationUser class, at the Id column, it showing some warning and message in tooltip like this-------
models.ApplicationUSer.ID hides inherited member
Microsoft.Aspnet.Identity.EntityFramework.IDentity
USer.Id. To make current member override
that implementation, add override keyword otherwise
add new keyword where x is just the namespace.
My StartUp.Auth.cs in App_Start folder is like this------
public partial class Startup
{
public void ConfigureAuth(IAppBuilder app)
{
// Configure the db context, user manager and signin manager to use a single instance per request
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
// Enable the application to use a cookie to store information for the signed in user
// and to use a cookie to temporarily store information about a user logging in with a third party login provider
// Configure the sign in cookie
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
Provider = new CookieAuthenticationProvider
{
// Enables the application to validate the security stamp when the user logs in.
// This is a security feature which is used when you change a password or add an external login to your account.
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser, int>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentityCallback: (manager, user) => user.GenerateUserIdentityAsync(manager), getUserIdCallback:(id)=>(id.GetUserId<int>()))
}
});
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
// Enables the application to temporarily store user information when they are verifying the second factor in the two-factor authentication process.
app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5));
// Enables the application to remember the second login verification factor such as phone or email.
// Once you check this option, your second step of verification during the login process will be remembered on the device where you logged in from.
// This is similar to the RememberMe option when you log in.
app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie);
// Uncomment the following lines to enable logging in with third party login providers
//app.UseMicrosoftAccountAuthentication(
// clientId: "",
// clientSecret: "");......................................................................
and my startUp.cs file is like this----
[assembly: OwinStartupAttribute(typeof(WebApp.Startup))]
namespace WebApp
{
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
}
}
}
You will have to pull out your ApplicationUserManager to have it nice and clean and implement more methods... For example see following post (It implemented all methods with your custom Key (TKey in the example):
http://www.symbolsource.org/MyGet/Metadata/aspnetwebstacknightly/Project/Microsoft.AspNet.Identity.Core/2.0.0-beta1-140211/Release/Default/Microsoft.AspNet.Identity.Core/Microsoft.AspNet.Identity.Core/UserManager.cs?ImageName=Microsoft.AspNet.Identity.Core
You will see that the error you receive GetSecurityStampAsync also is implemented there.
Related
I am trying to send permissions for documentdb for a specific user from my azure server to my client app, which are xamarin forms.
On server side everything looks good and I can see users specific permissions and token.
But when permissions are received in the client, the token is stripped away, why?
I am new with documentdb so hopefully it is just me.
I am using an Azure Mobile App service as backend.
My backend controller returns an object holding properties for documentdb database including a list of permissions for the user.
public class DbConfig
{
public string DatabaseName { get; set; }
public string CollectionId { get; set; }
public string EndpointUri { get; set; }
public IList<Permission> Permissions { get; set; }
}
I create a permission for a user for the entire collection if not already created.
public async Task<Permission> CreatePermissionAsync(string resourceLink, string userLink, PermissionMode mode, string resourcePartitionKey = null)
{
try
{
Permission permission = new Permission
{
Id = Guid.NewGuid().ToString("N"),
PermissionMode = mode,
ResourceLink = resourceLink
};
if (resourcePartitionKey != null)
{
permission.ResourcePartitionKey = new PartitionKey(resourcePartitionKey);
}
var result = await client.CreatePermissionAsync(userLink, permission);
DbConfig.Permissions.Add(result);
return result;
}
catch (Exception e)
{
Trace.WriteLine($"##### Exception: {e}");
throw;
}
}
I retrieve permissions for a user with this method.
public List<Permission> GetPermissionsForUserPermissionLink(User user)
{
var permFeed = client.CreatePermissionQuery(user.PermissionsLink);
List<Permission> permList = new List<Permission>();
foreach (Permission perm in permFeed)
{
permList.Add(perm);
DbConfig.Permissions.Add(perm);
}
return permList;
}
On the client side in my Xamarin forms app i use this call to my custom controller in the backend.
var parameters = new Dictionary<string, string> { { "userid", Settings.AzureUserId } };
dbConfig = await client.InvokeApiAsync<DbConfig>("Settings", HttpMethod.Get, parameters);
When i look at the permissionlist in the dbConfig object the token for a permission is null. My thought was that I could instantiate a documentdb client based on the permissionslist but it fails.
public void CreateDocumentDbClient(DbConfig config)
{
client = new DocumentClient(new Uri(config.EndPointUri), config.Permissions);
collectionLink = UriFactory.CreateDocumentCollectionUri(config.DatabaseName, config.CollectionId);
IsInitialized = true;
}
EDITS MADE FROM ANSWER
Just for finish up upon question.
I created a custom class holding both Permission and Token
public class PermissionCustom
{
public Permission Permission { get; set; }
public string Token { get; set; }
}
This makes it possible to create a documentdb client like this:
client = new DocumentClient(new Uri(config.EndPointUri), config.Permissions[0].Token);
So far so good :-) but it doesn't makes it easier to secure your database considering users could have many permissions for different resources. Even though it is properly to make it more secure, the token is readonly in the first place.
According to your code, I have checked this issue and found I could encounter the same issue. When you invoke client.InvokeApiAsync<DbConfig>("Settings", HttpMethod.Get, parameters);, you would send request with the following link:
https://{your-app-name}.azurewebsites.net/api/settings?userid={Settings.AzureUserId}
By using fiddler you could find that the token has been sent to your mobile client as follows:
But when deserialize it to Permission, the token has not been initialized correctly. I found that the token property is read only as follows:
In summary, I recommend that you need to define your custom Permission class and refer to the Permission class provided by DocumentDB client SDK for defining the properties you need within your custom permission class in your mobile client.
I structured my project into multiple mobile services, grouped by the application type eg:
my-core.azure-mobile.net (user, device)
my-app-A.azure-mobile.net (sales, order, invoice)
my-app-B.azure-mobile.net (inventory & parts)
I'm using custom authentication for all my services, and I implemented my own SSO by setting the same master key to all 3 services.
Things went well when I tested using REST client, eg. user who "logged in" via custom api at my-core.azure-mobile.net is able to use the returned JWT token to access restricted API of the other mobile services.
However, in my xamarin project, only the first (note, in sequence of creation) MobileServiceClient object is working properly (eg. returning results from given table). The client object are created using their own url and key respectively, and stored in a dictionary.
If i created client object for app-A then only create for app-B, I will be able to perform CRUD+Sync on sales/order/invoice entity, while CRUD+Sync operation on inventory/part entity will just hang there. The situation is inverse if I swap the client object creation order.
I wonder if there is any internal static variables used within the MobileServiceClient which caused such behavior, or it is a valid bug ?
=== code snippet ===
public class AzureService
{
IDictionary<String, MobileServiceClient> services = new Dictionary<String, MobileServiceClient>();
public MobileServiceClient Init (String key, String applicationURL, String applicationKey)
{
return services[key] = new MobileServiceClient (applicationURL, applicationKey);
}
public MobileServiceClient Get(String key)
{
return services [key];
}
public void InitSyncContext(MobileServiceSQLiteStore offlineStore)
{
// Uses the default conflict handler, which fails on conflict
// To use a different conflict handler, pass a parameter to InitializeAsync.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=521416
var syncHandler = new MobileServiceSyncHandler ();
foreach(var client in services) {
client.Value.SyncContext.InitializeAsync (offlineStore, syncHandler);
}
}
public void SetAuthenticationToken(String uid, String token)
{
var user = new MobileServiceUser(uid);
foreach(var client in services) {
client.Value.CurrentUser = user;
client.Value.CurrentUser.MobileServiceAuthenticationToken = token;
}
}
public void ClearAuthenticationToken()
{
foreach(var client in services) {
client.Value.CurrentUser = null;
}
}
}
=== more code ===
public class DatabaseService
{
public static MobileServiceSQLiteStore LocalStore = null;
public static string Path { get; set; }
public static ISet<IEntityMappingProvider> Providers = new HashSet<IEntityMappingProvider> ();
public static void Init (String dbPath)
{
LocalStore = new MobileServiceSQLiteStore(dbPath);
foreach(var provider in Providers) {
var types = provider.GetSupportedTypes ();
foreach(var t in types) {
JObject item = null;
// omitted detail to create JObject using reflection on given type
LocalStore.DefineTable(tableName, item);
}
}
}
}
=== still code ===
public class AzureDataSyncService<T> : IAzureDataSyncService<T>
{
public MobileServiceClient ServiceClient { get; set; }
public virtual Task<List<T>> GetAll()
{
try
{
var theTable = ServiceClient.GetSyncTable<T>();
return theTable.ToListAsync();
}
catch (MobileServiceInvalidOperationException msioe)
{
Debug.WriteLine("GetAll<{0}> EXCEPTION TYPE: {1}, EXCEPTION:{2}", typeof(T).ToString(), msioe.GetType().ToString(), msioe.ToString());
}
catch (Exception e)
{
Debug.WriteLine("GetAll<{0}> EXCEPTION TYPE: {1}, EXCEPTION:{2}", typeof(T).ToString(), e.GetType().ToString(), e.ToString());
}
List<T> theCollection = Enumerable.Empty<T>().ToList();
return Task.FromResult(theCollection);
}
}
=== code ===
public class UserService : AzureDataSyncService<User>
{
}
public class PartService : AzureDataSyncService<Part>
{
}
const string coreApiURL = #"https://my-core.azure-mobile.net/";
const string coreApiKey = #"XXXXX";
const string invApiURL = #"https://my-inventory.azure-mobile.net/";
const string invApiKey = #"YYYYY";
public async void Foo ()
{
DatabaseService.Providers.Add (new CoreDataMapper());
DatabaseService.Providers.Add (new InvDataMapper ());
DatabaseService.Init (DatabaseService.Path);
var coreSvc = AzureService.Instance.Init ("Core", coreApiURL, coreApiKey);
var invSvc = AzureService.Instance.Init ("Inv", invApiURL, invApiKey);
AzureService.Instance.InitSyncContext (DatabaseService.LocalStore);
AzureService.Instance.SetAuthenticationToken("AAA", "BBB");
UserService.Instance.ServiceClient = coreSvc;
PartService.Instance.ServiceClient = invSvc;
var x = await UserService.GetAll(); // this will work
var y = await PartService.GetAll(); // but not this
}
It's ok to use multiple MobileServiceClient objects, but not with the same local database. The offline sync feature uses a particular system tables to keep track of table operations and errors, and it is not supported to use the same local store across multiple sync contexts.
I'm not totally sure why it is hanging in your test, but it's possible that there is a lock on the local database file and the other sync context is waiting to get access.
You should instead use different local database files for each service and doing push and pull on each sync context. With your particular example, you just need to move LocalStore out of DatabaseService and into a dictionary in AzureService.
In general, it seems like an unusual design to use multiple services from the same client app. Is there a particular reason that the services need to be separated from each other?
Been stuck with that error till madness phases ... Please help
I have created an Azure Mobile Service .NET backend, and am now trying to call its Post function from a Xamarin Android client
I initialize and call the Insert async function (these are just snippets from my code)
private static IMobileServiceTable<Todo> _todoMobileServiceTable;
public static bool? InitializeAms()
{
try
{
CurrentPlatform.Init();
_mobileServiceClient = new MobileServiceClient(applicationUrl, applicationKey);
_todoMobileServiceTable = _mobileServiceClient.GetTable<Todo>();
return true;
}
catch (MalformedURLException malformedUrlException)
{
ReportHelper.Report(Tag, "There was an error creating the Mobile Service. Verify the URL", true, malformedUrlException);
}
catch (Exception exception)
{
ReportHelper.Report(Tag, "Error occurred during initialization of Azure Mobile Services", true, exception);
}
return null;
}
_todoMobileServiceTable.InsertAsync(Todo);
I get the following error when calling .InsertAsync(Todo)
The request could not be completed. (Not Found)
N.B:
Azure storage client is not available for xamarin yet, and I have no other choice other than to use this dirty fork which is 1 year old and is made for iOS not Android (although it works fine with azure mobile service javascript) https://github.com/zgramana/IOSAzureBlobUploader
It works if I use the browser 'try it out' button but it doesn't work when I call it from the xamarin client app.
It works from the xamarin client app if I use the javascript mobile service
This error occurs both on the local azure mobile service and the published one online
Here is the WebApiConfig class
namespace Service.Ams
{
public static class WebApiConfig
{
public static void Register()
{
// Use this class to set configuration options for your mobile service
ConfigOptions options = new ConfigOptions();
// Use this class to set WebAPI configuration options
HttpConfiguration config = ServiceConfig.Initialize(new ConfigBuilder(options));
// To display errors in the browser during development, uncomment the following
// line. Comment it out again when you deploy your service for production use.
config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
Database.SetInitializer(new ServiceAmsInitializer());
}
}
public class ServiceAmsInitializer : ClearDatabaseSchemaIfModelChanges<ServiceAmsDbContext>
{}
}
Here is the TableController class
namespace Service.Ams.Controllers
{
public class TodoItemController : TableController<TodoItem>
{
protected override void Initialize(HttpControllerContext controllerContext)
{
base.Initialize(controllerContext);
ServiceAmsDbContext serviceAmsDbContext = new ServiceAmsDbContext();
DomainManager = new EntityDomainManager<TodoItem>(serviceAmsDbContext, Request, Services);
}
// GET tables/TodoItem
[AuthorizeLevel(AuthorizationLevel.Admin)]
public IQueryable<TodoItem> GetAllTodoItems()
{
return Query();
}
// GET tables/TodoItem/55D11C86-6EA6-4C44-AA33-337FC9A27525
[AuthorizeLevel(AuthorizationLevel.Admin)]
public SingleResult<TodoItem> GetTodoItem(string id)
{
return Lookup(id);
}
// PATCH tables/TodoItem/55D11C86-6EA6-4C44-AA33-337FC9A27525
[AuthorizeLevel(AuthorizationLevel.Admin)]
public Task<TodoItem> PatchTodoItem(string id, Delta<TodoItem> patch)
{
return UpdateAsync(id, patch);
}
// POST tables/TodoItem/55D11C86-6EA6-4C44-AA33-337FC9A27525
[AuthorizeLevel(AuthorizationLevel.Anonymous)]
public async Task<IHttpActionResult> PostTodoItem(TodoItem item)
{
string storageAccountName;
string storageAccountKey;
// Try to get the Azure storage account token from app settings.
if (
!(Services.Settings.TryGetValue("STORAGE_ACCOUNT_NAME", out storageAccountName) |
Services.Settings.TryGetValue("STORAGE_ACCOUNT_ACCESS_KEY", out storageAccountKey)))
Services.Log.Error("Could not retrieve storage account settings.");
// Set the URI for the Blob Storage service.
Uri blobEndpoint = new Uri(string.Format("http://127.0.0.1:10000/{0}/", storageAccountName));
// Create the BLOB service client.
CloudBlobClient blobClient = new CloudBlobClient(blobEndpoint, new StorageCredentials(storageAccountName, storageAccountKey));
// Create a container, if it doesn't already exist.
CloudBlobContainer container = blobClient.GetContainerReference(item.ContainerName);
await container.CreateIfNotExistsAsync();
// Create a shared access permission policy.
BlobContainerPermissions containerPermissions = new BlobContainerPermissions
{
PublicAccess = BlobContainerPublicAccessType.Blob
};
// Enable anonymous read access to BLOBs.
container.SetPermissions(containerPermissions);
// Define a policy that gives write access to the container for 5 minutes.
SharedAccessBlobPolicy sasPolicy = new SharedAccessBlobPolicy
{
SharedAccessStartTime = DateTime.UtcNow,
SharedAccessExpiryTime = DateTime.UtcNow.AddMinutes(5),
Permissions = SharedAccessBlobPermissions.Write
};
// Get the SAS as a string.
item.SasQueryString = container.GetSharedAccessSignature(sasPolicy);
// Set the URL used to store the image.
item.ImageLqUri = string.Format("{0}{1}/{2}", blobEndpoint, item.ContainerName, item.ResourceNameLq);
item.ImageHqUri = string.Format("{0}{1}/{2}", blobEndpoint, item.ContainerName, item.ResourceNameHq);
// Complete the insert operation.
TodoItem current = await InsertAsync(item);
return CreatedAtRoute("Tables", new {id = current.Id}, current);
}
// DELETE tables/TodoItem/55D11C86-6EA6-4C44-AA33-337FC9A27525
[AuthorizeLevel(AuthorizationLevel.Admin)]
public Task DeleteTodoItem(string id)
{
return DeleteAsync(id);
}
}
}
Here is the EntityData class
namespace Service.Ams.DataObjects
{
[Table("dbo.TodoItems")]
public class TodoItem : EntityData
{
public string ContainerName { get; set; }
public string ResourceNameLq { get; set; }
public string ResourceNameHq { get; set; }
public string SasQueryString { get; set; }
public string ImageLqUri { get; set; }
public string ImageHqUri { get; set; }
}
}
Is there any way you can get a dump of what the HTTP request looks like?
I don't have an android client handy here but we can have a look on Monday.
Henrik
TableController and client corresponding class must have the same name for example TodoController and TodoClass. I don't know if there is an attribute that modifies this rule and how to use, if at server side decorating TableController class or at client side decorating data class.
This is a continuation of this question.
If I override the userManager:
public class NHibernateAspnetUserManager<TUser> : UserManager<TUser> where TUser : IdentityUser
{
public NHibernateAspnetUserManager(IUserStore<TUser> store) : base(store)
{
}
public override Task<ClaimsIdentity> CreateIdentityAsync(TUser user, string authenticationType)
{
var identity = new ClaimsIdentity();
identity.AddClaim(new Claim(ClaimTypes.Name, user.UserName));
return Task.FromResult(identity);
}
}
This doesn't throw any errors but will not log the user in, (log process happens but #Request.IsAuthenticated will always return false). If I don't override it then I get a "System.Security.Claims.Claim..ctor" error as described in the other question. To try and solve that my own userstore implemented IUserClaimStore but simply return a new list of claims.
I am not sure what the default usermanager does under the hood that differs. I am guessing it sets up some form of claim identity object that allows MVC to recognise someone as logged in.
var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
AuthenticationManager.SignIn(new AuthenticationProperties { IsPersistent = isPersistent}, identity);
EDIT
Found out why the ctor error was occuring. The user object was coming back without the ID so the default UserManager was getting upset. Fixed that and used the default UserManager which now no longer throws an error, but still doesn't log the user in. The identity object it returns looks good from what I can tell.
FURTHER NOTE
So I installed VS2013 and copied the store and NHibernate repo across, all worked first time. I can only assume there is some sutble difference between creating it and updating MVC5 in VS2012 and doing it in VS2013.
So the main issue is that you aren't respecting the authentication type in your method, you need to create a ClaimsIdentity for DefaultAuthenticationType.ApplicationCookie, here's what the default claims factory does:
public override Task<ClaimsIdentity> CreateIdentityAsync(TUser user, string authenticationType)
{
var id = new ClaimsIdentity(authenticationType, UserNameClaimType, RoleClaimType);
id.AddClaim(new Claim(UserIdClaimType, ConvertIdToString(user.Id), ClaimValueTypes.String));
id.AddClaim(new Claim(UserNameClaimType, user.UserName, ClaimValueTypes.String));
I've faced the same problem implementing custom identity using ASP.NET 4.5. And the problem really was in adding null values into the Claims collection (see the comments):
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new AppUser { UserName = model.UserName };
// after the UserManager creates a user, all the properties of
// AppUser except "UserName" are automatically discarded
var result = await UserManager.CreateAsync(new AppUser
{
UserRealName = model.UserRealName,
UserName = model.UserName,
Password = model.Password
}, model.Password);
if (result.Succeeded)
{
// So we need to re-get the new user
user = AppUser.GetByName(model.UserName);
await SignInAsync(user, false); // otherwise here we will add null values ...
return RedirectToAction("Index", "Home");
}
AddErrors(result);
}
return View(model);
}
private async Task SignInAsync(AppUser user, Boolean isPersistent)
{
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
var identity = await UserManager.CreateIdentityAsync(user,
DefaultAuthenticationTypes.ApplicationCookie);
AuthenticationManager.SignIn(new AuthenticationProperties // ... into the list of
// claims for all AppUser properties except UserName
{ IsPersistent = isPersistent }, identity);
}
Using the new ASP.net Identity in MVC 5, How do we disable a user from logging in? I don't want to delete them, maybe just disable their account for a time period.
Does anyone have any ideas on this as I don't see a status column or anything on the ASPNetUsers table.
await userManager.SetLockoutEnabledAsync(applicationUser.Id, true);
await userManager.SetLockoutEndDateAsync(DateTime.Today.AddYears(10));
Update: As CountZero points out, if you're using v2.1+, then you should try and use the lockout functionality they added first, before trying the solution below. See their blog post for a full sample: http://blogs.msdn.com/b/webdev/archive/2014/08/05/announcing-rtm-of-asp-net-identity-2-1-0.aspx
Version 2.0 has the IUserLockoutStore interface that you can use to lockout users, but the downside is that there is no OOB functionality to actually leverage it beyond the pass-through methods exposed by the UserManager class. For instance, it would be nice if it would actually increment the lockout count as a part of the standard username/password verification process. However, it's fairly trivial to implement yourself.
Step #1: Create a custom user store that implements IUserLockoutStore.
// I'm specifying the TKey generic param here since we use int's for our DB keys
// you may need to customize this for your environment
public class MyUserStore : IUserLockoutStore<MyUser, int>
{
// IUserStore implementation here
public Task<DateTimeOffset> GetLockoutEndDateAsync(MyUser user)
{
//..
}
public Task SetLockoutEndDateAsync(MyUser user, DateTimeOffset lockoutEnd)
{
//..
}
public Task<int> IncrementAccessFailedCountAsync(MyUser user)
{
//..
}
public Task ResetAccessFailedCountAsync(MyUser user)
{
//..
}
public Task<int> GetAccessFailedCountAsync(MyUser user)
{
//..
}
public Task<bool> GetLockoutEnabledAsync(MyUser user)
{
//..
}
public Task SetLockoutEnabledAsync(MyUser user, bool enabled)
{
//..
}
}
Step #2: Instead of UserManager, use the following class in your login/logout actions, passing it an instance of your custom user store.
public class LockingUserManager<TUser, TKey> : UserManager<TUser, TKey>
where TUser : class, IUser<TKey>
where TKey : IEquatable<TKey>
{
private readonly IUserLockoutStore<TUser, TKey> _userLockoutStore;
public LockingUserManager(IUserLockoutStore<TUser, TKey> store)
: base(store)
{
if (store == null) throw new ArgumentNullException("store");
_userLockoutStore = store;
}
public override async Task<TUser> FindAsync(string userName, string password)
{
var user = await FindByNameAsync(userName);
if (user == null) return null;
var isUserLockedOut = await GetLockoutEnabled(user);
if (isUserLockedOut) return user;
var isPasswordValid = await CheckPasswordAsync(user, password);
if (isPasswordValid)
{
await _userLockoutStore.ResetAccessFailedCountAsync(user);
}
else
{
await IncrementAccessFailedCount(user);
user = null;
}
return user;
}
private async Task<bool> GetLockoutEnabled(TUser user)
{
var isLockoutEnabled = await _userLockoutStore.GetLockoutEnabledAsync(user);
if (isLockoutEnabled == false) return false;
var shouldRemoveLockout = DateTime.Now >= await _userLockoutStore.GetLockoutEndDateAsync(user);
if (shouldRemoveLockout)
{
await _userLockoutStore.ResetAccessFailedCountAsync(user);
await _userLockoutStore.SetLockoutEnabledAsync(user, false);
return false;
}
return true;
}
private async Task IncrementAccessFailedCount(TUser user)
{
var accessFailedCount = await _userLockoutStore.IncrementAccessFailedCountAsync(user);
var shouldLockoutUser = accessFailedCount > MaxFailedAccessAttemptsBeforeLockout;
if (shouldLockoutUser)
{
await _userLockoutStore.SetLockoutEnabledAsync(user, true);
var lockoutEndDate = new DateTimeOffset(DateTime.Now + DefaultAccountLockoutTimeSpan);
await _userLockoutStore.SetLockoutEndDateAsync(user, lockoutEndDate);
}
}
}
Example:
[AllowAnonymous]
[HttpPost]
public async Task<ActionResult> Login(string userName, string password)
{
var userManager = new LockingUserManager<MyUser, int>(new MyUserStore())
{
DefaultAccountLockoutTimeSpan = /* get from appSettings */,
MaxFailedAccessAttemptsBeforeLockout = /* get from appSettings */
};
var user = await userManager.FindAsync(userName, password);
if (user == null)
{
// bad username or password; take appropriate action
}
if (await _userManager.GetLockoutEnabledAsync(user.Id))
{
// user is locked out; take appropriate action
}
// username and password are good
// mark user as authenticated and redirect to post-login landing page
}
If you want to manually lock someone out, you can set whatever flag you're checking in MyUserStore.GetLockoutEnabledAsync().
You can have a new class, which should be derived from IdentityUser class. YOu can add a boolean property in the new class and can use this new property of take care per check for login process. I also done it pretty well. I might wanna take a look at : blog
UserManager.RemovePasswordAsync("userId") will effectively disable a user. If the user has no password he will not be able to log in. You will need to set a new password to enable the user again.