How do I manage my authentication with WorldDomina

2019-03-19 23:13发布

I'm trying to get social authentication working in an asp.net-hosted Nancy web app using the WorldDomination SimpleAuthentication plugin for Nancy. TL;DRs skip to the question bolded at the bottom of the question.

Both are pretty nice, but there is a big documentation gap between the authentication process (well covered) and identifying the authenticated user during requests other than the initial authenticate request (nothing).

Nancy provides for basic and forms authentication via additional packages, and the hooks they provide are pretty straight forward. WorldDomination does not provide much information past the actual authentication process. There seems to be a distinct lack of Happy Path for the normal "who is the user making this request" process that has to happen every time a user hits the server.

I've been spending a fair amount of time to figure this part out, but my research hasn't led me to any obvious solutions. The WD demo apps are bereft of request code other than authentication requests, and the codebase doesn't appear to contain anything dealing with the normal request cycle.

My best guess is that I need to integrate with forms auth, implementing Nancy's forms auth hooks and using what I get back from WD to populate my own types.

This doesn't exactly seem like the happiest of happy paths. In fact, it seems to be more of a "do lots of work you lazy bastard" path.

What, exactly, is the recommended happy path for integrating WorldDomination's social OAuth authentication providers and Nancy? I'm concentrating on the standard "who is this person that requests of me" page lifecycle part here.

Bonus points (from my hordes of sockpuppet accounts I will create for the purpose) for how this happy path handles users logging out as well!

1条回答
乱世女痞
2楼-- · 2019-03-20 00:13

With Simple Authentication, we simply handle the authentication with a provider in a simple way. Every provider has slightly different implementations, different naming, different promises, so we can to consolidate all that into Simple Authentication and make it easier for a developer to implement into their website.

Thats why the Nancy.SimpleAuthentication package exists. Because we know how Nancy works we have simplified the integration into Nancy by creating the modules for you to handle redirection, authentication callback, etc.

The problem is, we simply do not know how you authenticate a user against your website.

We can handle the whole forms auth scenario ourselves, and I actually plan to in the future. (have to implement claims first which I'm 60% way through), but it will still at bare minimum require you to implement the IAuthenticationCallbackProvider

public class Test : IAuthenticationCallbackProvider
{
    public dynamic Process(
        NancyModule nancyModule, 
        AuthenticateCallbackData model)
    {
        //Query for the database user based on the Provider / Id
        //Authenticate the user
        //Call LoginWithoutRedirect, and redirect how you want...
        //  or LoginWithRedirect

        return nancyModule.Negotiate.WithView("AuthenticateCallback")
            .WithModel(model);
    }
}

This class is required in order for you to authenticate the user against your database.

The thing we thought about tho is 95% of the time the user putting in the authentication, most likely already has some form of authentication already. Usually Forms Auth.


So assuming you've pulled in SimpleAuthentication, and wired up your IAuthenticationCallbackProvider class. All you really need to do is implement the Forms Auth stuff, which is pretty much 1 class, and a method call.

In the provider you need to call the LoginWithoutRedirect method so that Nancy can create an auth cookie.

Then you need to setup the IUserMapper class to tell Nancy how to get the user from the Database. If you're using RavenDB this would look something like:

public class DatabaseUser : IUserMapper
{
    public IDocumentStore DocumentStore { get; set; }
    public DatabaseUser(IDocumentStore documentStore)
    {
        DocumentStore = documentStore;
    }

    public IUserIdentity GetUserFromIdentifier(
        Guid identifier, 
        NancyContext context)
    {
        using (var session = DocumentStore.OpenSession())
        {
            var member = session.Query<Member>()
                .SingleOrDefault(x => x.Identifier == identifier);

            if (member == null)
                return null;

            return new UserIdentity
            {
                UserName = member.DisplayName,
                Claims = new []
                {
                    "NewUser",
                    "CanComment"
                }
            };
        }
    }
}

Configured in the bootstrapper like:

protected override void ConfigureRequestContainer(
    TinyIoCContainer container,
    NancyContext context)
{
    base.ConfigureRequestContainer(container, context);
    container.Register<IUserMapper, DatabaseUser>();
}
protected override void RequestStartup(
    TinyIoCContainer container, 
    IPipelines pipelines, 
    NancyContext context)
{
    base.RequestStartup(container, pipelines, context);

    var formsAuthConfiguration = new FormsAuthenticationConfiguration
    {
        RedirectUrl = "~/login",
        UserMapper = container.Resolve<IUserMapper>(),
    };

    FormsAuthentication.Enable(pipelines, formsAuthConfiguration);
}

And that's really it...

I personally don't think it's a lot of code that you have to write. Both Nancy and Simple Authentication have done most of the leg work for you :)

I hope we can make SimpleAuthentication even easier in the future by removing the need for the Forms Auth, but for now I think we have a pretty good solution.

Helpful links:

http://www.philliphaydon.com/2012/12/18/forms-authentication-with-nancyfx/

http://www.philliphaydon.com/2013/01/31/oauth-with-nancyfx-and-world-domination-authentication/

The 2nd link for World Domination, although there's a bit of renaming, it's mostly the same. I do plan to do an updated blog post and revamp the wiki when we have polished off Claims.

I hope that helps you.

Edit:

  • I've made note to create a more end-to-end solution demo project.
查看更多
登录 后发表回答