How to log inserts, updates in SQL Server? - asp.net

I am wondering what would be the best practice to logging when a user inserts or updates some data from my ASP.NET application.
In my application I need to know which user made the change, I think I have to options:
Register my ASP.NET users into the SQL Server adding them the rights for the tables needed, and store for each of my users
individual connectionstring. Thus I could use the currently logged in
user's connectionstring when connecting to the database, so that I
could write T-SQL triggers for SELECT and UPDATE.
The other option I thought of is that I can write stored procedures that get the ASP.NET user name as input parameter and makes
the log for me, (I use only one connectionstring in the application).
After modifying the database from the application I would call this
procedure giving the currently logged in user's username.
The second option seems simpler to me, but I think that for that purpose I should choose the first option.

Go for the second option. Managing users in a database creates more of a headache for you and what happens if you have to move the database server? You would need to update all of the connection strings for all the users. It just creates an extra admin overhead.
Furthermore, if you need to log all the changes in the database then I have come up with something that I have used in the past to store all changes made to a database over time. Have a look, it might be useful.
http://richhooper.wordpress.com/2012/06/11/sql-server-row-level-versioning/

Related

User profile in Session variable

I've a pretty basic question related to user profile storage along a session.
Let's say that I've an Account table that stores user profiles and that I've linked this table to ASP.NET SimpleMembership. Once a user is logged in, controllers may need to retrieve information in or based from her Account. What I'm doing right now is querying the database each time I need data, with something similar to this: _dbContext.Accounts.Where(a => a.EmailAddress == User.Identity.Name).Single().
But I'm afraid that this may cause unnecessary load on the DB and think that a better idea (perhaps it's what everybody does!) is to store the Account object in a Session variable once a user logs in, enabling direct access without re-querying the DB.
Is this the usual way to do it? Isn't there a risk of "de-sync" between the Session variable and the authentication?
Thanks
Our website uses this same type of method for a user-type object at login. Upon confirmed login we store the user object in a session variable. If something is changed or updated the object is updated and depending on the circumstance the change is updated in the database as well (timing meaning update immediately following the change or, after gathering a group of changes).
It just depends on how complex your system is. Ours is fairly complex, and this has proved to be a pretty solid way - without requiring constant maintenence and updates.

Passing asp.net login name to the database

