membership & profile help needed using createuserwizard and login control in asp.net - asp.net

I am working on a project where I got a task to create a user (using the CreateUserWizard control). I have to save the user in a specific table in the SQL Server database.
Also create a login (using the Login control) and after the login is authenticated it should hold the profile information.
So far, I have created CustomProfile that inherites the ProfileBase. Also have created 3 aspx pages.
Login.aspx
CreateUser.aspx
Default.aspx
My CustomProfile looks like the following:
public class UserProfile : ProfileBase
{
static public UserProfile CurrentUser
{
get
{
return (UserProfile)(ProfileBase.Create(Membership.GetUser().UserName));
}
}
public string FirstName
{
get { return (string)base["FirstName"]; }
set { base["FirstName"] = value; Save(); }
}
public string LastName
{
get { return (string)base["LastName"]; }
set { base["LastName"] = value; Save(); }
}
public DateTime DateOfBirth
{
get { return (DateTime)base["DateOfBirth"]; }
set { base["DateOfBirth"] = value; Save(); }
}
public ContactInfo Contact
{
get { return (ContactInfo)base["Contact"]; }
set { base["Contact"] = value; Save(); }
}
}
I have used aspnet_regsql.exe and it created multiple tables in the sql server and storing the data in those tables and is working fine. I would like to save the information into my table eg. tblUserInfo. How should I proceed? I checked multiple forums but no luck.
Any help is much appreciated.

First of all aspnet_regsql.exe is outdated. You might want to consider using ASP.Net Universal Providers.
I assume your question is save the information into my table eg. tblUserInfo
Instead of using CreateUserWizard, you can collect the user information and save it by yourself.
1. Creating a tblUserInfo table (alternative solution to ASP.Net Profile)
2. Inserting UserInfo into tblUserInfo after creating a user
<asp:TextBox ID="UsernameTextBox" runat="Server" />
<asp:TextBox ID="EmailTextBox" runat="Server" />
<asp:TextBox ID="PasswordTextBox" runat="Server" />
<asp:TextBox ID="PasswordQuestionTextBox" runat="Server" />
<asp:TextBox ID="PasswordAnswerTextBox" runat="Server" />
<asp:TextBox ID="FirstNameTextBox" runat="Server" />
<asp:TextBox ID="LastNameTextBox" runat="Server" />
string username = UsernameTextBox;
string password = PasswordTextBox.text;
string email = EmailTextBox.text;
string passwordQuestion = PasswordQuestionTextBox.text;
string passwordAnswer = PasswordAnswerTextBox.text;
bool isApproved = true;
MembershipCreateStatus status;
MembershipUser membershipUser = System.Web.Security.Membership.CreateUser(
username, password, email, passwordQuestion, passwordAnswer, isApproved, out status);
if (status != MembershipCreateStatus.Success)
throw new Exception(status.ToString());
// Save the rest of the user info to tblUserInfo with userId
Guid userId = (Guid)membershipUser.ProviderUserKey;
3. How to make UserInfo available for login user?

Related

ASP.NET Core : How to login with “UserName” instead of “Email”?

