zoukankan      html  css  js  c++  java
  • springboot集成shiro实现验证码校验

    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登录页面

  • 相关阅读:
    js json 与字符串 转换过程由于书写不统一规范引发的一个问题
    asp.net 运行时,"未能映射路径"
    android html 图片处理类--加载富文本工具类
    System.Web.HttpCompileException (0x80004005): (0): error CS0016: 未能写入输出文件
    “请运行Chkdsk工具”怎么解决
    android studio新项目时提示:Plugin is too old, please update to a more recent version
    mvvm和mvc区别?
    什么是mvvm?
    js去除html标签
    数组的翻转(非reverse)
  • 原文地址:https://www.cnblogs.com/wangjing666/p/7339852.html
Copyright © 2011-2022 走看看