I'm trying to login using UserService, but unfortunately there is no isPersistent flag on the login function. Is there a reason for this? Because my login code is in a separate assembly, shared between two Silverlight applications, I want to use UserService
rather than using the authentication class that is created as part of the .net ria services generated code (which does have isPersistent on it).
I'm actually not quite clear why there are two classes for logging in. In a normal situation, when should we use the authentication class that is built in generated code, and when should we use the user service class?
In addition, I want users to be able to login with their e-mail address, rather than their username. Unfortunately on the server-side authentication class it is not possible to override the login function and therefore change the username like this:
So, I have done some further investigation. I've discovered that if I use my own function to log in with an e-mail address then
UserService.Current.User is never set and there is no way to set it, so hopefully someone will have some solutions on how to solve the above two problems.
UserService is intended as a client-side abstraction for authentication and authorization. This should become more evident in later releases. The generated authentication context is just the default way to communicate with the server. In most cases, you
should be using the abstraction.
The second Login signature supports the isPersistent flag.
Off the top of my head, I'm not sure whether ASP.NET Membership allows you to use email addresses as usernames. I assume it would, but there might be some character restrictions. If that won't work for you, you could override the ValidateUser method in AuthenticationBase.
If you want the email address available on the client, you can add it to your user object and override the GetAuthenticatedUser and GetAnonymousUser methods.
Thanks for your suggestion regarding login parameters, that works fine.
I don't want to use e-mail address as the username, just allow people to log in using their e-mail address, which means I need to translate the e-mail address into the username. As you say, you can use ValidateUser, which I have tried, but the problem is
with the login function in AuthenticationBase:
if (this.ValidateUser(userName, password)) {
IPrincipal principal =
new GenericPrincipal(new Identity("Forms",
true, userName), AuthenticationBase<T>.DefaultRoles.ToArray<string>());
this.IssueAuthenticationToken(principal, isPersistent);
return
this.GetUserCore(principal);
}
Because I changed the userName in ValidateUser (using similar code to what I've posted in my original message) but then the creation of the GenericPrincipal doesn't have the new updated userName. So it fails to work properly.
I do have another problem with the persistent cookie option - when I call
UserService.Current.Logout() I get an exception: UserService operation already in progress, but I haven't done anything at all with the user service in that session because I've just restarted.
2) Have email address appear as username in the principal.
In the snippet above, GetUserCore(principal) calls into GetAuthenticatedUser(). You could override that to populate the user however you like. I'd recommend letting the name property be the username and just adding an email property. It might look something
like this.
protected override UserBase GetAuthenticatedUser(IPrincipal principal)
{
// ...
user.Email = Membership.GetEmailForUser(user.Name);
}
// ...public class User : UserBase
{
[ProfileUsage(IsExcluded = true)]
public string Email { get; set; }
}
I'm not sure about the Logout issue. You probably have something running (check the UserService.IsBusy property), but it's difficult to know without more details.
My goal is to be able to login using the e-mail address, or username. One of the problems with a websites is that it's easy to forget your username, but remembering your e-mail address is much easier, so I want users to log in with their e-mail address.
The problem I'm having is that the login system requires a username, which is fine, because I can get the username from the e-mail address, but before any login activity occurs I need to replace the e-mail addresses I have been provided as a username with
the actual username, so that the new Identity("Forms",
true, userName) can be created correctly.
I don't need to have the e-mail address appear as the username, I need the username to appear as the username. The problem is that I want to pass in the e-mail address to the login function because that is what the user has given me.
Just try and be completely clear, here is the code that I would like to be able to write, but I currently can't because login is not virtual:
public override User Login(string userName,
string password, bool isPersistent)
{ string newUserName = Membership.GetUserNameByEmail(userName); if (newUserName != null)
// if the user has provided an e-mail address use the username associated with that
{
userName = newUserName;
} return base.Login(userName, password, isPersistent);
}
After reading your posts a few times, I think you should get the right results if you override ValidateUser, GetAuthenticatedUser, and IssueAuthenticationToken to switch out the username. It's not as easy as just overriding Login, but it should get things
working for you.
StefanOlson
Member
260 Points
138 Posts
UserService/Authentication issues
May 11, 2009 11:45 PM | LINK
I'm trying to login using UserService, but unfortunately there is no isPersistent flag on the login function. Is there a reason for this? Because my login code is in a separate assembly, shared between two Silverlight applications, I want to use UserService rather than using the authentication class that is created as part of the .net ria services generated code (which does have isPersistent on it).
I'm actually not quite clear why there are two classes for logging in. In a normal situation, when should we use the authentication class that is built in generated code, and when should we use the user service class?
In addition, I want users to be able to login with their e-mail address, rather than their username. Unfortunately on the server-side authentication class it is not possible to override the login function and therefore change the username like this:
string
newUserName = Membership.GetUserNameByEmail(userName);if (newUserName != null)
{
userName = newUserName;
}
I tried to create a custom login function, but service functions return InvokeEventArgs rather than LoginCompletedEventArgs.
...Stefan
StefanOlson
Member
260 Points
138 Posts
Re: UserService/Authentication issues
May 12, 2009 04:29 AM | LINK
So, I have done some further investigation. I've discovered that if I use my own function to log in with an e-mail address then UserService.Current.User is never set and there is no way to set it, so hopefully someone will have some solutions on how to solve the above two problems.
...Stefan
kylemc
Contributor
7231 Points
1146 Posts
Microsoft
Re: UserService/Authentication issues
May 12, 2009 04:01 PM | LINK
UserService is intended as a client-side abstraction for authentication and authorization. This should become more evident in later releases. The generated authentication context is just the default way to communicate with the server. In most cases, you should be using the abstraction.
The second Login signature supports the isPersistent flag.
Off the top of my head, I'm not sure whether ASP.NET Membership allows you to use email addresses as usernames. I assume it would, but there might be some character restrictions. If that won't work for you, you could override the ValidateUser method in AuthenticationBase. If you want the email address available on the client, you can add it to your user object and override the GetAuthenticatedUser and GetAnonymousUser methods.
Kyle
StefanOlson
Member
260 Points
138 Posts
Re: UserService/Authentication issues
May 13, 2009 02:28 AM | LINK
Kyle,
Thanks for your suggestion regarding login parameters, that works fine.
I don't want to use e-mail address as the username, just allow people to log in using their e-mail address, which means I need to translate the e-mail address into the username. As you say, you can use ValidateUser, which I have tried, but the problem is with the login function in AuthenticationBase:
if (this.ValidateUser(userName, password)) {IPrincipal principal =
new GenericPrincipal(new Identity("Forms", true, userName), AuthenticationBase<T>.DefaultRoles.ToArray<string>()); this.IssueAuthenticationToken(principal, isPersistent); return this.GetUserCore(principal);}
Because I changed the userName in ValidateUser (using similar code to what I've posted in my original message) but then the creation of the GenericPrincipal doesn't have the new updated userName. So it fails to work properly.
I do have another problem with the persistent cookie option - when I call UserService.Current.Logout() I get an exception: UserService operation already in progress, but I haven't done anything at all with the user service in that session because I've just restarted.
...Stefan
kylemc
Contributor
7231 Points
1146 Posts
Microsoft
Re: UserService/Authentication issues
May 13, 2009 04:57 PM | LINK
I'm hearing two conflicting goals.
1) Login with email address, not username.
2) Have email address appear as username in the principal.
In the snippet above, GetUserCore(principal) calls into GetAuthenticatedUser(). You could override that to populate the user however you like. I'd recommend letting the name property be the username and just adding an email property. It might look something like this.
Kyle
kylemc
Contributor
7231 Points
1146 Posts
Microsoft
Re: UserService/Authentication issues
May 13, 2009 04:59 PM | LINK
I'm not sure about the Logout issue. You probably have something running (check the UserService.IsBusy property), but it's difficult to know without more details.
Kyle
StefanOlson
Member
260 Points
138 Posts
Re: UserService/Authentication issues
May 13, 2009 08:44 PM | LINK
The logout issue was my fault, there was a bug in my routed command implementation.
StefanOlson
Member
260 Points
138 Posts
Re: UserService/Authentication issues
May 13, 2009 08:52 PM | LINK
My goal is to be able to login using the e-mail address, or username. One of the problems with a websites is that it's easy to forget your username, but remembering your e-mail address is much easier, so I want users to log in with their e-mail address.
The problem I'm having is that the login system requires a username, which is fine, because I can get the username from the e-mail address, but before any login activity occurs I need to replace the e-mail addresses I have been provided as a username with the actual username, so that the new Identity("Forms", true, userName) can be created correctly.
I don't need to have the e-mail address appear as the username, I need the username to appear as the username. The problem is that I want to pass in the e-mail address to the login function because that is what the user has given me.
Hopefully, that makes it clearer :-)
...Stefan
StefanOlson
Member
260 Points
138 Posts
Re: UserService/Authentication issues
May 13, 2009 09:49 PM | LINK
Just try and be completely clear, here is the code that I would like to be able to write, but I currently can't because login is not virtual:
public override User Login(string userName, string password, bool isPersistent)
{
string newUserName = Membership.GetUserNameByEmail(userName);
if (newUserName != null) // if the user has provided an e-mail address use the username associated with that
{
userName = newUserName;
}
return base.Login(userName, password, isPersistent);
}
...Stefan
kylemc
Contributor
7231 Points
1146 Posts
Microsoft
Re: UserService/Authentication issues
May 14, 2009 07:11 PM | LINK
After reading your posts a few times, I think you should get the right results if you override ValidateUser, GetAuthenticatedUser, and IssueAuthenticationToken to switch out the username. It's not as easy as just overriding Login, but it should get things working for you.
Kyle