With asp.net core, all the login pages and viewmodels etc are hidden in referenced packages, so can't be directly changed. How do I allow login to still make use of usernames and not force the use of emails?
The first step is to scaffold identity to your application :
Scaffold Identity in ASP.NET Core projects
Then you could customize the Register.cshtml/Register.cshtml.cs and Login.cshtml/Login.cshtml.cs , update model and view , and change the logic in OnPostAsync function to fit your requirement .
To your requirement , you can follow the steps :
Scaffold identity into your project .
Modify the Register.cshtml.cs , add Username to InputModel :
[Required]
[DataType(DataType.Text)]
[Display(Name = "User Name")]
public string UserName { get; set; }
Modify the OnPostAsync method :
var user = new IdentityUser { UserName = Input.UserName, Email = Input.Email };
Update the Register.cshtml to include the UserName :
<div class="form-group">
<label asp-for="Input.UserName"></label>
<input asp-for="Input.UserName" class="form-control"/>
<span asp-validation-for="Input.UserName" class="text-danger"></span>
</div>
Modify the Login.cshtml.cs , modify InputModel to replace Email with UserName :
[Required]
[DataType(DataType.Text)]
[Display(Name = "User Name")]
public string UserName { get; set; }
Modify the Login.cshtml :
<div class="form-group">
<label asp-for="Input.UserName"></label>
<input asp-for="Input.UserName" class="form-control" />
<span asp-validation-for="Input.UserName" class="text-danger"></span>
</div>
Modify the Login.cshtml.cs OnPostAsync method to use Username instead of email :
var result = await _signInManager.PasswordSignInAsync(Input.UserName, Input.Password, Input.RememberMe, lockoutOnFailure: true);
By default ASP.NET Identity uses FindByNameAsync to check if user with given name exists , so that you don't need to override PasswordSignInAsync function in SignInManager . If you want to login with email , your could click here to update that .
When using the excepted answer I also had to modify the following line in step three from Input.Email to Input.UserName on the latest ASP.NET Core template.
await _userStore.SetUserNameAsync(user, Input.UserName, CancellationToken.None);
Look inside Pages -> Login.cshtml page (Here, you will get a class named Login.cshtml.cs). Inside that class, you will get a method named 'OnPostAsync'
Change frontend as likes
And inside your 'Login.cshtml.cs' class change this method with your target Dashboard/Index url..
public async Task<IActionResult> OnPostAsync()
{
if (ModelState.IsValid)
{
var validated = _ADService.Validate(new NetworkCredential(LoginData.UserId, LoginData.Password));
if (validated)
{
if (await _identityService.SignInAsync(HttpContext, LoginData.UserId))
{
// return Redirect("Index");
return Redirect("../app/bootstrap.html");
}
ModelState.AddModelError("", "account does not exist in system!");
return Page();
}
ModelState.AddModelError("", "userid or password is invalid!");
return Page();
}
else
{
ModelState.AddModelError("", "userid or password is blank!");
return Page();
}
}

The attempt to connect to the report server failed - Setting URL and Path in ASP.NET?

