Login authentication to asp.net and postgresql - asp.net

I have tried to implement login page in ASP.NET Core MVC and using postgresql as database.
It should check whether user exits in the database table of postgresql and verify, so what is the query to search for user in database and made them sign in?
I have written my code like this:
public IActionResult Login(string seller_email, string seller_password)
{
using var connection = new NpgsqlConnection(connString);
connection.Open();
string main_query = String.Format(#"select exists(select 1 from public.""sellers"" where ""seller_email""='{0}')", seller_email);
using var command_main = new NpgsqlCommand(main_query, connection);
int result_main = command_main.ExecuteNonQuery();
if (result_main < 0)
{
return View(nameof(Create));
}
else
{
return View(nameof(Sign));
}
}
There is a seller table in the database, so just have to check seller exists or not - if exists the have to create a view for it

You are doing a select query, so you must use a command.ExecuteReader.
The ExecuteNonQuery is to be used with statements that update/insert/delete records.
BUT, most importantly, don't concatenate user submitted values into the query string, as it opens the door to SQL injections. Instead, used a parameter.
See the getting started doc for a simple example.

Related

Exchange Web Services find item by unique id

I just started using Microsoft Exchange Web Services for the first time. Want I want to be able to do is the following:
Create Meeting
Update Meeting
Cancel/Delete Meeting
These meetings are created in an ASP.NET MVC application and saved into a SQL Server database. I simply wish to integrate this with the on site Exchange Server. So far, I'm able to created my meeting with the following code:
public static Task<string> CreateMeetingAsync(string from, List<string> to, string subject, string body, string location, DateTime begin, DateTime end)
{
var tcs = new TaskCompletionSource<string>();
try
{
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2013);
service.Credentials = CredentialCache.DefaultNetworkCredentials;
//service.UseDefaultCredentials = true;
// I suspect the Service URL needs to be set from the user email address because this is then used to set the organiser
// of the appointment constructed below. The Organizer is a read-only field that cannot be manually set. (security measure)
service.AutodiscoverUrl(from);
//service.Url = new Uri(WebConfigurationManager.AppSettings["ExchangeServer"]);
Appointment meeting = new Appointment(service);
meeting.Subject = subject;
meeting.Body = "<span style=\"font-family:'Century Gothic'\" >" + body + "</span><br/><br/><br/>";
meeting.Body.BodyType = BodyType.HTML;
meeting.Start = begin;
meeting.End = end;
meeting.Location = location;
meeting.ReminderMinutesBeforeStart = 60;
foreach (string attendee in to)
{
meeting.RequiredAttendees.Add(attendee);
}
meeting.Save(SendInvitationsMode.SendToAllAndSaveCopy);
tcs.TrySetResult(meeting.Id.UniqueId);
}
catch (Exception ex)
{
tcs.TrySetException(ex);
}
return tcs.Task;
}
This successfully creates my meeting, places it into the user's calendar in outlook and sends a meeting request to all attendees. I noticed the following exception when attempting to call meeting.Save(SendInvitationsMode.SendToAllAndSaveCopy); twice:
This operation can't be performed because this service object already has an ID. To update this service object, use the Update() method instead.
I thought: Great, it saves the item in exchange with a unique id. I'll save this ID in my application's database and use it later to edit/cancel the meeting. That is why I return the id: tcs.TrySetResult(meeting.Id.UniqueId);
This is saved nicely into my application's database:
Now, I am attempting to do the next part where I update the meeting, but I cannot find a way to search for the item based on the unique identifier that I'm saving. An example I found on code.msdn uses the service.FindItems() method with a query that searches the subject:
string querystring = "Subject:Lunch";
FindItemsResults<Item> results = service.FindItems(WellKnownFolderName.Calendar, querystring, view);
I don't like this. There could be a chance that the user created a meeting outside of my application that coincidentally has the same subject, and here come's my application and cancel's it. I tried to determine wether it's possible to use the unique id in the query string, but this does not seem possible.
I did notice on the above query string page that the last property you can search on is (property is not specified) that searches in "all word phase properties.". I tried thus simply putting the id into the query, but this returns no results:
FindItemsResults<Item> results = service.FindItems(WellKnownFolderName.Calendar, "AAMkADJhZDQzZWFmLWYxYTktNGI1Yi1iZTA5LWVmOTE3MmJiMGIxZgBGAAAAAAAqhOzrXRdvRoA6yPu9S/XnBwDXvBDBMebkTqUWix3HxZrnAAAA2LKLAAB5iS34oLxkSJIUht/+h9J1AAFlEVLAAAA=", view);
Use the Appointment.Bind static function, providing a service object and the ItemId saved in your database. Be aware with meeting workflow (invite, accept, reject) can re-create a meeting on the same calendar with a new ItemId. But if you are just looking at the meeting you make on your own calendar, you should be OK.