I'm wondering how to solve the following issue:
I have a web asp.net app where Forms Authentification is used, connected to the Active Directory. Also, I have a connection string to MS SQL db in the web app, where one global user (with given privileges) is used. The problem is that when I want to store information about the user (e.g. data modification log) in database, I can only get the global user info provided in the connection string, not the real user who is logged in.
Is there any possiblity to log onto a web app with my personal credentials, after, use a global user credentials to connect into the database and pass my personal user credentials (but not as parameters in store procedure) that database will think that the user who is logged in is not the global user?
I assume, it might be only possible if I also create same users in the database and use Impersonalization?
Or any other possibillities?
Thanks in advance.
What are you doing to get the current user? Are you doing something like SELECT #user = SYSTEM_USER? This will obviously only return the user that you connect to SQL Server with.
I would rather keep to using a single SQL login that the application uses, but pass in the username when you are making changes, e.g. through a sproc or a table update:
CREATE PROCEDURE dbo.DoSomething
#id INT,
#username VARCHAR(50)
AS
-- Make your changes.
INSERT INTO dbo.[Audit] SELECT 'update', #id, #username
GO
In ASP.NET you can grab the currently logged in user through User.Identity.Name property of the page.
You could use a role within your database to handle permissions, and then get the users you need in a group in AD, and assign permissions to that AD group to access your database under the role you define. (This way you don't need to assign each user to your database as you create them).
You would then use windows authentication right the way through from your web site to the database, and have the user identity that you need for logging. (You'll need to set identity impersonate="true" in your configuration).
I would note that this is only going to work (easily) if your servers and your users are all on the same network.

Dynamically connect to different databases in a hybrid multitenant solution

I was researching about multi-tenancy and multi-instance approaches and chose a hybrid.
I keep a single instance of my ASP.Net MVC 2 application but clone the database structure for each client. I am using LINQ to SQL.
Right now, I have one instance of both so just a single connection string is working.
I am planning to expand it for many clients.
I can write code to create a clone of the database structure, create a db user and give permissions whenever a new client signs up. I also will save all these details (db name, db user, allowed app users) in a table.
But how can I make the app use a different database based on who is logged in?
I can't even figure out the approach I should take to do this. Should I programmatically add connection string to web.config? Is there another way to do this?
One of the constructors for DataContext accepts the connection string. You can assemble this string based on the user for the specific request.
This will override the default connection.
Check the constructor overloads for the DataContext, there is one that takes connection string. You just need to map a string property against the logged in user.
Please don't programmatically add EVERY user's connection string to web.config, think scalability!!!

more persistent than session?

we have a asp.net application which use session (in-proc) for single user across pages, now they want to keep the data (eg. a shopping cart) more persistent, even they leave the web app, means close the browser, next time they login use same id, they want the data back, any solution in ASP.NET?
If we save session in sql-server which I think is an option by microsoft, but I am not sure if it works even after user leave the app, or close the browser
Session data is meant to only persist for the lifetime of that browser session.
The answer is to not save the data in session, save it in the database in ShoppingCart and ShoppingCartItem tables instead. These will persist as long as you want them to.
The ShoppingCart table would have a UserID column that is FK to your User table.
You'll need to construct a relational database and store the entries in there.
Granted, the Application scope is higher than Session, but it will only exist for the life of the application pool. It sounds like you're looking for permanent storage.
I've seen shopping cart system using cookies instead and some using both cookies and database.
Cookie only: The "official" size of a cookie is 4K
Cookie + database: Store a GUID in the cookie and use it as a reference in the database
But... I think that storing shopping cart in a cookie or a cookie/database is not very user friendly. I do prefer that the website forget my shopping cart if I leave. I'm annoyed when website store such information with my approval.
You will need to use a database to mirror the data contained in the session, that way the data will persist long after the user logs off, if the application is restarted, or if the server is restarted. You could save the session object into sql-server as a binary object and serialize/deserialize when needed, but how do you know when to do the initial serialization? It's hard to tell when a user has logged off if they close the browser window.
Storing the session object as a single column might work in the interim, but in the long run you will probably want to come up with a proper relational design and store data in columns in tables, that way you can run queries and reports against the "work-in-progress" shopping carts (such as: how long do people let a shopping cart sit before finally checking out?).
As others have mentioned, cookies are another option but those exist on the client side, and if they decide to clear cookies (a lot of tech support people seem to give this advice as the first response when users complain about slow browsers), the shopping cart is lost.

secure way to authenticate administrator in ASP.NET site using OpenID with DotNetOpenID

Encouraged by SO, I'm trying to write an ASP.NET site that uses OpenID for user authentication. It's a regular WinForms site (not MVC.NET), using the DotNetOpenId library for authentication.
Is it safe for me to permit/deny administrative functions on the site by simply comparing the current session's "ClaimedID" (as returned in the OpenIdLogin_LoggedIn event, as member DotNetOpenId.RelyingParty,OpenIdEventArgs.Response.ClaimedIdentifier) to a known administrator's OpenID (i.e. mine)?
If so, is it safe for this ID to be visible (e.g. in open source code), or should it be "hidden" in a configuration file or a database row? (I know it's better design to make it configurable, my question is just about safety.)
My solution is to follow the same idea of the Roles table. After you've authenticated the user, look up that user's roles. If the user has role "Administrator" in the UserRoles table, then they can do whatever the Administrator can do.
I don't broadcast open ID's in my app. They're stored in the table. On every action result, I'm hitting the Users table, since I have also modified mine to store various user state information. With the exception of the home page, there is going to be some user information that I need from that table. I'm using LINQ, so I include the .LoadWith() to load the User with his list of roles when it serializes.
Jarrett makes some good comments about using database tables.
Just to answer another one of your questions, no, it's not a confidentiality thing to put your OpenID in your code generally. If setting up roles seems overkill for your site, a simple equality check against your ClaimedIdentifier is just perfect.

Resources