更新答案:
在发布原始答案Combining Forms Authentication and Basic Authentication几个月后,我偶然发现了这个问题。我没有测试过这个解决方案,因为那艘船已经航行了,但它看起来很有希望。
原答案:
据我所知,这个问题的答案是“不”。您无法修改 Umbraco 内容页面的标题,因此您无法告诉浏览器针对给定的 LDAP 服务器进行身份验证。
但是,我能够使用表单身份验证以相同的方式运行(针对 Active Directory 进行身份验证并针对我的数据库进行授权)。下面我包含了在 Umbraco 中获得此身份验证所需的所有代码。
登录页面
登录页面只是一个 Umbraco 视图,使用以下部分视图和表面控制添加到其中@Html.Action("MemberUmbLogin", "MemberUmbLoginSurface")
@model CustomUmbraco.Models.MemberUmbLoginModel
@if (User.Identity.IsAuthenticated)
{
<p>Logged in: @User.Identity.Name</p>
<p>@Html.ActionLink("Log out", "MemberUmbLogout", "MemberUmbLoginSurface")</p>
}
else
{
using (Html.BeginUmbracoForm("MemberUmbLogin", "MemberUmbLoginSurface"))
{
@Html.EditorFor(x => Model)
<input type="submit" />
}
<p>@TempData["Status"]</p>
}
登录模式
public class MemberUmbLoginModel
{
public string Username { get; set; }
[DataType(DataType.Password)]
public string Password { get; set; }
public bool RememberMe { get; set; }
}
表面控制器
public class MemberUmbLoginSurfaceController : SurfaceController
{
//
// GET: /MemberUmbLogin/
[HttpGet]
[ActionName("MemberUmbLogin")]
public ActionResult MemberUmbLoginGet()
{
return PartialView("MemberUmbLogin", new MemberUmbLoginModel());
}
[HttpGet]
public ActionResult MemberUmbLogout()
{
Session.Clear();
FormsAuthentication.SignOut();
return Redirect("/");
}
[HttpPost]
[ActionName("MemberUmbLogin")]
public ActionResult MemberUmbLoginPost(MemberUmbLoginModel model)
{
string returnUrl = GetValidReturnUrl(Request.UrlReferrer);
if (Membership.ValidateUser(model.Username, model.Password))
{
FormsAuthentication.SetAuthCookie(model.Username, model.RememberMe);
if (Url.IsLocalUrl(returnUrl) && !String.IsNullOrWhiteSpace(returnUrl))
{
return Redirect(returnUrl);
}
return RedirectToCurrentUmbracoPage();
}
TempData["Status"] = "Invalid username or password";
return RedirectToCurrentUmbracoPage();
}
private static String GetValidReturnUrl(Uri uri)
{
string returnUrl = null;
if (uri != null && !String.IsNullOrWhiteSpace(uri.PathAndQuery) && uri.PathAndQuery.StartsWith("/") &&
!uri.PathAndQuery.StartsWith("//") && !uri.PathAndQuery.StartsWith("/\\"))
{
returnUrl = uri.PathAndQuery;
}
return returnUrl;
}
}
我将自定义 MembershipProvider 与标准 Umbraco 角色提供程序一起使用。我依靠 MembershipProvider 来根据我的非 Umbraco 数据库更新成员的角色,每当他们登录时。然后 MembershipProvider 用适当的组更新成员。
注意:因为我使用的是 Umbraco 的角色提供程序,所以我需要将我的非 Umbraco 数据库中的角色作为“成员组”添加到 Umbraco。
网页配置
<!-- Membership Provider -->
<membership defaultProvider="CustomMembershipProvider" userIsOnlineTimeWindow="15">
<providers>
<clear />
<add name="CustomMembershipProvider" type="CustomUmbraco.MembershipProviders.CustomMembershipProvider" minRequiredNonalphanumericCharacters="0" minRequiredPasswordLength="4" useLegacyEncoding="true" enablePasswordRetrieval="false" enablePasswordReset="false" requiresQuestionAndAnswer="false" defaultMemberTypeAlias="NetIDAlias" passwordFormat="Hashed" />
<add name="UmbracoMembershipProvider" type="Umbraco.Web.Security.Providers.MembersMembershipProvider, Umbraco" minRequiredNonalphanumericCharacters="0" minRequiredPasswordLength="4" useLegacyEncoding="true" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" defaultMemberTypeAlias="Member" passwordFormat="Hashed" />
<add name="UsersMembershipProvider" type="Umbraco.Web.Security.Providers.UsersMembershipProvider, Umbraco" minRequiredNonalphanumericCharacters="0" minRequiredPasswordLength="4" useLegacyEncoding="true" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" passwordFormat="Hashed" />
</providers>
</membership>
<!-- Role Provider -->
<roleManager enabled="true" defaultProvider="UmbracoRoleProvider">
<providers>
<clear />
<add name="UmbracoRoleProvider" type="Umbraco.Web.Security.Providers.MembersRoleProvider" />
</providers>
</roleManager>
会员提供者
public class CustomMembershipProvider : MembershipProvider
{
private String GetDomainFreeName(String fullName)
{
return fullName.Contains("\\") ? fullName.Substring(fullName.IndexOf("\\") + 1) : fullName;
}
public override bool ValidateUser(string username, string password)
{
DirectoryEntry directoryEntry = new DirectoryEntry(ConfigurationManager.ConnectionStrings["LDAPConnection"].ConnectionString, username, password);
DirectorySearcher searcher = new DirectorySearcher(directoryEntry);
String domainFreeName = GetDomainFreeName(username);
searcher.Filter = String.Format("(&(objectClass=user)(SAMAccountName={0})(!msExchUserAccountControl=2))", domainFreeName);
SearchResult result;
try
{
result = searcher.FindOne();
}
catch (COMException)
{
return false; // authentication failed
}
if (result != null)
{
NotReallyARoleProvider provider = new NotReallyARoleProvider();
provider.UpdateUserRoles(domainFreeName);
Member m = Member.GetMemberFromLoginName(domainFreeName);
Member.AddMemberToCache(m);
return true;
}
return false;
}
}
更新用户角色方法
public void UpdateUserRoles(String username)
{
var groups = this.GetRolesForUser(username); // this is the method that gets the roles for your user.
this.RemoveUsersFromRoles(new[] { username }, this.GetAllRoles());
this.AddUsersToRoles(new[] { username }, groups);
}
public override void AddUsersToRoles(string[] usernames, string[] roleNames)
{
foreach (String username in usernames)
{
Member m = Member.GetMemberFromLoginName(username);
if (m == null)
{
m = Member.MakeNew(username, MemberType.GetByAlias("Member"), new User(0));
m.LoginName = username;
}
roleNames.ForEach(group => m.AddGroup(MemberGroup.GetByName(group).Id));
m.Save(true);
}
}
public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames)
{
foreach (String username in usernames)
{
Member m = Member.GetMemberFromLoginName(username);
if (m == null)
{
m = Member.MakeNew(username, MemberType.GetByAlias("Member"), new User(0));
m.LoginName = username;
}
roleNames.ForEach(group => m.RemoveGroup(MemberGroup.GetByName(group).Id));
m.Save(true);
}
}
最后,我不使用 ActiveDirectoryMembershipProvider 的原因是因为我无法获得足够的权限来修改帐户。
这个解决方案远非完美,但它对我有用。如果您在登录页面时遇到问题,但它表现得好像您不在正确的组中,或者如果您从 Umbraco 界面中删除了一个成员并且当您调用时他们仍然出现Member.GetMemberFromLoginName(username)
,那么您可能有用以下行替换您的 Provider 中的会员保存代码一次。
ApplicationContext.Current.Services.MemberService.DeleteMembersOfType(MemberType.GetByAlias("Member").Id);
这将清除存储在 ethereal 存储库中的所有成员。
有了所有这些代码,用户就可以像往常一样选择他们想要访问 Umbraco 后台内容页面的组。