ASP Membership / Role Provider -> how to report the number of users currently logged in?

I'm using the ASP.NET Membership and Role provider. My question is about if there is a built in way to report the number of users who are currently logged in. The question is not get the information about the user who is logged in but from a high level view of everyone who is logged in.
I would like to create a user management dashboard and this metric would be great. also showing the usernames of users who are currently logged in would be useful.
thank you for any help you can provide.
Yes there's a built-in way, see Membership.GetNumberOfUsersOnline(). You can change the "window" for what's considered online, see Membership.UserIsOnlineTimeWindow. (you set the threshold in web.config)
UPDATE:
In response to your comment about getting a list of online usernames...
The Membership API is lacking what you want, so you have to roll your own. You can use the following as starter code, it's similar to what I've done in the past:
public static List<string> GetUsersOnline() {
List<string> l = new List<string>();
string CS = WebConfigurationManager
.ConnectionStrings[YOUR_WEB_CONFIG_KEY]
.ConnectionString
;
string sql = #"
SELECT UserName,LastActivityDate
FROM aspnet_Users
WHERE LastActivityDate > #window
ORDER BY LastActivityDate DESC"
;
using (SqlConnection c = new SqlConnection(CS) ) {
using (SqlCommand cmd = new SqlCommand(sql, c) ) {
DateTime window = DateTime.UtcNow.AddMinutes(
-Membership.UserIsOnlineTimeWindow
);
cmd.Parameters.AddWithValue("#window", window);
c.Open();
using (SqlDataReader r = cmd.ExecuteReader() ) {
while ( r.Read() ) {
l.Add(r.GetString(0));
}
}
}
}
return l;
}
A couple of notes:
Replace YOUR_WEB_CONFIG_KEY above with the key in your web.config <connectionStrings> section.
The LastActivityDate field in the aspnet_Users table (aspnetdb database) is stored as a GMT/UTC Datetime value, so that's why DateTime.UtcNow is used to calculate the window.
Not sure how your Membership database permissions are setup, but you may need to make permission changes, since above code is directly querying the database.

ASP.NET Membership: Where is Current User ID Stored?

