I need to have Sitecore send an email to a particular email address whenever a user gets locked out of Sitecore by entering an incorrect password too many times. I have code to send an email; however, I don't see a pipeline that fires during the login process (loggedin and loggingin only fire upon successful login).
3 に答える
Had to modify @Maras's answer a little bit to get it to work as the domain is not prefixed to the UserName property in the LoggingIn Event. Other than that the code works great.
namespace My.Namespace.Login
{
public class CustomLoginPage : LoginPage
{
private bool _userIsNotLockedOut;
protected override void OnInit(EventArgs e)
{
Login.LoggingIn += Login_LoggingIn;
Login.LoginError += Login_LoginError;
base.OnInit(e);
}
private void Login_LoggingIn(object sender, LoginCancelEventArgs e)
{
string domainUser = Login.UserName;
if (!domainUser.Contains("sitecore\\"))
{
var domain = Sitecore.Context.Domain;
domainUser = domain + @"\" + domainUser;
}
var user = Membership.GetUser(domainUser, false);
if (user != null)
{
_userIsNotLockedOut = !user.IsLockedOut;
}
}
private void Login_LoginError(object sender, EventArgs e)
{
if (_userIsNotLockedOut)
{
var user = Membership.GetUser(Login.UserName, false);
if (user != null && user.IsLockedOut)
{
SendEmail();
}
}
}
}
}
Also you need to reference the Sitecore.Client.dll, testing done in Sitecore 7.
This solution assumes that you're using standard Sitecore login page.
I managed to achieve what you need with overriding Sitecore login page. What you need to do is to create a class which inherits from Sitecore.sitecore.login.LoginPage
(it's not a typo) class and then add 2 methods which will be executed before logging in to the system and after login failed as follows:
namespace My.Assembly.Namespace
{
public class MyLoginPage : LoginPage
{
private bool maybeWillBeLockedOut;
protected override void OnInit(EventArgs e)
{
Login.LoggingIn += Login_LoggingIn;
Login.LoginError += Login_LoginError;
base.OnInit(e);
}
void Login_LoggingIn(object sender, LoginCancelEventArgs e)
{
MembershipUser user = Membership.Provider.GetUser(Login.UserName, false);
// user with username exists and is not locked out yet
maybeWillBeLockedOut = user != null && !user.IsLockedOut;
}
void Login_LoginError(object sender, EventArgs e)
{
if (maybeWillBeLockedOut)
{
// login failed - lets check if locked out now
MembershipUser user = Membership.Provider.GetUser(Login.UserName, false);
if (user != null && user.IsLockedOut)
{
// user wasn't locked out but is now - send an email
SendEmail();
}
}
}
}
}
Then update sitecore\login\default.aspx file and set the new class in Inherits attribute:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="default.aspx.cs"
Inherits="My.Assembly.Namespace.MyLoginPage" %>
This is not the most elegant solution but as you and @OptimizedQuery noticed, LoggingIn
and LoggedIn
pipelines are not sufficient in this scenario.
I added a custom pipeline process just before the Sitecore.Pipelines.LoggingIn.CheckStartPage, Sitecore.Kernel
processor in the loggingin
pipeline process. When I entered a valid username and invalid password, my breakpoint was hit before I was notified that my login was unsuccessful. If your custom processor comes after the CheckStartPage
processor, then it would only get hit upon successful login because the CheckStartPage
process aborts the pipeline if the username/password combination fails validation. I am unsure how to check for a locked out user but it appears you should be able to add your processor before the CheckStartPage
processor or override that processor.
My testing and Reflecting was done on a Sitecore 6.6 solution.