我编写了 DNN 实现,所以我可以告诉你它是如何工作的。我不知道 ServiceStack 的细节,所以我不能告诉你如何在那里应用它。当我第一次着手构建它时,我预计它会比实际复杂得多。你真的只需要少数调用核心。
在 DnnController 初始化期间建立上下文和身份验证。DNN 完全开源的一大优点是所有这些细节都是公开的。这是DnnController.cs的链接
以下是最有趣的部分:
protected override void Initialize(RequestContext requestContext)
{
base.Initialize(requestContext);
LoadDnnContext(requestContext.HttpContext);
AuthenticateRequest(requestContext.HttpContext, PortalSettings.PortalId);
}
protected virtual void AuthenticateRequest(HttpContextBase context, int portalId)
{
if (!context.Request.IsAuthenticated)
{
BasicAuthenticator.Instance.TryToAuthenticate(context, portalId);
}
if (!context.Request.IsAuthenticated)
{
DigestAuthenticator.Instance.TryToAuthenticate(context, portalId);
}
MembershipModule.AuthenticateRequest(context, true /*allowUnknownExtension*/);
}
protected virtual void LoadDnnContext(HttpContextBase context)
{
var domainName = TestableGlobals.Instance.GetDomainName(context.Request);
var alias = TestablePortalAliasController.Instance.GetPortalAliasInfo(domainName);
int tabId;
ValidateTabAndModuleContext(context, alias.PortalID, out tabId);
var portalSettings = new PortalSettings(tabId, alias);
context.Items["PortalSettings"] = portalSettings;
}
服务框架将所有路由强制为 {unique portal path}/DesktopModules/{ModuleName}/API/{url} 形式。唯一的门户路径对于轻松识别请求发送到的门户非常重要。在大多数情况下,DNN 将允许 /Default.aspx?portalid=n 形式的 URL,但服务框架不会接受,它要求请求路径与门户别名匹配,例如 mysite.com/childportal/...要求确保 GetDomainName() 将起作用。
我应该提到 TestableXXX 类位于 Internal 命名空间中,因此不是官方公共 API 的一部分,并且会在版本之间发生重大变化。类上的大多数方法都有一个公共模拟,它更难模拟,但在其他方面是等效的。如果您在升级服务器之前进行小的代码修复是合理的,请随意使用 Testables。如果您无法完全控制服务器的升级,则应避免使用 .Internal 命名空间。
服务框架支持针对特定模块实例的权限进行身份验证。绑定到模块的服务必须提供选项卡和模块 ID。如果您的服务不是特定于模块的,您可以忽略它,并在 PortalSettings 中使用 tabid 为 -1。
ServiceFramework 有自己的基本和摘要身份验证实现,因为 MVC 不提供它们。我相信 ServiceStack 确实提供了 Basic 和 Digest,所以您可能只需要调用 MembershipModule.AuthenticateRequest()。