Using ASP.NET membership, if I want to get information for the current user, I can call MembershipUser.GetUser()
So, somehow the system must know the ID of the current user.
If this is correct, and all I want is the ID of the current user, is there a way to get it without returning all the user information from the database?
I know I can get the username of the current user using User.Identity.Name, but I need the ID.
The short answer is no you can't get only userID without retrieve whole user info when you use built-in membership provider, only by this
MembershipUser user = Membership.GetUser();
string UserID = user.ProviderUserKey.ToString();
But if you want to have method or property which retrieve only userID, you must re-implement your own membership provider or(it's simply) to implement IPrincipal interface
To return the UserId, use the command bellow in your controller:
User.Identity.GetUserId();
To return the UserName, use:
User.Identity.Name;
To return the user:
var user = db.Users.Find(User.Identity.GetUserId());
Please refer to the post: How to get current user, and how to use User class in MVC5?
As you've guessed, the Membership API doesn't support what you want out of the box. In the past, I've used a helper class instead of creating my own provider. In this case it's pretty simple, maybe something like this:
public static object GetUserId() {
return GetUserId(HttpContext.Current.User.Identity.Name, true);
}
public static object GetUserId(string userName) {
return GetUserId(userName, true);
}
public static object GetUserId(string userName, bool UpdateLastActivity) {
using (SqlConnection c = new SqlConnection(CONNECTION_STRING)) {
string sql = #"
DECLARE #UserId uniqueidentifier
SELECT #UserId=u.UserId
FROM dbo.aspnet_Applications AS a
,dbo.aspnet_Users AS u
,dbo.aspnet_Membership AS m
WHERE
a.LoweredApplicationName=LOWER(#ApplicationName)
AND u.ApplicationId=a.ApplicationId
AND u.LoweredUserName=LOWER(#UserName)
AND u.UserId=m.UserId;
IF #UserId IS NOT NULL AND #UpdateLastActivity=1
UPDATE dbo.aspnet_Users
SET LastActivityDate=#CurrentTimeUtc
WHERE UserId=#UserId;
SELECT #UserId
";
using (SqlCommand cmd = new SqlCommand(sql, c)) {
cmd.Parameters.AddWithValue("#ApplicationName", Roles.ApplicationName);
cmd.Parameters.AddWithValue("#UserName", userName);
cmd.Parameters.AddWithValue("#UpdateLastActivity", UpdateLastActivity);
cmd.Parameters.AddWithValue("#CurrentTimeUtc", DateTime.UtcNow);
object id = null;
c.Open();
id = cmd.ExecuteScalar();
return id != DBNull.Value ? id : null;
}
}
}
Above is pretty similar to what's done in the Membership API when calling GetUser()
You can use MembershipUser.UserName to get the user id or try calling Membership.GetUser(User.Identity.Name) and see if that works for you.
After looking into this further, it seems that the ASP.NET Membership API does not track the user ID after all. It must track just the user name (User.Identity.Name). The ID is not required because Membership.GetUser() can find a user from an ID or user name.
In fact, Membership.GetUser() must simply translate to Membership.GetUser(User.Identity.Name). Since it can obtain the current user from the user name, there is no longer any reason to assume that the current user ID is cached anywhere.
So it appears the ID is not loaded into memory, and the only way to obtain the ID is to load the data from the database (which means loading the entire user record when using the ASP.NET Membership API).
Consider
int userId = WebSecurity.CurrentUserId;
Credit: https://stackoverflow.com/a/15382691/1268910

Passing databasename to SQL query in webmatrix/razor

I have a form built in webmatrix that will be updating data within a user specified database.
I would like the user to insert their DB name into the form, and have the Database.Open("SQLServerConnectionString"); open based on the users submission.
if not possible, is there a way to simply include the user specified DB name within the SQL query below within webmatrix? Sample of what I have below:
var db = Database.Open("SQLServerConnectionString");
var selectQueryString = "SELECT donor_id,first_name,last_name FROM SUPPORT.dpo.dp WHERE donor_id=#0";
I would like the static "SUPPORT" database in the FROM clause to be updated dynamically based on user input. Any help would be great.
Are you using .mdf files or actual database connection strings? If connection strings you can use the OpenConnectionString method and pass a custom connection string instead of using whats in the web.config.
http://msdn.microsoft.com/en-us/library/gg569301(v=VS.99).aspx
Something like this would probably work:
#{
var databaseName = Request["databaseName"]; //load from request
var connectionString = string.Format("Data Source=.\\SQLExpress;Initial Catalog={0};Integrated Security=True", databaseName);
var providerName = "System.Data.SqlClient";
var db = Database.OpenConnectionString(connectionString, providerName);
var selectQueryString = "SELECT * FROM Product ORDER BY Name";
}
You can just drop the SUPPORT. prefix as its not necessary for the select statement.

ASP.NET username change

I have an asp.net site which uses the ASP.net Membership provider. Each comment, entry etc in the DB is tracked by the userID.
Since MS doesn't provide a way to change the username, I've found the userNAME in the "users" table in the DB and there is only 1 place where the username appears.
My question is,
Is it safe to provide an "edit profile" page where the user is allowed to edit their own username. Of course i would handle this change in the background by directly changing the "username" value in the DB.
Are there any downsides to this ? I've created and modified some test accounts and it seems to be fine, i am just wondering if there is any known negatives to this before putting it into production.
cptScarlet's link was good, however I despise using stored procedures if I don't have to and I favor Entity Framework whenever possible. Here's what I did to change the user name, using EF 4.0 and .NET 4.0:
Right click project -> Add New Item -> ADO.NET Entity Data Model
Give it a proper name, I chose "MembershipModel.edmx" and click Add
Select Generate from database and click Next
Add the connection to your 'aspnetdb' database (the ASP.NET membership database)
Give it a proper name, I chose "MembershipEntities"
Click Next
Drill into Tables and select aspnet_Users
Change the Model Namespace to MembershipModel
Click Finish
Now you can add code to create the EF object context and modify the database:
public void ChangeUserName(string currentUserName, string newUserName)
{
using (var context = new MembershipEntities())
{
// Get the membership record from the database
var currentUserNameLowered = currentUserName.ToLower();
var membershipUser = context.aspnet_Users
.Where(u => u.LoweredUserName == currentUserNameLowered)
.FirstOrDefault();
if (membershipUser != null)
{
// Ensure that the new user name is not already being used
string newUserNameLowered = newUserName.ToLower();
if (!context.aspnet_Users.Any(u => u.LoweredUserName == newUserNameLowered))
{
membershipUser.UserName = newUserName;
membershipUser.LoweredUserName = newUserNameLowered;
context.SaveChanges();
}
}
}
}
Note: I did not account for application ID's in my code. I typically only ever have one application using the ASP.NET membership database, so if you have multiple apps, you'll need to account for that.

Resources