How add identity and user management into aspnetcore web api? - c#

I'm building asp.net core web api with 3 types of users: Admin, Clients and Programmers. Each of those roles have their own list of tickets. These are entity classes I've already added:
public class User
{
[Key]
public Guid Id { get; set; }
[Required]
[MaxLength(50)]
public string FirstName { get; set; }
[Required]
[MaxLength(50)]
public string LastName { get; set; }
[Required]
public string Address { get; set; }
[Required]
public string Zip { get; set; }
[Required]
[Phone]
public string PhoneNumber { get; set; }
[Required]
[EmailAddress]
public string EmailAddress { get; set; }
[Required]
public Gender Gender { get; set; }
[Required]
[MaxLength(50)]
public string UserName { get; set; }
[Required]
[MaxLength(50)]
public string Password { get; set; }
[Required]
public Role Role { get; set; }
public virtual Programmer Programmer { get; set; }
public virtual Admin Admin { get; set; }
public virtual Client Client { get; set; }
}
public class Client
{
public Guid clientId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public virtual ICollection<Ticket> Tickets { get; set; } = new List<Ticket>();
public Guid Id { get; set; }
public virtual User User { get; set; }
}
public class Admin
{
public Guid adminId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public virtual ICollection<Ticket> Tickets { get; set; } = new List<Ticket>();
public Guid Id { get; set; }
public virtual User User { get; set; }
}
public class Programmer
{
public Guid programmerId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public ProgrammingLanguage ProgrammingLanguage { get; set; }
public Experience Experience { get; set; }
public DetailOriented DetailOriented { get; set; }
public FieldOfInterest FieldOfInterest { get; set; }
public virtual ICollection<Ticket> Tickets { get; set; } = new List<Ticket>();
public Guid Id { get; set; }
public virtual User User { get; set; }
}
I've already created regular DbContext and implemented functionality of my api using that DbContext. Now I want to change users to be IdentityUsers. I'm not sure should I make a new project where UserIdentity will be handled and then pass those users to my api(if so, how can I pass them to api and connect them with their tickets, i.e.do I leave only tickets table in api?) or make users as part of an api as I already did(if so, what would be the best way to change them into identity users so that I can query their tickets later?). Does anyone have any tips/links/similar code samples or something? I would be grateful :)

Out of the box, Identity supports a single set of user profile properties. The easiest solution would be to create an AppUser class that inherits from IdentityUser with ALL of the properties across your user types. Also introduce an interface for each of your user types with the properties they support.
class AppUser: IdentityUser, IAdmin, IProgrammmer, IClient {...}
Based on the IdentityRole associated with the user, you can cast the AppUser instance to the appropriate interface to access the user-specific properties.

Related

NET Core identity grouping of users

I currently have a project that uses identity and individual users have access to their own resources (sub database table linked by application user id). I'd like each user who signs up (admin) to then be able to invite new users to their 'group' and all share the same resource.
I'm looking at implementing a 'Groups' and 'UserGroups' table similar to the current 'Roles' and 'UserRoles' tables. Does the following code look ok to achieve this?
public class ApplicationUser : IdentityUser
{
[MaxLength(30)]
public string FirstName { get; set; }
[MaxLength(30)]
public string LastName { get; set; }
[MaxLength(100)]
public string Company { get; set; }
[MaxLength(30)]
public string Telephone { get; set; }
[MaxLength(15)]
public string Postcode { get; set; }
public DateTime Created { get; set; } = DateTime.UtcNow;
public DateTime PasswordResetTime { get; set; } = DateTime.UtcNow;
public bool PasswordReset { get; set; } = false;
public virtual ICollection<GSMSite> GSMSites { get; set; }
}
public class UserGroups
{
public virtual ApplicationUser ApplicationUser { get; set; }
public virtual Groups Groups { get; set; }
}
public class Groups
{
public Guid Id { get; set; }
[MaxLength(30)]
public string Name { get; set; }
}
You are trying to achieve Many to Many relationship.
Firstly by convention You should name Classes with singular form:
UserGroups -> UserGroup
Groups -> Group
You should also put ICollection<UserGroup> in both AplicationUser and Group:
public virtual ICollection<UserGroup> UserGroups
And change UserGroup to:
public class UserGroup
{
public Guid ApplicationUserId { get; set;}
public virtual ApplicationUser ApplicationUser { get; set; }
public Guid GroupId { get; set; }
public virtual Groups Groups { get; set; }
}
And then the resource You are talking about should be linked to Group not ApplicationUser.

Error: Unable to determine composite primary key ordering for type

