Adding ASP.NET Identity to an existing project with already managed users table - asp.net-core

I have an existing web api project with a users table. In general User is involved in some key business queries in the system (as other tables keep its 'UserId' foreign key).
These days I'm interested in adding Asp.net (core) identity. Basically I've already performed the required steps adding a separate Identity table, managing an additional db context (implementing IdentityDbContext), and also added a JWT token service. It looks that everything works fine. However I am now wondering how should I "link" between the authenticated user (which has logged in through the Identity module) and the user which is found on the other original "business related db".
What I was thinking of is that upon login, having the userId retrieved from the original Users table, based on the email which is used as the username and is found on both the original Users table and the new Identity table, and than have it kept as a Claim on the authenticated user. This way, each time the user is calling the API (for an Authorize marked action on the API relevant controller), assuming is authenticated I will have the relevant userId on hand and be able to address and query what ever is needed from the existing business table.
I guess this can work, however I'm not sure regarding this approach and I was wondering if there are any other options?
Regarding the option I've mentioned above, the main drawback I see is that upon the creation of a new user, this should be performed against 2 different tables, on 2 different DBs. In this case, in order to keep this in one unit of work, is it possible to create transaction scope consists of 2 different db contexts?

You're on the right track.
I faced similar problem
Imagine two different microservices.
Identity-Microservice(Stores identity information (Username, Password Etc...))
Employees-Microservice (Stores employee information (Name, Surname Etc...))
So how to establish a relationship between these two services?
Use queues(RabbitMq, Kafka etc...)
An event is created after User Registration(UserCreatedEvent {Id, Name etc..})
The workers microservice listens for this activity and records it in the corresponding table
This is the final state
Identity
Id = 1, UserName = ExampleUserName, Email = Example#Email Etc...
Employee
Id = 1, Name = ExampleName, Surname = ExampleSurname Etc...
Now both services are associated with each other.
Example
If i want to get the information of an employee who is logged in now.
var currentEmployeeId = User.Identity.GetById()
var employee = _db.Employee.GetById(currentEmployeeId)

Related

Associate one column in table with two existing tables

My DB has following tables:
Resource: Some resources can be uploaded on site
Groups: Groups on site
Users: Users on site (not necessarily be part of any group but could be if they like)
Now, when some one uploads a resource then currently, ownership of that resource is given to it's uploader by default. So resource table has column OwnerID with foreign key association to User table.
But now, this has to be changed such that ownership of a resource could be given to either a user or entire group.
I'm trying to decide the migration scheme, to move this owner being user to an entity that could be either user or group. Intuition is that when someone uploads a material, he can choose its owner to be a user or entire group.
Currently my migration plans involves:
Add OwnerType (User, Group, Global) and UserOwner and GroupOwner within the Material table (probably worse normalized table).
OwnerType could be Global if owner is everyone --or-- Group if owner is group entity else user.
Then when I'm querying the Resource table, I can check the OwnerType to condionally select its Owner from either user table or group table.
I do not know if this is good way. I'm using entity framework, and things are already started to look ugly as User and Group hardly have any relationaship that would require me to make generalized entity.
Can some expert guide me on this? What is generally considered good migration plan in this case? Thanks for any help or suggestions.

Multiple Login Feature

