shiro 集成kaptcha验证码

一、添加依赖包

<!--验证码依赖包-->
<dependency>
    <groupId>com.github.penggle</groupId>
    <artifactId>kaptcha</artifactId>
    <version>2.3.2</version>
</dependency>

二、新建CaptchaValidateFilter.java 过滤器 继承AccessControlFilter

/**
 * create_by krystal on 2018/11/15/015.
 */
public  class CaptchaValidateFilter extends AccessControlFilter {
    private String captchaParam = "captchaCode"; //前台提交的验证码参数名
    private String failureKeyAttribute = "shiroLoginFailure";  //验证失败后存储到的属性名
    public String getCaptchaCode(ServletRequest request) {
        return WebUtils.getCleanParam(request, getCaptchaParam());
    }
    public String getName(ServletRequest request) {
        return WebUtils.getCleanParam(request, "name");
    }
    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue)
            throws Exception {
        // 从session获取正确的验证码
        Session session = SecurityUtils.getSubject().getSession();
        //页面输入的验证码
        String name=getName(request);
        String validateCode = (String)session.getAttribute(Constants.KAPTCHA_SESSION_KEY);
        String captchaCode = getCaptchaCode(request);
        HttpServletRequest httpServletRequest = WebUtils.toHttp(request);
        //判断验证码是否表单提交(允许访问)
        if ( !"post".equalsIgnoreCase(httpServletRequest.getMethod())) {
            return true;
        }
        // 若验证码为空或匹配失败则返回false
        if(captchaCode == null) {
            return false;
        } else if (validateCode != null) {
            captchaCode = captchaCode.toLowerCase();
            validateCode = validateCode.toLowerCase();
            if(!captchaCode.equals(validateCode)) {
                return false;
            }
        }
        return true;
    }
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        //如果验证码失败了,存储失败key属性
        request.setAttribute(failureKeyAttribute, "验证码错误");
        return true;
    }
    public String getCaptchaParam() {
        return captchaParam;
    }
    public void setCaptchaParam(String captchaParam) {
        this.captchaParam = captchaParam;
    }
}

三、新建KaptchaConfig.java 验证码工具类

public class KaptchaConfig {
    @Bean
    public ServletRegistrationBean<KaptchaServlet> kaptchaServlet() {

        ServletRegistrationBean<KaptchaServlet> registrationBean = new ServletRegistrationBean<KaptchaServlet>(new KaptchaServlet(), "/captcha/kaptcha.jpg");

        registrationBean.addInitParameter(Constants.KAPTCHA_SESSION_CONFIG_KEY,
                Constants.KAPTCHA_SESSION_KEY);
        //宽度
        registrationBean.addInitParameter(Constants.KAPTCHA_IMAGE_WIDTH,"140");
        //高度
        registrationBean.addInitParameter(Constants.KAPTCHA_IMAGE_HEIGHT,"60");
        //字体大小
        registrationBean.addInitParameter(Constants.KAPTCHA_TEXTPRODUCER_FONT_SIZE,"50");
//        registrationBean.addInitParameter(Constants.KAPTCHA_BORDER_THICKNESS,"1"); //边框
        //无边框
        registrationBean.addInitParameter(Constants.KAPTCHA_BORDER,"no");
        //文字颜色
        registrationBean.addInitParameter(Constants.KAPTCHA_TEXTPRODUCER_FONT_COLOR, "blue");
        //长度
        registrationBean.addInitParameter(Constants.KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "4");
        //字符间距
        registrationBean.addInitParameter(Constants.KAPTCHA_TEXTPRODUCER_CHAR_SPACE, "6");

        //可以设置很多属性,具体看com.google.code.kaptcha.Constants
//      kaptcha.border  是否有边框  默认为true  我们可以自己设置yes,no
//      kaptcha.border.color   边框颜色   默认为Color.BLACK
//      kaptcha.border.thickness  边框粗细度  默认为1
//      kaptcha.producer.impl   验证码生成器  默认为DefaultKaptcha
//      kaptcha.textproducer.impl   验证码文本生成器  默认为DefaultTextCreator
//      kaptcha.textproducer.char.string   验证码文本字符内容范围  默认为abcde2345678gfynmnpwx
//      kaptcha.textproducer.char.length   验证码文本字符长度  默认为5
//      kaptcha.textproducer.font.names    验证码文本字体样式  默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
//      kaptcha.textproducer.font.size   验证码文本字符大小  默认为40
//      kaptcha.textproducer.font.color  验证码文本字符颜色  默认为Color.BLACK
//      kaptcha.textproducer.char.space  验证码文本字符间距  默认为2
//      kaptcha.noise.impl    验证码噪点生成对象  默认为DefaultNoise
//      kaptcha.noise.color   验证码噪点颜色   默认为Color.BLACK
//      kaptcha.obscurificator.impl   验证码样式引擎  默认为WaterRipple
//      kaptcha.word.impl   验证码文本字符渲染   默认为DefaultWordRenderer
//      kaptcha.background.impl   验证码背景生成器   默认为DefaultBackground
//      kaptcha.background.clear.from   验证码背景颜色渐进   默认为Color.LIGHT_GRAY
//      kaptcha.background.clear.to   验证码背景颜色渐进   默认为Color.WHITE
//      kaptcha.image.width   验证码图片宽度  默认为200
//      kaptcha.image.height  验证码图片高度  默认为50
        return registrationBean;
    }
}

