自己自定义实现了一个验证码表单过滤器,基于FormAuthenticationFilter
代码如下:
package cn.ddsxy.ddlx.shiro;
import cn.ddsxy.ddlx.util.CaptchaUtil;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.apache.shiro.web.util.WebUtils;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
/**
* 自定义表单过滤器
* @author zhiguang
*/
public class CaptchaFormAuthentcationFileter extends FormAuthenticationFilter {
/**
* 是否开启验证码支持
*/
private boolean captchaEbabled = true;
/**
* 验证码参数名
*/
private String captchaParam = "captcha";
public boolean isCaptchaEbabled() {
return captchaEbabled;
}
public void setCaptchaEbabled(boolean captchaEbabled) {
this.captchaEbabled = captchaEbabled;
}
public String getCaptchaParam() {
return captchaParam;
}
public void setCaptchaParam(String captchaParam) {
this.captchaParam = captchaParam;
}
public String getCaptcha(ServletRequest request){
return WebUtils.getCleanParam(request, this.getCaptchaParam());
}
@Override
protected CaptchaUserNamePassWordToken createToken(ServletRequest request, ServletResponse response) {
String username = request.getParameter("username");
String password = request.getParameter("password");
String captcha = request.getParameter("captcha");
return new CaptchaUserNamePassWordToken(username, password==null?"":password, captcha);
}
@Override
protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
CaptchaUserNamePassWordToken token = createToken(request, response);
try {
if(captchaEbabled) CaptchaUtil.verify(request);
Subject subject = getSubject(request, response);
subject.login(token);
return onLoginSuccess(token, subject, request, response);
} catch (IncorrectCaptchaException e) {
return onLoginFailure(token, e, request, response);
} catch (UnknownAccountException e1) { // 不存在用户名对应的有效用户记录
return onLoginFailure(token, e1, request, response);
} catch (IncorrectCredentialsException e2) { // 用户名或密码不对
return onLoginFailure(token, e2, request, response);
} catch (AuthenticationException e3) { // 其它异常
return onLoginFailure(token, e3, request, response);
}
}
@Override
protected void setFailureAttribute(ServletRequest request, AuthenticationException e) {
if(e instanceof IncorrectCaptchaException){
request.setAttribute(DEFAULT_ERROR_KEY_ATTRIBUTE_NAME,"验证码错误");
}else if(e instanceof UnknownAccountException){
request.setAttribute(DEFAULT_ERROR_KEY_ATTRIBUTE_NAME,"用户不存在");
}else if(e instanceof IncorrectCredentialsException){
request.setAttribute(DEFAULT_ERROR_KEY_ATTRIBUTE_NAME,"密码错误");
}else if(e instanceof AuthenticationException){
request.setAttribute(DEFAULT_ERROR_KEY_ATTRIBUTE_NAME,"登录失败");
}
}
/**
* 表示访问拒绝时是否自己处理,如果返回true表示自己不处理且继续拦截器链执行,返回false表示自己已经处理了(比如重定向到另一个页面)
* @param request
* @param response
* @return
* @throws Exception
*/
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
return super.onAccessDenied(request, response);
}
/**
* 是否允许访问,返回true表示允许
* @param request
* @param response
* @param mappedValue
* @return
*/
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
return super.isAccessAllowed(request, response, mappedValue);
}
}
CaptchaUtil.verify该方法验证验证码是否正确,可自行实现,重要的是executeLogin这个方法,我开始了解shiro的时候一直分不清这个 FormAuthenticationFilter过滤器和Realm的doGetAuthenticationInfo(身份认证)有什么关系,看源码,看到了AuthenticatingFilter这个父类executeLogin方法里调用了
protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
AuthenticationToken token = this.createToken(request, response);
if (token == null) {
String msg = "createToken method implementation returned null. A valid non-null AuthenticationToken must be created in order to execute a login attempt.";
throw new IllegalStateException(msg);
} else {
try {
Subject subject = this.getSubject(request, response);
subject.login(token);
return this.onLoginSuccess(token, subject, request, response);
} catch (AuthenticationException var5) {
return this.onLoginFailure(token, var5, request, response);
}
}
}
我明白了,这个过滤器无非还是用subject进行登录,shiro实现登录就这个接口