我在Umbraco 7中遇到了公共访问问题。
我使用自定义成员资格提供程序通过我的CRM数据库对用户进行身份验证。 我设置了一条规则,允许只访问经过身份验证的(前端)用户,并使用自定义角色提供程序来定义经过身份验证的用户具有访问者角色。如果未经过身份验证,则会将其重定向到登录页面。
当我调试网站时,用户具有以下角色:
我已通过身份验证,当前用户的角色非常好。
但我仍然被重定向到登录页面!我不明白。
我的角色提供者:
public class CustomRoleProvider : Umbraco.Web.Security.Providers.MembersRoleProvider
{
const int SITE_ID = 6;
public override string ApplicationName
{
get
{
return "Site";
}
}
public override string[] GetAllRoles()
{
return new[] { Const.VISITORS_LABEL };
}
public override string[] GetRolesForUser(string username)
{
return new[] { Const.VISITORS_LABEL };
}
/// <summary>
///
/// </summary>
/// <param name="username"></param>
/// <param name="roleName"></param>
/// <returns></returns>
public override bool IsUserInRole(string username, string roleName)
{
//every user is a visitor
if(roleName == Const.VISITORS_LABEL)
{
return true;
}
else
{
return base.IsUserInRole(username, roleName);
}
}
public override string[] GetUsersInRole(string roleName)
{
if(roleName == Const.VISITORS_LABEL)
{
using (var db = new CRMEntities())
{
var usersEmails = db.Customer_View.Where(x => x.SiteID == SITE_ID).Select(x=>x.Email).ToArray();
return usersEmails;
}
}
else
{
return base.GetUsersInRole(roleName);
}
}
}
以下是我用于身份验证的控制器:
public class MemberLoginSurfaceController : Umbraco.Web.Mvc.SurfaceController
{
// The MemberLogin Action returns the view, which we will create later. It also instantiates a new, empty model for our view:
[HttpGet]
[ActionName("MemberLogin")]
public ActionResult MemberLoginGet()
{
return PartialView("MemberLogin", new MemberLoginModel());
}
// The MemberLogout Action signs out the user and redirects to the site home page:
[HttpGet]
public ActionResult MemberLogout()
{
Session.Clear();
FormsAuthentication.SignOut();
return Redirect("/");
}
// The MemberLoginPost Action checks the entered credentials using the standard Asp Net membership provider and redirects the user to the same page. Either as logged in, or with a message set in the TempData dictionary:
[HttpPost]
[ActionName("MemberLogin")]
public ActionResult MemberLoginPost(MemberLoginModel model)
{
if (Membership.ValidateUser(model.Username, model.Password))
{
FormsAuthentication.SetAuthCookie(model.Username, model.RememberMe);
return RedirectToCurrentUmbracoPage();
}
else
{
TempData["Status"] = "Invalid username or password";
return RedirectToCurrentUmbracoPage();
}
}
}
我的角色提供程序位于web.config中,并且Visitors角色在管理面板中被检测为角色。
<roleManager enabled="true" defaultProvider="CustomRoleProvider">
<providers>
<clear />
<add name="UmbracoRoleProvider" type="Umbraco.Web.Security.Providers.MembersRoleProvider" />
<add name="CustomRoleProvider" type="*.UI.Helpers.CustomRoleProvider" />
</providers>
</roleManager>
编辑:我忘了会员提供商:
public class MyMembershipProvider : Umbraco.Web.Security.Providers.MembersMembershipProvider
{
const int SITE_ID = 6;
//we dont let user change their password using RC website
public override bool AllowManuallyChangingPassword
{
get
{
return false;
}
}
public override bool EnablePasswordReset
{
get
{
return false;
}
}
public override bool EnablePasswordRetrieval
{
get
{
return false;
}
}
public override bool ValidateUser(string username, string password)
{
Customer_View user;
//just to avoid errors with uppercase letters
username = username.ToLowerInvariant();
using (var db = new CRMEntities())
{
user = db.Customer_View.SingleOrDefault(x => x.Email == username && x.SiteID == SITE_ID);
//no user with this email
if (user == null)
return false;
//check if password is same
return user.Password == password;
}
}
public override MembershipUser GetUser(string username, bool userIsOnline)
{
//just to avoid errors with uppercase letters
username = username.ToLowerInvariant();
MembershipUser toReturn;
using (var db = new CRMEntities())
{
Customer_View user = db.Customer_View.SingleOrDefault(x => x.Email == username && x.SiteID == SITE_ID);
toReturn = user != null ? new MembershipUser(
//provider name
"MyMembershipProvider", string.Format("{0} {1}", user.FirstName, user.LastName),
username, username, string.Empty, string.Empty, true, true, user.CreateDate, new DateTime(), new DateTime(), new DateTime(), new DateTime()) :
null;
}
return toReturn;
}
public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)
{
return this.GetUser(providerUserKey as string, userIsOnline);
}
}
每当我尝试访问具有特定访问权限的页面时,即使我通过了身份验证,我也会被重定向到登录页面:
我该如何解决?
答案 0 :(得分:2)
您为什么要添加自定义角色提供程序。保持简单。如果您有该站点的注册页面,则可以以编程方式分配成员类型和成员角色
如果您从后端添加成员,则可以添加&#34;访客&#34;角色很容易。
所以在这两种情况下&#34;访客&#34;角色可以轻松应用于所有成员,您可以轻松地登录访问者角色(所有经过身份验证)的页面。
修改强> 我已经删除了以编程方式向用户添加角色的代码,因为您不需要,解决方案如下:
正如您所知,自定义角色提供程序和自定义成员资格提供程序齐头并进。您已添加了自定义成员资格提供程序和覆盖的< input sed -e 's/\(.*\)=.*/\1=${\1}/' | tr \\n \ ; echo
方法,但要使所有这些工作正常,您需要覆盖另外两个ValidateUser
方法,请参阅下面的自定义提供程序代码,它可以正常工作
的MembershipProvider
GetUser
<强> EDIT2 强>
好的,我调试了roleprovider和membershipprovider中的每一段代码,当用户登录用户尝试访问受保护页面后,首先调用public class MyMembershipProvider : MembersMembershipProvider
{
public override bool ValidateUser(string username, string password)
{
if (base.ValidateUser(username,password))
{
//if this is umbraco user validate by base method
return true;
}
else
{
var allow = //add your validation code for CRM, I have checked if username is "tester" and allowed for testing purpose.
return allow;
}
}
// These two methods below which you have not overridden and need to override for public access to work
public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)
{
if(base.GetUser(providerUserKey, false)!=null)
//if this is umbraco user add it as is.
return base.GetUser(providerUserKey,userIsOnline);
else
//Add your CRM user, I do not have database, so added test user
return new MembershipUser("UmbracoMembershipProvider", "tester", 1233, "tester@test.com", null, null, true, false, DateTime.Now, DateTime.Now, DateTime.Now, DateTime.Now, DateTime.Now);
}
public override MembershipUser GetUser(string username, bool userIsOnline)
{
if (true)//check if this is CRM user here
{
return new MembershipUser("UmbracoMembershipProvider", "tester", 1233, "tester@test.com", null, null, true, false, DateTime.Now, DateTime.Now, DateTime.Now, DateTime.Now, DateTime.Now);
//I am adding test user, you should create user from your CRM database
}
else
return base.GetUser(username,false);
}
}
,如果失败,则返回登录页面,此后是成功GetUser(string username, bool userIsOnline)
接到电话。如果返回null,则显示访问页面不足,否则将调用GetUser(object providerUserKey, bool userIsOnline)
。并显示所有成功页面。我在两个文件的每个方法上都设置了断点,因此只涉及这3种方法。当你看到登录页面时,我的猜测是GetRolesForUser(string username)
这个第一次调用失败了。
以下是我的文件,如果它有帮助
角色配置部分
GetUser(string username, bool userIsOnline)
会员配置部分
<roleManager enabled="true" defaultProvider="UmbracoRoleProvider">
<providers>
<clear />
<!--<add name="UmbracoRoleProvider" type="Umbraco.Web.Security.Providers.MembersRoleProvider" />-->
<add name="UmbracoRoleProvider" type="Assembly.Providers.MyRolesProvider" />
</providers>
</roleManager>
的AccountController
<membership defaultProvider="UmbracoMembershipProvider" userIsOnlineTimeWindow="15">
<providers>
<clear />
<add name="UmbracoMembershipProvider" type="Assembly.Providers.MyMemberShipProvider, Assembly" enablePasswordRetrieval="false" enablePasswordReset="false" 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" />-->
<add name="UsersMembershipProvider" type="Assembly.Providers.MyUserMembershipProvider, Assembly" minRequiredNonalphanumericCharacters="0" minRequiredPasswordLength="4" useLegacyEncoding="true" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" passwordFormat="Hashed" />
</providers>
</membership>
RolesProvider
public class AccountSurfaceController : Umbraco.Web.Mvc.SurfaceController
{
[HttpPost]
public ActionResult LoginForm(LoginModel model)
{
//model not valid, do not save, but return current umbraco page
if (!ModelState.IsValid)
{
//Perhaps you might want to add a custom message to the TempData or ViewBag
//which will be available on the View when it renders (since we're not
//redirecting)
return CurrentUmbracoPage();
}
// Login
if (Membership.ValidateUser(model.Username, model.Password))
{
FormsAuthentication.SetAuthCookie(model.Username, false);
return RedirectToCurrentUmbracoUrl();
}
else
{
ModelState.AddModelError("Username", "Username is not valid");
return CurrentUmbracoPage();
}
}
}
public class LoginModel
{
[Required]
public string Username { get; set; }
[Required]
[DataType(DataType.Password)]
public string Password { get; set; }
}
<强> EDIT3:强>
我重现了你的场景,它与web.config配置有关
当我保持网络配置以获得会员资格时,除非我打电话
,否则它没有打到我的提供商public class MyRolesProvider : MembersRoleProvider
{
const string VISITORS_LABEL = "Visitor";
public override string[] GetAllRoles()
{
var roles = base.GetAllRoles().ToList();
roles.Add(VISITORS_LABEL);
return roles.ToArray();
}
public override string[] FindUsersInRole(string roleName, string usernameToMatch)
{
if(roleName== VISITORS_LABEL)
{
var users = ApplicationContext.Current.Services.MemberService
.GetAllMembers().Select(m => m.Email).ToList();
users.Add("tester@test.com");
return users.ToArray();
}
return base.FindUsersInRole(roleName, usernameToMatch);
}
public override bool RoleExists(string roleName)
{
if(roleName == VISITORS_LABEL)
{
return true;
}
return base.RoleExists(roleName);
}
public override string[] GetRolesForUser(string username)
{
var roles = base.GetRolesForUser(username).ToList();
roles.Add(VISITORS_LABEL);
return roles.ToArray();
}
public override bool IsUserInRole(string username, string roleName)
{
if(roleName == VISITORS_LABEL)
{
return true;
}
return base.IsUserInRole(username, roleName);
}
public override string[] GetUsersInRole(string roleName)
{
if(roleName == VISITORS_LABEL)
{
var list = ApplicationContext.Current.Services.MemberService
.GetAllMembers().Select(m => m.Email).ToList();
list.Add("tester@test.com");
return list.ToArray();
}
return base.GetUsersInRole(roleName);
}
}
但是当它改变为下面给出的时候它起作用了。请仔细检查配置中的差异。
<membership defaultProvider="MyMembershipProvider" userIsOnlineTimeWindow="15">
<providers>
<clear />
<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="MyMembershipProvider" type="Umbraco724.Providers.MyMembersMembershipProvider, Umbraco724" />
<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>
我认为umbraco只为会员和用户提供一个提供商。此外,它的名称应仅为 UmbracoMembershipProvider 。当我保持不同的时候也有错误。
答案 1 :(得分:0)
使用Umbraco的公共访问权限,当用户注销并尝试访问受保护的页面时,他们将看到登录页面。但是,地址栏中的URL将是他们尝试访问的页面的URL。
验证后,用户RedirectToCurrentUmbracoPage()
将实际执行完全重定向到登录页面,地址栏中的URL将相应更新。您实际想要做的是将它们重定向到当前URL。您可以将RedirectToCurrentUmbracoPage()
方法中的第一个MemberLoginPost
替换为RedirectToCurrentUmbracoUrl()
来完成此操作。
当用户的凭据不正确时,您还使用RedirectToCurrentUmbracoPage()
,这也会导致完全重定向到登录页面。如果您只是将CurrentUmbracoPage()
返回给用户,那么一切都应该正常工作。请参阅下面的更新方法:
[HttpPost]
[ActionName("MemberLogin")]
public ActionResult MemberLoginPost(MemberLoginModel model)
{
if (Membership.ValidateUser(model.Username, model.Password))
{
FormsAuthentication.SetAuthCookie(model.Username, model.RememberMe);
return RedirectToCurrentUmbracoUrl();
}
else
{
TempData["Status"] = "Invalid username or password";
return CurrentUmbracoPage();
}
}