How to restrict access to WordPress content in .NE

2019-08-22 14:15发布

问题:

I have a WordPress site for a small journal. It is hosted in IIS on an Azure VM and uses MSSQL rather than MySQL. Although much of the content is freely available I want to restrict access to the more recent content to paying subscribers only. I'm wondering how I might do this. I was thinking of adding some simple code to the slug of each Post/Article (perhaps just having the slug start with 'protected-'). I could then write an C#.NET HttpHandler to check the Uri for the 'protected' code, check whether or not the user has access to it via entries in the DB, and allow, or not, access. Would this approach work? Any other possibilities.

Please note that I am not a PHP developer and any solution needs to be implementable using .NET.

EDIT 200814

I've made some progress using a HttpModule to review any incoming requests. This was achieved by adding the relevant lines to the Web.config:

Inside

<modules runAllManagedModulesForAllRequests="true">
    <add name="WpContentAccess" type="WpJournalHttpHandler.ContentAccessModule, WpJournalHttpHandler, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ced90a15f96f61ed" preCondition="managedHandler" />
</modules>

Inside

<httpModules>
  <add name="WpContentAccess" type="System.ServiceModel.Activation.HttpModule"/>
</httpModules>
<compilation targetFramework="4.0">
    <assemblies>
        <add assembly="WpJournalHttpHandler, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ced90a15f96f61ed" />
    </assemblies>
</compilation>

where WpJournalHttpHandler is my custom HttpModule.

I want to redirect whenever a user tries to view a Post/Article that has a slug containing 'protected', e.g., https://journal.emergentpublications.com/article/protected_eco_010101/

However, WP uses URL rewriting so my HttpModule never receives the original URL for processing. Do I need to have the HttpModule run before the URL rewriting?

Here's the rewrite entry in my web.config:

<rewrite>
  <rules>
        <rule name="wordpress" patternSyntax="Wildcard">
            <match url="*" />
                <conditions>
                    <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
                    <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
                </conditions>
            <action type="Rewrite" url="index.php" />
        </rule></rules>
</rewrite>

EDIT 200814_2

After changing the rewrite part of my Web.config to:

<rewrite>
    <rules>
        <rule name="WordPress Rule" stopProcessing="true">
            <match url=".*" />
            <conditions>
                <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
                <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
            </conditions>
            <action type="Rewrite" url="index.php?page_id={R:0}" />
        </rule>
    </rules>
</rewrite>

And had my HttpModule check context.Request.Url.ToString().Contains("protected") as part of the AuthenticateRequest event I can now filter the WP requests as desired.

回答1:

Take a look at Paid Memberships Pro, it should accomplish what you are looking for without having to write any code.

http://www.paidmembershipspro.com/

Note: I'm not trying to sell you something, I'm just a fan of their product and have used it on a couple of wordpress implementations.



回答2:

Adding a C#.NET HttpModule worked in the end. The full web.config for the WordPress site hosted with IIS is:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.webServer>
    <httpErrors errorMode="Detailed" />
        <validation validateIntegratedModeConfiguration="false" />
        <modules runAllManagedModulesForAllRequests="true">
            <add name="WpContentAccess" type="WpJournalHttpHandler.ContentAccessModule, WpJournalHttpHandler, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ced90a15f96f61ed" preCondition="managedHandler" />
        </modules>
        <rewrite>
      <rules>
            <rule name="wordpress" stopProcessing="true">
                <match url=".*" />
                    <conditions>
                        <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
                        <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
                    </conditions>
                <action type="Rewrite" url="index.php?page_id={R:0}" />
            </rule></rules>
    </rewrite>
  </system.webServer>
  <system.web>
    <customErrors mode="Off" />
        <httpModules>
      <add name="WpContentAccess" type="System.ServiceModel.Activation.HttpModule" />
    </httpModules>
        <compilation targetFramework="4.0">
            <assemblies>
                <add assembly="WpJournalHttpHandler, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ced90a15f96f61ed" />
            </assemblies>
        </compilation>
  </system.web>
</configuration>

And the skeleton code for my ContentAccessModule is:

using System;
using System.Web;
using System.Diagnostics;

namespace WpJournalHttpHandler
{
    public class ContentAccessModule : IHttpModule
    {
        private EventLog eventLog;

        public void Init(HttpApplication application)
        {
            application.AuthenticateRequest += Application_AuthenticateRequest;


            if (!EventLog.SourceExists("WpJournal"))
            {
                EventLog.CreateEventSource("WpJournal", "WpJournalActivity");
            }
            eventLog = new EventLog {Source = "WpJournal"};
            eventLog.WriteEntry("Application initialized.", EventLogEntryType.Information);
        }

        public void Dispose()
        {
            //Cleanup
        }

        private void Application_AuthenticateRequest(object source, EventArgs e)
        {
            HttpContext context = HttpContext.Current;
            eventLog.WriteEntry("Authentication for " + context.Request.Url + " from " + context.Request.UserHostAddress, EventLogEntryType.Information);
            if (context.Request.Url.ToString().Contains("protected"))
            {
                context.Response.Redirect("https://journal.emergentpublications.com/restricted-content/");
            }
        }

        private bool IsValidIpAddress(string ipAddress)
        {
            return false;
        }

        private string IsSubscribed(HttpContext context)
        {
            return null;
        }
    }
}

Once compiled the WpJournalHttpHandler was loaded into the GAC so it could be found by the web.config. Note that the WP project is actually a PHP project built using "PHP Tools for Visual Studio 2013". Now I can write whatever access logic I want for my WP content using C#.NET, as long as I change the slug of the Post/Article to include some common string such as "protected" (I'll probably use a string less likely to actually appear in a Post/Article title - perhaps a short random alphanumeric).

Note that if you use Event Logging like I have you'll need to give Network Service permission to access the event logs.