I try to scaffold a controller for my ClientModel and it gives me an error called:
There was an error running the selected code generator: 'Unable to retrieve metadata for '/////.ClientModel'. Unable to determine composite primary key for ordering for type '/////.ClientModel'. Use the ColumnAttribute (link) or the HasKey method (link) to specify an order for composite primary keys.
I have three classes with all of them an One-To-One relationship with my Client class.
This is my ClientModel:
[Table("Client")]
public class ClientModel : PersonModel
{
[Key(), DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid ClientId { get; set; }
[Required]
public string FirstName { get; set; }
public string Initials { get; set; }
[Required]
public string LastName { get; set; }
//... snip ...
[Required]
public long ClientIdentificationNumber { get; set; }
public virtual PassportDetailsModel Passport { get; set; }
public virtual MembershipClientValidationModel Membership { get; set; }
public virtual AccountClientModel Account { get; set; }
}
Passport class:
[Table("Passport")]
public class PassportDetailsModel
{
[Key(), DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid PassportDetailsId { get; set; }
[Required]
public string IssuingCountry { get; set; }
[Required]
public DateTime Issued { get; set; }
[Required]
public DateTime ExpirationDate { get; set; }
public virtual ClientModel Client { get; set; }
}
Account class:
[Table("AccountClient")]
public class AccountClientModel
{
[Key(), DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid AccountId { get; set; }
[Required]
public string Username { get; set; }
[Required]
public string Password { get; set; }
public virtual ClientModel Client { get; set; }
}
Membership class:
[Table("MembershipClientValidation")]
public class MembershipClientValidationModel
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid MembershipClientValidationId { get; set; }
public DateTime MembershipStartDate { get; set; }
public DateTime MembershipExpiryDate { get; set; }
public bool IsMembershipValid { get; set; }
[Required]
public virtual ClientModel Client { get; set; }
}
I don't understand how to fix the 'unable to retrieve metadata for <class> error. How do I link classes with composite keys?
21-09-2015
After reading some comments I deleted the
DatabaseGenerated.DatabaseOption.Identity
In my primary key's in the other classes (Passport, Membership and Account). So I added some properties to my ClientModel:
[ForeignKey("Passport")]
public Guid PassportDetailsId { get; set; }
public virtual PassportDetailsModel Passport { get; set; }
[ForeignKey("Membership")]
public Guid MembershipClientValidationId { get; set; }
public virtual MembershipClientValidationModel Membership { get; set; }
[ForeignKey("Account")]
public Guid AccountClientId { get; set; }
public virtual AccountClientModel Account { get; set; }
It still gives me the same error as it gave me above.
I fixed this problem by doing some simple changes.
I removed my three [ForeignKey("//")] in my ClientModel. I added the Foreign keys to my Primary keys in my other 3 models with reference to my ClientModel.
What I did next was the major fix. I added [Required] above the public ClientModel Client { get; set; } in my other three models.
Now it works and scaffolds my ClientController without error(s).
So to show an example of one of the other three models:
public class MembershipClientValidationModel
{
[Key]
[ForeignKey("Client")]
public Guid ClientId { get; set; }
public DateTime MembershipStartDate { get; set; }
public DateTime MembershipExpiryDate { get; set; }
public bool IsMembershipValid { get; set; }
[Required]
public virtual ClientModel Client { get; set; }
}
It just works.

How to Disable SignIn/Missing UserManagement Property in ASP.NET MVC 5 EntityFramework

I'm working on a project using Asp.NET MVC 5, but now I'm having some problems since its last update.
Basically, the application user, which inherits from IdentityUser, had an "Management" property, that through it one could block the user, i.e. disable the signin for that user.
How can I do that with the new Entity Framework definitions?
What is the SecurityStamp property of the User?
(Also, in this ASP.NET Tutorial there is an image that shows the project's database, and we can see a "AspNetUserManagement" table that isn't created, but maybe it's just a mistake)
OLD Microsoft.AspNet.Identity.EntityFramework.User:
//...
public string Id { set; get; }
public virtual System.Collections.Generic.ICollection<UserLogin> Logins { set; get; }
public virtual Microsoft.AspNet.Identity.EntityFramework.UserManagement Management { set; get; }
public virtual System.Collections.Generic.ICollection<UserRole> Roles { set; get; }
public string UserName { set; get; }
OLD Microsoft.AspNet.Identity.EntityFramework.UserManagement:
//...
public bool DisableSignIn { set; get; }
public System.DateTime LastSignInTimeUtc { set; get; }
public virtual Microsoft.AspNet.Identity.EntityFramework.User User { set; get; }
public string UserId { set; get; }
NEW Microsoft.AspNet.Identity.EntityFramework.User:
//...
public virtual System.Collections.Generic.ICollection<IdentityUserClaim> Claims { get; }
public virtual string Id { set; get; }
public virtual System.Collections.Generic.ICollection<IdentityUserLogin> Logins { get; }
public virtual string PasswordHash { set; get; }
public virtual System.Collections.Generic.ICollection<IdentityUserRole> Roles { get; }
public virtual string SecurityStamp { set; get; }
public virtual string UserName { set; get; }

How can i expose dto objects using wcf data service with ef code first?

I am trying to make a wcf data service where i dont want to get acces to the database models but instead i want to use Data transfer objects. I have been reading a lot on the internet about how to accomplish this but i cant get a good answer for my problem. It is the first time for me doing something with wcf data services so i am a little inexperienced.
Oke here are my models that are linked to my database using Entity Framework
public class User
{
[Key]
public int UserId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string UserName { get; set; }
public string Email { get; set; }
public string CountryCode { get; set; }
public string PhoneNumber { get; set; }
public ICollection<User> Contacts { get; set; }
public virtual Language Language { get; set; }
public User()
{
Contacts = new List<User>();
}
}
public class Message
{
[Key]
public int MessageId { get; set; }
public DateTime SentDate { get; set; }
public virtual User Sender { get; set; }
public virtual User Receiver { get; set; }
public string Content { get; set; }
public string OriginalCultureInfoEnglishName { get; set; }
public string ForeignCultureInfoEnglishName { get; set; }
}
public class Language
{
[Key]
public int LanguageId { get; set; }
public string CultureInfoEnglishName { get; set; }
}
Now i made a Service.svc which has my DatabaseContext so it can directly acces my database models. What i want to achieve is that instead of directly getting the database models i would like to get the DTO models when i query against my service.
A Example of how my dto's would look like
public class UserDTO
{
public int UserId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string UserName { get; set; }
public string Email { get; set; }
public string Country { get; set; }
public string PhoneNumber { get; set; }
public ICollection<ContactDTO> Contacts { get; set; }
public virtual LanguageDTO Language { get; set; }
public UserModel()
{
Contacts = new List<ContactDTO>();
}
}
public class ContactDTO
{
public int UserId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string UserName { get; set; }
public string Email { get; set; }
public string Country { get; set; }
public string PhoneNumber { get; set; }
public virtual LanguageDTO Language { get; set; }
}
public class LanguageDTO
{
public int LanguageId { get; set; }
public string CultureInfoEnglishName { get; set; }
}
public class MessageDTO
{
public int MessageId { get; set; }
public DateTime SentDate { get; set; }
public virtual ContactDTO Sender { get; set; }
public virtual ContactDTO Receiver { get; set; }
public string Content { get; set; }
public string OriginalCultureInfoEnglishName { get; set; }
public string ForeignCultureInfoEnglishName { get; set; }
}
Now is it possible to do it like this by making a different context that i can use in my service.svc or is there any other way to achieve the this?
for example i would like to get ContactDto by userid which is a user but with less properties because they are not relevant in the client application. I see this happening by a uri http://localhost:54895/Service.svc/ContactDto(1)
Hopefully anyone can clear this up for me because it is really frustrating :)
I'm not sure that what you're interested in is possible, exactly. You are looking to have multiple entity sets per type (aka MEST), and I don't know how well that's supported.
Beyond that point, and into a discussion around DTOs in general...
If you use custom providers, you can implement your own IDataServiceMetadataProvider and IDataServiceQueryProvider. When your service starts, you can make calls into the IDataServiceMetadataProvider to control what entities and properties are exposed or hidden -- including exposing properties that do not actually exist on your entity. The upshot is that you end up with a DTO without coding a DTO class. The exposed metadata is the DTO. This is a good resource for creating your own providers.
In your case, this isn't a 100% solution, because you can't selectively choose when a property is exposed and when it's not.
Hope this helps...

Create the relationship table between 2 tables in asp.net mvc EF

I created:
custom custom membership provider
custom role provider
an user model
an role model
It create me the 2 custom tables correctly.
Now I want to create the table between Users and Roles with 2 columns: RoleId, UserId
I should I tweak my models to teach to EF to create this relationship table (UsersInRole)?
User model:
public class User
{
[Key]
public int UserId { get; set; }
[Required]
public Int32 CompanyId { get; set; }
[Required]
public String UserName { get; set; }
public String Password { get; set; }
public String PasswordSalt { get; set; }
public String Email { get; set; }
public Boolean IsApproved { get; set; }
public Boolean IsLockedOut { get; set; }
public DateTime CreateDate { get; set; }
public DateTime LastLoginDate { get; set; }
public DateTime LastPasswordChangedDate { get; set; }
public DateTime LastLockoutDate { get; set; }
}
Role model:
public class Role
{
[Key]
public int RoleId { get; set; }
[Required]
[MaxLength(20)]
public string Name { get; set; }
public ICollection<string> AssignedUsers { get; set; }
}
If you are using code-first EF, then all you should need to do is add a collection of the Users to the Role class and vice-versa. EF takes this two-way link as a signal to create a many-to-many relationship in the underlying data store. To summarize, your classes would be augmented something like this...
public class User
{
...
List<Role> Roles {get; set;}
}
public class Role
{
...
List<User> Users {get; set;}
}
public class Role
{
[Key]
public int RoleId { get; set; }
[Required]
[MaxLength(20)]
public string Name { get; set; }
public ICollection<User> AssignedUsers { get; set; }
}
public class User
{
[Key]
public int UserId { get; set; }
[Required]
public Int32 CompanyId { get; set; }
[Required]
public String UserName { get; set; }
public String Password { get; set; }
public String PasswordSalt { get; set; }
public String Email { get; set; }
public Boolean IsApproved { get; set; }
public Boolean IsLockedOut { get; set; }
public DateTime CreateDate { get; set; }
public DateTime LastLoginDate { get; set; }
public DateTime LastPasswordChangedDate { get; set; }
public DateTime LastLockoutDate { get; set; }
public ICollection<Role> Roles{ get; set; }
}

Categories