I am implementing a multiple login system, using Facebook, Twitter, Email.
If the user login with Facebook, he is able to merge his account with Twitter account or Email account, so next time login, he can press on "Login with Twitter" or key in email+password to login.
Now the problem is the merging.
If user created account A using Facebook login, modify some data, then create account B using Twitter login, and modify some data, this would be hard to merge, because both accounts will have different data.
What do app/site who use multiple login handle this kind of situation? Or is it me who makes it complicated?
I guess the main point is not storing any detailed account information with the login method. This is probably what your user account DB looks like now:
- account_id: …
facebook_auth_info: …
username: …
birth_date: …
- account_id: …
twitter_auth_info: …
username: …
birth_date: …
Now this schema should make it a no-op to “merge accounts”:
- account_id: …
facebook_auth_info: …
twitter_auth_info: …
username: …
birth_date: …
In other words, treat Facebook, Twitter and other as a “identity providers” and allow for multiple identity providers per your own account.
The way I would do this is to keep separated third party login details and use tables like email and third party login details interchangeable to authenticate a user. This way you can have a customer that get authorized either by using email or using a third party login. This does not mean that the same user can login either with email&password or third party provider. This I find it helpful to avoid having all the time fields for third party providers in the User table and if you want to add more login providers you don't have to alter any table, just add another entry in Types table.
For example I would use a Users table where you you keep all details for a customer but login details. No email, password or any other login details. These details are held in separate tables and are linked by the PK from this table. This table will map 1:1 to the Emails table. For example a schema might be:
- Id (PK)
- FirstName
- SecondName
- etc.
Then I'll have an Emails table where I would keep the email and password for a user. You can also have extra details like Id and Verified (to know if email is verified). Please be aware of keeping plain text passwords or keeping pairs email - password in your db. This is an important security concern and I would not discuss it here. I would also use a UserId column to map emails to users. This will map 1:1 to Users table. A schema might be:
- Id (PK)
- Email
- Password
- UserId (FK)
- Verified
To handle the third party login details I'll use a table called ThirdPartyUsers. In this table I will store a UserId to map one record from this table to one record from User tables. Basically this table can replace Email table and you can move away from holding email - password in your db. In this table I would keep a ProviderCode that is a code from types table and a ProviderId that is an Id provided by third party logins. This Ids are unique per third party providers and don't change per user. You can pair a ProviderCode with a ProviderId to make a composite key. This will map 1:1 to Users table. A schema might be:
- Id (PK)
- UserId (FK)
- ProviderCode
- ProviderId
To have a unified User account I would have a MasterUsers table where you define a User as a Master user and you define into a link table its children. Through its children I understand any account that has the same email address. This means a classic account and any third party login providers. Using this you can a unique Master and multiple children. This would map 1:1 to Users table and 1:* to MasterLinkToChildren table. A schema might be :
- Id (PK)
- UserId
To link multiple customers to one MasterUser I would use a link table called MasterLinkToChildren (or any naming you prefer). In this I would have two columns for storing UserIds for childrens and MasterId for their parent. An important thing I would do is to make any MasterUser also be a children of himself in the Link table so when you update the MasterUser you would keep consistency between your records. This will map *:1 to MasterUsers and 1:1 to Users table. A schema might be:
- MasterId (FK)
- UserId (FK)
Finally I would have a Codes table where I would store unique code for each third party login provider. This would map 1:* to ThirdPartyUsers. A schema like:
- Id (PK)
- Code (Unique)
It might look like a lot of code and many tables but in this way you can preserve unique user login or you can unify everything under one Master account. I wouldn't merge them automatically but I will offer the user the option to do that. Another thing you need to consider is not to allow users to login or merge accounts before they verified their account. I didn't use a Verified column on ThirdPartyUsers table as I don't want to verify this type of users but you can do this as well.
By using a Codes table you can extend your third party login providers without altering other tables.

Database design relations in User and Profile

I'm designing a web application for a school. So far, I'm stuck with the database which has these tables:
users
id
username
password
profile
user_id (FK)
name
last_name
sex
group_id (FK)
(other basic information)
... And other tables irrelevant now, like events, comitees, groups and so on.
So, the users table stores basic information about the login, and the profiles table stores all the personal data about the user.
Now, the *group_id* column in the profile table has a foreign key that references the ID column of the group in which the user is currently enrolled, in the groups table. A user can only be enrolled in one group at once, so there's no need for any additional tables.
The thing is that it doesn't make much sense to me declaring a relation like group HAS MANY profiles. Instead, the relation should be group HAS MANY users, but then, I would have to put a *group_id* column on the users table, which doesn't really fit in, since the users table only stores auth information.
On the other side, I would like to list all the users enrolled in a group using an ORM and getting the a users collection and not profiles. The way I see it, is that the users table is like the 'parent' and the profiles table extends the users table.
The same problem would occur when setting attendances for events. Should I reference the profile as a foreign key in the events_attendance table? Or should I reference the user ID?
Of course both solutions could be implemented and work, but which of them is the best choice?
I have dug a little and found that both solutions would comply with 3NF, so in theory, would be correct, but I'm having a hard time designing the right way my database.
This is a question of your own conventions. You need to decide what is the main entity, right after that you can easiy find a proper solution. Both ways are good, but if you think of User as of the main entity while Profile is a property then you should put GroupId into User, otherwise, if you mean User and Profile as a single entity, you can leave GroupId in Profile, and by this you're not saying group HAS MANY profiles but group HAS MANY users.
By setting a proper one-to-one relation (User-Profile) you can force your data integrity good enough.