I'm trying to connect to a Report (rdlc file) using ASP.NET Web Applications. I'm working with VS2010 and the Report Server is version 2008.
I have the following URL to the report which works fine:
http://server url/Products/_layouts/ReportServer/RSViewerPage.aspx?rv:RelativeReportUrl=/Products/Dashboards/Product_tool.rdl&Source=Server Url/Products/Dashboards/Forms/AllItems.aspx&DefaultItemOpen=1
When i enter that URL in my browser it first asks for a username password. When i log in then the Report shows up just fine.
Now i need to display this report in a Report Viewer. So i added a Report Viewer control to my aspx page. I configured the URls for it like so:
Report Server:** http://server url/Products/_layouts/ReportServer
Report Path:** /Products/Dashboards/Product_tool.rdl
I'm not really sure if that is even correct..?
In any case, in my PageLoad i have the following line of code:
eportViewer1.ServerReport.ReportServerCredentials = new ReportCredentials("myuser", "mypass");
The ReposrtCredentials class is taken from: http://social.msdn.microsoft.com/Forums/en-US/vsreportcontrols/thread/c65abca7-0fdb-40fb-aabe-718f63377a55/ (from Phil)
Now when i run my Web Application i get the following error:
The attempt to connect to the report server failed. Check your
connection information and that the report server is a compatible
version.
Now i'm not sure if the URL i supplied to the Report Viewer is right? Or what the problem else could be.
Anyone any idea..?
In order to Integrate SSRS Reports into an ASP.NET application, follow these steps.
Firstly, Implement IReportServerConnection2 interface. I did something like this:
public sealed class CustomReportServerConnection : IReportServerConnection2
{
public WindowsIdentity ImpersonationUser
{
get
{
// Use the default Windows user. Credentials will be
// provided by the NetworkCredentials property.
return null;
}
}
public ICredentials NetworkCredentials
{
get
{
// Read the user information from the web.config file.
// By reading the information on demand instead of
// storing it, the credentials will not be stored in
// session, reducing the vulnerable surface area to the
// web.config file, which can be secured with an ACL.
// User name
string userName = ConfigurationManager.AppSettings[Utility.Constants.AppConst.REPORT_USER].ToString();
if (string.IsNullOrEmpty(userName))
throw new Exception(Utility.Constants.AppConst.MESSAGE_MISSING_USER_NAME);
// Password
string password = ConfigurationManager.AppSettings[Utility.Constants.AppConst.REPORT_PASSWORD].ToString();
if (string.IsNullOrEmpty(password))
throw new Exception(Utility.Constants.AppConst.MESSAGE_MISSING_PWD);
// Domain
string domain = ConfigurationManager.AppSettings[Utility.Constants.AppConst.REPORTS_DOMAIN].ToString();
if (string.IsNullOrEmpty(domain))
throw new Exception(Utility.Constants.AppConst.MESSAGE_MISSING_DOMAIN);
return new NetworkCredential(userName, password, domain);
}
}
public bool GetFormsCredentials(out Cookie authCookie, out string userName, out string password, out string authority)
{
authCookie = null;
userName = null;
password = null;
authority = null;
// Not using form credentials
return false;
}
public Uri ReportServerUrl
{
get
{
string url = ConfigurationManager.AppSettings[Utility.Constants.AppConst.REPORT_SERVER_URL].ToString();
if (string.IsNullOrEmpty(url))
throw new Exception(Utility.Constants.AppConst.MESSAGE_MISSING_URL);
return new Uri(url);
}
}
public int Timeout
{
get
{
return int.Parse(ConfigurationManager.AppSettings[Utility.Constants.AppConst.REPORT_SERVER_TIME_OUT].ToString());
// return 60000; // 60 seconds
}
}
public IEnumerable<Cookie> Cookies
{
get
{
// No custom cookies
return null;
}
}
public IEnumerable<string> Headers
{
get
{
// No custom headers
return null;
}
}
}
Now in your Configuration AppSettings place following keys ( or provide these values from wherever you want):
<add key="ReportServerUrl" value="http://sqlServerURL/ReportServer_SQL2008R2"/>
<!--Development TargetReportFolder-->
<add key="TargetReportFolder" value="/AppReporting/"/>
<add key="ReportServerTimeOut" value="600000"/>
<add key="ReportViewerServerConnection" value="FullyQualified Name of ur CustomReportServerConnection,ProjectName"/>
<add key="ReportsUser" value="ReportUser"/>
<add key="ReportsPassword" value="reportPassword"/>
<add key="ReportsDomain" value="myDomain"/>
Now , in your .aspx page, drag a reportViewer something like this:
<rsweb:ReportViewer ID="RptViewer" runat="server" AsyncRendering="False" SizeToReportContent="true"
ProcessingMode="Remote" Width="100%" BackColor="#F7F8F9" OnReportError="RptViewer_ReportError"
OnReportRefresh="RptViewer_ReportRefresh1" Height="">
</rsweb:ReportViewer>
and configure your ReportViewer in the codeBehind..
place your ReportParameter properly.
it shud give you an idea...
point is, you need to authenticate properly, hence writing your custom ReportServerConnection
When you configure your report viewer,check whether the account you use has permission to view the report because it is necessary that you have access when using server report.
Check out this link too. They will be of help : http://forums.asp.net/t/1562624.aspx/1

SSRS & ASP.net ReportViewer rsAccessDenied

