springboot集成shiro实现验证码校验

守給你的承諾、 提交于 2020-01-30 17:18:14

github:https://github.com/peterowang/shiro/

这里实现验证码校验的思路是自己添加一个Filter继承FormAuthenticationFilter,FormAuthenticationFilter负责表单验证,shiro会先在FormAuthenticationFilter子类去校验验证码,然后再去做身份验证。

生成验证码这里使用Google的Kaptcha框架。

1.添加依赖

<!--google的验证码框架--><dependency>   <groupId>com.google.code.kaptcha</groupId>   <artifactId>kaptcha</artifactId>   <version>2.3</version></dependency>

2.拓展UsernamePasswordToken,将验证码包含进去:

在com.example.demo.config.Shiro包下添加以下类:

package com.example.demo.config.shiro;import org.apache.shiro.authc.UsernamePasswordToken;/** * 对UsernamePasswordToken进行二次封装,将验证码加入 * Created by BFD-593 on 2017/8/10. */public class CaptchaUsernamePasswordToken extends UsernamePasswordToken {    /*    * serialVersionUID用来作为Java对象序列化中的版本标示之用;    * 如果一个序列化类没有声明这样一个static final的常量,    * JVM会根据各种参数为这个类计算一个; 对于同样一个类,    * 不同版本的JDK可能会得出不同的serivalVersionUID;    * 所以为了兼容性,一般自己加一个,至于值自己定就行,不一定是1L。自己练习的时候加不加没什么区别。    *    * */    private static final long serivalVersionUID = 1L;    //验证码字符串    private String captcha;    public CaptchaUsernamePasswordToken(String username, char[] password, boolean rememberMe, String host, String captcha) {        super(username,password,rememberMe, host);        this.captcha = captcha;    }    public static long getSerivalVersionUID() {        return serivalVersionUID;    }    public String getCaptcha() {        return captcha;    }    public void setCaptcha(String captcha) {        this.captcha = captcha;    }}顺便再Exception包下添加一个验证码异常的类,方便在controller中捕获:
package com.example.demo.config.ExceptionResolver;import org.apache.shiro.authc.AuthenticationException;/** * 将shiro异常进行二次封装,抛出该异常表示验证码不正确,好让controller通过判断进行error设置展示在前台 * Created by BFD-593 on 2017/8/10. */public class IncorrectCaptchaException extends AuthenticationException {    /*    * serialVersionUID用来作为Java对象序列化中的版本标示之用;    * 如果一个序列化类没有声明这样一个static final的常量,    * JVM会根据各种参数为这个类计算一个; 对于同样一个类,    * 不同版本的JDK可能会得出不同的serivalVersionUID;    * 所以为了兼容性,一般自己加一个,至于值自己定就行,不一定是1L。自己练习的时候加不加没什么区别。    *    * */   private static final long serialVersionUID = 1L;    public IncorrectCaptchaException() {        super();    }    public IncorrectCaptchaException(String message, Throwable cause) {        super(message, cause);    }    public IncorrectCaptchaException(String message) {        super(message);    }    public IncorrectCaptchaException(Throwable cause) {        super(cause);    }}

2.添加校验用的Filter

package com.example.demo.filter;import com.example.demo.config.ExceptionResolver.IncorrectCaptchaException;import com.example.demo.config.shiro.CaptchaUsernamePasswordToken;import org.apache.shiro.authc.AuthenticationException;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;import javax.servlet.http.HttpServletRequest;/** * 对FormAuthenticationFilter进行封装 * 这里实现验证码校验的思路是自己添加一个Filter继承FormAuthenticationFilter, * FormAuthenticationFilter负责表单验证, * shiro会先在FormAuthenticationFilter子类去校验验证码,然后再去做身份验证。 * Created by BFD-593 on 2017/8/10. */public class KaptchaFilter extends FormAuthenticationFilter{        public static final String DEFAULT_CAPTCHA_PARAM = "captcha";//此处的值应和前台验证码值的name对应        private String captchaParam = DEFAULT_CAPTCHA_PARAM;        @Override        protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {            CaptchaUsernamePasswordToken token = createToken(request, response);            try {                doCaptchaValidate((HttpServletRequest) request, token);//先做校验验证码是否正确                Subject subject = getSubject(request, response);                subject.login(token);//身份验证                return onLoginSuccess(token, subject, request, response);//设置成功跳转            } catch (AuthenticationException e) {                return onLoginFailure(token,e,request,response);//设置保存异常对象            }        }        //验证码校验        protected void doCaptchaValidate(HttpServletRequest request, CaptchaUsernamePasswordToken token) {            // 从session中获取图形吗字符串,这个是由goggle的框架帮我们设置到session中的            String captcha = (String) request.getSession().getAttribute(com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY);            // 校验            if (captcha == null || !captcha.equals(token.getCaptcha())) {                throw new IncorrectCaptchaException();            }        }        /*        * 将username password host rememberMe 和captcha封装到我们自己的CaptchaUsernamePasswordToken中        * */        @Override        protected CaptchaUsernamePasswordToken createToken(ServletRequest request, ServletResponse response) {            String username = getUsername(request);            String password = getPassword(request);            String host = getHost(request);            boolean rememberMe = isRememberMe(request);            String captcha = getCaptcha(request);            return new CaptchaUsernamePasswordToken(username,password.toCharArray(),rememberMe,host,captcha);        }        /*        * 在request请求中获取name=captcha的值(也就是验证码的值)        * */        protected  String getCaptcha(ServletRequest request) {            return WebUtils.getCleanParam(request, getCaptchaParam());        }        //保存异常对象到request        @Override        protected void setFailureAttribute(ServletRequest request, org.apache.shiro.authc.AuthenticationException ae) {            request.setAttribute(getFailureKeyAttribute(), ae);        }        public String getCaptchaParam() {            return captchaParam;        }        public void setCaptchaParam(String captchaParam) {            this.captchaParam = captchaParam;        }}在com.example.demo.config.Shiro.ShiroConfiguration的ShiroFilterFactoryBean中添加验证码filter。.....
//将我们自己的拦截器注入到shiro中Map<String, Filter> filterMap = shiroFilterFactoryBean.getFilters();//先获取shiro内部拦截器KaptchaFilter kaptchaFilter = new KaptchaFilter();//初始化自己的拦截器filterMap.put("kaptchaFilter", kaptchaFilter);//加入我们的拦截器shiroFilterFactoryBean.setFilters(filterMap);//注入....
filterChainDefinitionMap.put("/login", "kaptchaFilter");//设置登录时使用kaptchaFilter我们自己的拦截器filterChainDefinitionMap.put("/kaptcha.jpg", "anon");//图片验证码(kaptcha框架,会访问localhost:8080/kaptcha.jpg来自动生成验证码)....接下来需要在启动类中注册KaptchaServlet.
    //配置kaptcha图片验证码框架提供给Servlet   @Bean   public ServletRegistrationBean kaptchaServlet() {      //图片验证码(kaptcha框架,会访问localhost:8080/kaptcha.jpg来自动生成验证码)      ServletRegistrationBean registrationBean = new ServletRegistrationBean(new KaptchaServlet(), "/kaptcha.jpg");      //设置初始化参数,供kaptcha生成指定样式的验证码      registrationBean.addInitParameter(Constants.KAPTCHA_SESSION_CONFIG_KEY,            Constants.KAPTCHA_SESSION_KEY);      registrationBean.addInitParameter(Constants.KAPTCHA_IMAGE_HEIGHT,"60");//高度      registrationBean.addInitParameter(Constants.KAPTCHA_IMAGE_WIDTH,"150");      registrationBean.addInitParameter(Constants.KAPTCHA_TEXTPRODUCER_FONT_SIZE,"50");//字体大小      registrationBean.addInitParameter(Constants.KAPTCHA_BORDER_THICKNESS,"1"); //边框      registrationBean.addInitParameter(Constants.KAPTCHA_TEXTPRODUCER_FONT_COLOR, "red"); //文字颜色      //可以设置很多属性,具体看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;   }

3.最后,在login.html页面把验证码添加进去:

<div><label> 验证码 : <input type="text" name="captcha" placeholder="验证码"/> </label></div><div><img th:src="@{/kaptcha.jpg}"></div>

好了,在进入login登录页面

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!