若依框架-Shiro验证码校验过滤器源码分析

本文介绍了一个基于若依框架的管理平台项目迁移过程中遇到的问题,即登录接口仅接收用户名和密码,未集成验证码验证。文章详细解析了如何利用Shiro框架的自定义过滤器来实现验证码的功能,并展示了具体的代码实现。
摘要由CSDN通过智能技术生成

引入

在将公司一个管理平台项目迁移到若依框架时,发现了其登录接口只接收 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值