Associate users and roles added to ASPNET SQL Database tables with existing user information

I have added a series of ASPNET database tables for roles, user and membership management to my existing SQL database using aspnet_regsql.exe.
There is already a user table in the existing database which contains information (ID, Name, Address, Postcode, etc) for a number of users. What I want to achieve to associate the new aspnet_Users table with the existing user table.
Is there any option or options for recommendation please? Thanks
Cheers,
Alex
The UserKey, called UserId in the ASPnet membership tables, is the GUID which identifies a user. You can add a UserKey column to your Users table and then start doing dangerous things like:
select *
from Users as U inner join
aspnet_Users as aU on aU.UserId = U.UserKey inner join
aspnet_Membership as aM on aM.UserId = aU.UserId
where U.UserId = #UserId
No warranty, expressed or implied, is provided by Microsoft (or me) if you want to fiddle about directly in their tables.
We had a similar situation on a project I worked on a couple years ago. What we ended up doing was storing the primary key of the related user record from the external user table as a Profile Property of the ASPNET Membership model.
The benefit was that we didn't have to change anything about the schema of the external database to create the relationship and we could use the built in ASPNET Membership profile objects to easily obtain the related key from within the web code-behinds.
The initial population of this profile property was accomplished via a utility we wrote specifically for the task using ASPNET Membership Profile objects and was made easier by the fact that both our Membership setup and external table stored the email address of the user making it the key for the one time task.
The downside of this approach is that the ASPNET Membership Profile table is very much NOT denormalized (or realy normalized for that matter). It stores the Profile Properties as either xml data or serialized binary. In older versions it was serialized with the property names stored as names and character position of a single value string containing all values. This makes it hard (if not impracticle) to write queries, joins, etc from the aspect of your external table.
For us this wasn't a big deal because we were only working with the external user data on a case by case basis from the website. So, grabbing the key from the ASPNET profile using built objects and then looking it up in the external database was easy.
If your project is going to do a lot of relational queries or batch processes then I would probably recommend instead storing the ASPNET UserId GUID as a foriegn key in your external user table or if emails are going to be unique using those.

use of views for validation of an incorrect login-id or an unidentified user

I read this on msdn:
Views let different users to see data in different ways, even when they are using the same
data at the same time. This is especially useful when users who have many different interests and skill levels share the same database.
For example, a view can be created that retrieves only the data for the customers with whom an account manager deals. The view can determine which data to retrieve based on the login ID of the account manager who uses the view.
My question:
For the above example , i would have to have a column named Userid/LoginId on my table on which the view is created so that i can apply a check option in the view for this column. and then if a user with a name not in that column tries to enter data , then he/she is blocked.
Yes, you are right. You should
add a column with the user's login or database user name (say you call it username),
each row should have username populated with the login or database name of the person who is allowed to see that row
you can then build a view where you use the builtin functions SUSER_SNAME() (for logins) or USER_NAME (for database names) in your WHERE clause to filter only the rows the user is allowed to see
See Granting Row-Level Permissions in SQL Server (ADO.NET).
You don't have to add a column to the table: it could be more appropriate to instead add a new table to model the relationship.
There's a deisgn rule of thumb that states a table should model an entity or a relationship but not both. Let's say the table in question models the companies a customer owns (i.e. an entity table) and the business rule states the the account manager can only see companies relating to customers he looks after.
Is account manager an attribute of a company? No, so account_manager should not be a column (attribute) in the Companies table.
Is there a direct relationship between account_manager and a company? No, so a relationship table between is not due here (because the relationship is indirect).
Rather, the direct relationships are between account manager and customer, and between customer and company respectively. There should be two tables whose sole purpose is to model these relationships.