我正在构建一个ASP。. Net MVC web应用程序,使用Umbraco7,以取代旧的WebForms网站。
旧的WebForms站点在站点的某些部分使用Basic Authentication
(在IIS的目录级别指定),它指定了一个默认的Windows域和自己的Active directory。浏览器请求相应页面上的用户ID和密码,后面的代码使用System.Web.UI.Page.User.Identity
属性检索用户信息。
我想在新的Umbraco网站上提供类似的体验。
使用Basic Authentication
的MVC站点示例将认证和默认域作为Controller方法http://www.asp.net/mvc/tutorials/older-versions/security/authenticating-users-with-windows-authentication-cs的属性。
Umbraco似乎没有为其内容页提供单独的控制器方法,并且我没有发现任何使用Basic Authentication
并依赖浏览器检索凭据的Umbraco身份验证示例。
是否可以在Umbraco内容页面上使用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;
}
}
我正在使用带有标准Umbraco角色提供程序的自定义MembershipProvider。每当成员登录时,我依靠MembershipProvider根据我的非umbraco数据库更新成员的角色。MembershipProvider然后用适当的组更新成员。
注意:因为我使用的是Umbraco的角色提供者,我需要将角色从我的非Umbraco数据库添加到Umbraco作为"成员组"。
web . config
<!-- 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>
MembershipProvider
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;
}
}
UpdateUserRoles方法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)
,那么你可能不得不替换你的成员保存代码在你的提供者与以下一行一次。
ApplicationContext.Current.Services.MemberService.DeleteMembersOfType(MemberType.GetByAlias("Member").Id);
这将清除存储在以太存储库中的所有成员。
有了所有这些代码,用户可以选择他们想要访问Umbraco后台内容页面的组,就像正常一样。