Reputation: 2643
I am using NancyFx to make a simple website were users can login and out using an ajax control.
I have read the documentation on Forms Authentication with Nancy and I think I have completed all the required steps.
I am having an issue where after calling login, requests do not have a current user set. I can see a cookie set after the login is executed. However the user mapper is not getting called. I have tried requesting routes with and with out the this.RequiresAuthentication(); and still no user.
Here is my Bootstrapper Implementation for step 4
public class Bootstrapper : DefaultNancyBootstrapper
{
protected override void ConfigureApplicationContainer(TinyIoCContainer container)
{
container.Register<ISessionFactory>((c, p) => SessionFactory.Factory);
}
protected override void ConfigureConventions(NancyConventions conventions)
{
base.ConfigureConventions(conventions);
conventions.StaticContentsConventions.Add(StaticContentConventionBuilder.AddDirectory("assets", @"content/assets"));
conventions.StaticContentsConventions.Add(StaticContentConventionBuilder.AddDirectory("application", @"content/application"));
}
protected override void ConfigureRequestContainer(TinyIoCContainer container, NancyContext context)
{
base.ConfigureRequestContainer(container, context);
container.Register<IUserMapper, UserMapper>();
}
protected override void RequestStartup(TinyIoCContainer container, IPipelines pipelines, NancyContext context)
{
base.RequestStartup(container, pipelines, context);
var formsAuthConfiguration =
new FormsAuthenticationConfiguration()
{
RedirectUrl = "~/",
UserMapper = container.Resolve<IUserMapper>()
};
FormsAuthentication.Enable(pipelines, formsAuthConfiguration);
}
}
Here is my login & logout logic for step 3.
Post["/login"] = x =>
{
//Verify here, hardcode for testing
string email = "[email protected]";
User user = ExecuteCommand(new FetchUser(email));
this.LoginWithoutRedirect(user.Session);
return new { email = user.Email, authorized = true, status = "okay" };
};
Post["/logout"] = x =>
{
return this.Logout("~/");
};
My IUsermapper simply looks up a user from a database with the given id. I can see it gets constructed when the RequestStartup resolves the IUserMapper but then there are never any calls to the get GetUserFromIdentifier function.
Any help would be great.
Upvotes: 2
Views: 2188
Reputation: 19123
The GetUserFromIdentifier
method is not being called because you are using the LoginWithoutRedirect
extension. It is not the login that calls GetUserFromIdentifier
but rather any subsequent redirect.
A more usual way of doing things would be:
string email = "[email protected]";
User user = ExecuteCommand(new FetchUser(email));
this.LoginAndRedirect(user.Session);
It is not expected that the login route would be accessed directly. Instead the user would normally request a protected resource, be authenticated and then redirected to the requested resource.
A couple of other points:
When I tried your code I got an error returning an anonymous type. Instead I needed to return the type as json, like this:
this.LoginWithoutRedirect(user.Session);
return Response.AsJson(new
{
email = user.Email,
authorized = true,
status = "okay"
});
This works fine, it logs in and returns your anonymous type as a json object and since there is no redirect then, as expected, it does not call GetUserFromIdentifier
.
Finally, your /logout
route should be protected using this.RequiresAuthentication()
. It makes sense because only authenticated users need to logout. It will also protect you when GetUserFromIdentifier
returns null - perhaps because a cached user has been timed out. RequiresAuthentication
detects this null user and redirects back to Get["/login"]
.
Upvotes: 1