I have a SSRS 2008 R2 report running on the reporting server. When I access the report using the Report Manager or Web Service URL it works ok.
http://mycomputer/ReportServer
and
http://mycomputer/Reports
When I add a ReportViewer to a WebForms web site and point it to
http://mycomputer/reportserver
with a report path to my report it gives me an access denied error when running the web site using VS.net's web server.
The permissions granted to user 'mycomputer\myusername' are insufficient for performing this operation. (rsAccessDenied)
The following is the exact code I'm using in the aspx page.
<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
<rsweb:ReportViewer ID="ReportViewer1" runat="server" ProcessingMode="Remote" Font-Names="Verdana"
Font-Size="8pt" InteractiveDeviceInfos="(Collection)" WaitMessageFont-Names="Verdana"
WaitMessageFont-Size="14pt" Width="712px">
<ServerReport ReportPath="/MyReports" ReportServerUrl="http://mycomputer/reportserver" />
</rsweb:ReportViewer>
mycomputer \ myusername is an Adminstrator on the machine. I also added it as an Administrator in the ReportManager.
I am running it using IE in Administrator mode.
What else could be causing the access denied issues?
I've read other people having issues, but most of them are not for 2008R2 so I haven't been able to figure out how to try what they did. There is no IIS to configure and no IUSR to give access to the reports.
SSRS logs just show the same error message without any other information.
Creating an instance class that implements IReportServerCredentials should fix the problem. Add the following class and call it as follows:
ReportViewer1.ServerReport.ReportServerCredentials = new ReportServerCredentials("username", "pwd", "domain");
/// <summary>
/// Local implementation of IReportServerCredentials
/// </summary>
public class ReportServerCredentials : IReportServerCredentials
{
private string _userName;
private string _password;
private string _domain;
public ReportServerCredentials(string userName, string password, string domain)
{
_userName = userName;
_password = password;
_domain = domain;
}
public WindowsIdentity ImpersonationUser
{
get
{
// Use default identity.
return null;
}
}
public ICredentials NetworkCredentials
{
get
{
// Use default identity.
return new NetworkCredential(_userName, _password, _domain);
}
}
public bool GetFormsCredentials(out Cookie authCookie, out string user, out string password, out string authority)
{
// Do not use forms credentials to authenticate.
authCookie = null;
user = password = authority = null;
return false;
}
}
Thanks to Phil Clewes: link

Object reference not set to an instance of an object.