四、新建MyFormAuthenticationFilter .java

用于验证码验证的Shiro拦截器在用于身份认证的拦截器之前运行;但是如果验证码验证拦截器失败了,就不需要进行身份认证拦截器流程了;所以需要修改下如FormAuthenticationFilter身份认证拦截器,当验证码验证失败时不再走身份认证拦截器

public class MyFormAuthenticationFilter extends FormAuthenticationFilter {
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
        if (request.getAttribute(getFailureKeyAttribute()) != null) {
            return true;
        }
        return super.onAccessDenied(request, response, mappedValue);
    }
    @Override
    protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception {
        WebUtils.issueRedirect(request, response, getSuccessUrl());
        return false;
    }
}

五、在shiro 权限类里面加上我们自己写的验证码过滤器

private void loadShiroFilterChain(ShiroFilterFactoryBean shiroFilterFactoryBean){/*, UserService userService*/
    /////////////////////// 下面这些规则配置最好配置到配置文件中 ///////////////////////
    Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
    //自定义拦截器 验证码使用
    Map<String, Filter> filters = shiroFilterFactoryBean.getFilters();
    filters.put("captchaVaildate", new CaptchaValidateFilter());
    filters.put("authc111", new MyFormAuthenticationFilter());
  
    filterChainDefinitionMap.put("/sysUser/**", "authc");
    filterChainDefinitionMap.put("/**", "anon");//anon 可以理解为不拦截
    shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
}

六、在jsp使用:

<c:set var="ctx" value="${pageContext.request.contextPath}"></c:set>
<div class="layui-form-item form_code">
    <input class="layui-input"  name="captchaCode" id="captchaCode" placeholder="验证码" lay-verify="required" type="text" autocomplete="off"/>
    <div>
        <img type="image" src="${ctx}/captcha/kaptcha.jpg" id="codeImage" onclick="chageCode()" title="图片看不清?点击重新得到验证码" style="cursor:pointer;" width="116" height="36"/>
    </div>
</div>

七、登录时候进行校验,判断是否验证码错误(方式很多我只写了这个)

在登录的方法里面加上:

if("验证码错误".equals(request.getAttribute("shiroLoginFailure"))){//该返回值在过滤器中有set进去
    //return "codeError";
    json.put("message","验证码错误");
    json.put("flag","errorCode");
    return json;
}

猜你喜欢

转载自blog.csdn.net/sinat_34338162/article/details/84256988