引入
在将公司一个管理平台项目迁移到若依框架时,发现了其登录接口只接收 username 和 password 两个参数,并无验证码。
@PostMapping("/login")
@ResponseBody
public AjaxResult ajaxLogin(String username, String password, Boolean rememberMe) {
UsernamePasswordToken token = new UsernamePasswordToken(username, password, rememberMe);
Subject subject = SecurityUtils.getSubject();
try {
subject.login(token);
return success();
} catch (AuthenticationException e) {
String msg = "用户或密码错误";
if (StringUtils.isNotEmpty(e.getMessage())) {
msg = e.getMessage();
}
return error(msg);
}
}
查看源码发现 shiro 单独用了个过滤器处理验证码
// 登录相关
filterChainDefinitionMap.put("/login", "anon,captchaValidate"); // echoo mark: 登录、注册使用验证码校验过滤器
// 注册相关
filterChainDefinitionMap.put("/register", "anon,captchaValidate");
filters.put("captchaValidate", captchaValidateFilter()); // echoo mark: 验证码校验过滤器 加入 滤池映射
验证码过滤器
/**
* 验证码过滤器
*/
public class CaptchaValidateFilter extends AccessControlFilter {
/**
* 是否开启验证码
*/
private boolean captchaEnabled = true;
/**
* 验证码类型
*/
private String captchaType = "math";
public void setCaptchaEnabled(boolean captchaEnabled) {
this.captchaEnabled = captchaEnabled;
}
public void setCaptchaType(String captchaType) {
this.captchaType = captchaType;
}
// echoo mark: 验证码校验逻辑
@Override
public boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception { // 校验逻辑
request.setAttribute(ShiroConstants.CURRENT_ENABLED, captchaEnabled);
request.setAttribute(ShiroConstants.CURRENT_TYPE, captchaType);
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
System.out.println("httpServletRequest.getRequestURI() = " + httpServletRequest.getRequestURI());
// 调用父类的 onPreHandle 方法,
// isAccessAllowed(request, response, mappedValue) || onAccessDenied(request, response, mappedValue)
// 因为 isAccessAllowed onAccessDenied 都是抽象方法,且在此过滤器实现,所以父类调用的是此过滤器实现的两个判断方法
// isAccessAllowed 返回 true 则直接通过校验,放行
// isAccessAllowed 返回 false 则执行 onAccessDenied 的判断逻辑决定是否通过放行
return super.onPreHandle(request, response, mappedValue);
}
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue)
throws Exception {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
// 验证码禁用 或不是表单提交 允许访问
// 只校验 Post 请求,Get 请求为转接登录页面请求
if (captchaEnabled == false || !"post".equals(httpServletRequest.getMethod().toLowerCase())) {
return true;
}
// 取出请求中参数 validateCode 的值作为验证码
return validateResponse(httpServletRequest,
httpServletRequest.getParameter(ShiroConstants.CURRENT_VALIDATECODE));
}
public boolean validateResponse(HttpServletRequest request, String validateCode) {
Session session1 = ShiroUtils.getSession();
System.out.println("shiro中的会话对象 = " + session1);
// 取出当前会话 KAPTCHA_SESSION_KEY 的值
Object obj = ShiroUtils.getSession().getAttribute(Constants.KAPTCHA_SESSION_KEY);
String code = String.valueOf(obj != null ? obj : "");
// 验证码清除,防止多次使用。
HttpSession session = request.getSession();
System.out.println("请求中的会话对象 = " + session);
// 移除请求中 会话对象的的 KAPTCHA_SESSION_KEY 字段
session.removeAttribute(Constants.KAPTCHA_SESSION_KEY);
// 校验会话中的验证码是否与请求表单中的验证码一致
if (StringUtils.isEmpty(validateCode) || !validateCode.equalsIgnoreCase(code)) {
return false;
}
return true;
}
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
// 设置 captcha 字段值为 captchaError , 在后续的逻辑中通过此字段判断校验结果
request.setAttribute(ShiroConstants.CURRENT_CAPTCHA, ShiroConstants.CAPTCHA_ERROR);
return true;
}
}
其父类:
1.为抽象类
2.onPreHandle() 方法有默认实现
3.onAccessDenied() 和 isAccessAllowed() 需要自己实现逻辑
public abstract class AccessControlFilter extends PathMatchingFilter {
public boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
return isAccessAllowed(request, response, mappedValue) || onAccessDenied(request, response, mappedValue);
}
protected abstract boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception;
protected abstract boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception;
}