My codes below don't have any errors during the compile time but when I open the page an error occur at the Guid currentUserId = (Guid)currentUser.ProviderUserKey; stating that Object reference not set to an instance of an object.
foreach(DataRowView ProfileInfo in UserProfileDataSource.Select(DataSourceSelectArguments.Empty))
{
//Some codes where I display data from database
}
protected void UserProfileDataSource_Selecting(object sender, SqlDataSourceSelectingEventArgs e)
{
MembershipUser currentUser = Membership.GetUser();
Guid currentUserId = (Guid)currentUser.ProviderUserKey;
e.Command.Parameters["USERID"].Value = currentUserId;
}
and here is my SQLDataSource
<asp:SqlDataSource ID="UserProfileDataSource" runat="server"
ConnectionString="<%$ ConnectionStrings:ConnectionString %>"
onselecting="UserProfileDataSource_Selecting"
ProviderName="<%$ ConnectionStrings:ConnectionString.ProviderName %>"
SelectCommand="SELECT "TITLE", "FAMILYNAME", "GIVENNAME", "MIDDLENAME", "POSITION", "INSTITUTIONNAME", "USERID", "REGISTEREDDATE" FROM "MEMBERINFO" WHERE ("USERID" = ?)">
<SelectParameters>
<asp:Parameter Name="USERID" Type="Object" />
</SelectParameters>
</asp:SqlDataSource>
Ernie
you should check to make sure that currentUser is not null before trying to access it:
if ( currentUser != null )
{
/* do stuff here */
}
else
{
/* do something else, like show an error message perhaps */
}
try this code:
string username = HttpContext.Current.User.Identity.Name;
if(!string.IsNullOrEmpty(username))
{
MembershipUser currentUser = Membership.GetUser(username);
Guid currentUserId = new Guid(currentUser.ProviderUserKey.ToString());
}
You appear to be allowing anonymous users to access a page that requires a logged in user. You can't get the user if they haven't logged in yet.
Security consists of two parts, authorization and authentication. Authentication is logging in, but authorization is denying access to pages to unauthorized users (such as ones that have not yet logged in, or do not have the correct roles assigned to them).
If your page depends on an authenticated user, then you should deny anonymous users access. If the page does not depend on an authenticated user, but merely makes use of member information if they are authenticated, then you need to guard against calling member functions (or anything that uses member data) if the user is not authenticated.
The issue is Bad code.
Try these steps:-
In your website, set the "Start page" to the correct "login" page.
Once you login, correctly and then land on the page, you should be able to access this property.
You may get into the same error if you click logout button and the landing page might be referring to this membership information.
So the work-around is simple.
1.Set the start page correctly.
2.Handle the 2 cases:- user is logged in and user is not logged in efficiently.
an example is as below:-
protected void Page_Load(object sender, EventArgs e)
{
if (Membership.GetUser() == null)
{ Label1.Text = "";
Label_TotalCoxxxxxxxxx.Text = "";
Label_TotalSuxxxxxxxxx.Text ="";
}
else {
string loggedinuser = Membership.GetUser().ToString();
Label1.Text = loggedinuser;
Label_TotalCoxxxxxxxxx.Text = "Total of xxxxxxxxxx Added in the current Month:-";
Label_TotalSuxxxxxxxxx.Text = "Total of yyyyyyyyyy done in the current Month:-";
}
}

ASP.NET how to store user login data in the APP

Just wondering what the best way to store user login data on successful login in my application. I.e. when logged in at the moment I do something like this in my login script
Session("loggedIn") = "Yes"
Session("userName") = reader_login("useremail").ToString()
Session("userId") = reader_login("user_ID").ToString()
Session("firstName") = reader_login("firstName").ToString()
Session("lastName") = reader_login("lastName").ToString()
And then I use these session variables on my scripts, but just noticed that every time I want to use some of these session variables I do need to check if they are nut null before calling them, seems a bit clumsy to repeat these for a lot of my .aspx pages. Is there a better way to do this ?
EDIT :
Also I am wondering why do I need to add the IS NUll check for the session on each script I use session variables I put the check in the master page but noticed I still get null exception in my usercontrol which is referenced in my master page but does not have the IS null check
Session is not the way to check whether user is authenticated or not. Session may be cleared on demand by administrator when clearing app pool, or by the low memory on server. You won't wish to log out user in such cases. The builtin and reccommended way for doing this in ASP.NET is storing data in authentication cookie. Once the user is logged in, you issue the cookie that contains all the data, including user id, name, etc. And then, you don't have to check every property in session for null, more simple - you just check if the user is authenticated - then you've got the data, else -not. And the other benefit, if you substitute builtin principal with custom one, you can define strongly typed object that holds user data, no more casting from objects extracted from session. Here're the examples for defining custom principal with forms authentication
First, let's define custom MyIdentity and MyPrincipal
public class MyIdentity : IIdentity
{
private FormsAuthenticationTicket _Ticket;
private int _userId = 0;
public FormsAuthenticationTicket Ticket
{
get { return _Ticket; }
}
public string Name
{
get { return _Ticket.Name; }
}
public int UserId
{
get
{
if (_userId == 0)
_userId = Convert.ToInt32(_Ticket.UserData.Split("|".ToCharArray())[0]);
return _userId;
}
}
public Identity(FormsAuthenticationTicket ticket)
{
this._Ticket = ticket;
}
public string AuthenticationType
{
get { return "Custom"; }
}
public bool IsAuthenticated
{
get { return UserId > 0; }
}
}
Then the MyPrincipal that holds MyIdentity
public class MyPrincipal : IPrincipal
{
private MyIdentity _Identity;
public Principal(MyIdentity identity)
{
_Identity = identity;
}
public IIdentity Identity
{
get { return _Identity; }
}
public bool IsInRole(string role)
{
return false;
}
}
Then substitute original forms user with the custom one. In Global.asax
private void Application_OnPostAuthenticateRequest(object sender, EventArgs e)
{
IPrincipal usr = HttpContext.Current.User;
// If we are dealing with an authenticated forms authentication request
if (usr.Identity.IsAuthenticated && usr.Identity.AuthenticationType == "Forms")
{
FormsIdentity formsIdentity = usr.Identity as FormsIdentity;
// Create a CustomIdentity based on the FormsAuthenticationTicket
IIdentity identity = new MyIdentity(formsIdentity.Ticket);
IPrincipal principal = new MyPrincipal(identity);
// Attach the CustomPrincipal to HttpContext.User and Thread.CurrentPrincipal
HttpContext.Current.User = principal;
Thread.CurrentPrincipal = principal;
}
}
Define method for issuing forms authentication ticket. Later, the custom MyIdentity class will extract userId and other methods from userData.
public static HttpCookie GetAuthCookie(string userName, string userData, bool createPersistentCookie, HttpSessionStateBase session)
{
HttpCookie authCookie = FormsAuthentication.GetAuthCookie(userName, createPersistentCookie);
FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(authCookie.Value);
FormsAuthenticationTicket newTicket = new FormsAuthenticationTicket(ticket.Version, ticket.Name, ticket.IssueDate, ticket.Expiration, ticket.IsPersistent, userData, session.SessionID);
authCookie.Value = FormsAuthentication.Encrypt(newTicket);
return authCookie;
}
When the user is checked and is authenticated, return them authentication cookie
Response.Cookies.Add(AuthenticationCookie.GetAuthCookie(model.UserName, GetUserInfo(model.UserName, passwordHash), model.RememberMe, Session));
//GetUserInfo returns | separated string of user datas. "userId|userName|firstName|lastName" for example.
And at last, using all of the above in code
if(User.Identity.IsAuthenticated)
{
int userId = ((MyIdentity)User.Identity).UserId;
}
This may seem the larger code, but in runtime it'll give much more benefits than storing all the data in session. The main of them are null checking and casting every time.
You could load this through a single object which you put in the Session. This will remove all your strings as you can just set properties. Also you can check if the object is available in the session, if it's not the user is not logged in?
public class CurrentUserObject
{
public string UserName { get; set; }
public string UserID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public CurrentUserObject(string userName, string userID, string firstName, string lastName)
{
UserName = userName;
UserID = userID;
FirstName = firstName;
LastName = lastName;
}
}
You can instantiate this object and store it in Session("CurrentUser") or something. If you request this session variable and it turns out to be null, your user is not logged in. I would advise you to do this in a master page or something by the way to avoid duplication of this code.
you don't have to store "loggedIn" in session.
you can use Session["userName"] to check, if it is null, not logged in; not null, logged in.
try to use one session item to track user login status, such username or userid.
also you can encapsule the logic into a method such as
static bool CheckLogin(HttpSession sessionState, out username, out userId, out firstName, out LastName);
FYI
may be you need to use caching in your application because you are going to check if null or not every time i think for save use data caching will be better and here are some links :
http://msdn.microsoft.com/en-us/library/xsbfdd8c(v=vs.71).aspx
http://msdn.microsoft.com/en-us/library/ms972379.aspx
http://www.exforsys.com/tutorials/asp.net/caching-in-asp.net.html
http://www.codeproject.com/KB/web-cache/cachingaspnet.aspx
Hope it helps mark as answered if it helps :)

Resources