美文网首页
springboot实现验证码功能

springboot实现验证码功能

作者: 85年的大喇叭 | 来源:发表于2023-11-26 20:47 被阅读0次

    转载自 : www.javaman.cn

    1、编写工具类生成4位随机数

    该工具类主要生成从0-9,a-z,A-Z范围内产生的4位随机数

    /**
         * 产生4位随机字符串
         */
        public static String getCheckCode() {
            String base = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
            int size = base.length();
            Random r = new Random();
            StringBuffer sb = new StringBuffer();
            for (int i = 1; i <= 4; i++) {
                //产生0到size-1的随机值
                int index = r.nextInt(size);
                //在base字符串中获取下标为index的字符
                char c = base.charAt(index);
                //将c放入到StringBuffer中去
                sb.append(c);
            }
            return sb.toString();
        }
    

    2、编写常量类

    用户常量的绑定,所有的常量都可以在ConfigConsts中定义,方便管理。

    import java.util.Arrays;
    import java.util.List;
    
    public interface ConfigConsts {
        /**
         * 验证码存session
         */
        String IMAGE_CODE_SESSION = "IMAGE_CODE";
    }
    

    3、获取验证码接口

    这段代码的主要作用是为用户生成一个图片验证码,并将其显示在浏览器中。当调用该代码对应的URL时,服务器会创建一个包含随机验证码的图片,并将此验证码存储在用户的会话中,然后将该图片发送给用户的浏览器显示

         /**
         * 验证码
         */
        @RequestMapping("/getImgCode")
        public void getImgCode(HttpServletRequest request, HttpServletResponse response) {
            int width = 80;
            int height = 30;
            BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            //获取画笔
            Graphics graphics = image.getGraphics();
            //设置画笔颜色为白色
            graphics.setColor(Color.white);
            //填充图片
            graphics.fillRect(0, 0, width, height);
            //设置画笔颜色为黑色
            graphics.setColor(Color.black);
            //设置字体的小大
            graphics.setFont(new Font("黑体", Font.BOLD, 24));
            //产生4个随机验证码
            String checkCode = CommonUtil.getCheckCode();
            //将验证码放入HttpSession中
            HttpSession session = request.getSession();
            session.setAttribute(ConfigConsts.IMAGE_CODE_SESSION, checkCode);
            //向图片上写入验证码
            graphics.drawString(checkCode, 15, 25);
            //将内存中的图片输出到浏览器
            try {
                response.setContentType("image/png");
                ImageIO.write(image, "PNG", response.getOutputStream());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    

    4、controller跳转到登录页

    对“/loginPage”的GET请求,并将用户重定向到登录页面。当调用这个URL时,系统会返回一个名为"login"的视图(通常是一个HTML页面),这个视图通常用于显示登录表单,让用户输入用户名和密码等信息。

        /**
         * 跳转到登陆页面
         * @return 登陆页面
         */
        @GetMapping("/loginPage")
        public String loginPage(){
            return "login";
        }
    

    5、登录界面

    在Web页面上实现一个图形验证码的输入功能

    1. HTML部分
      • 创建一个表单项,内部包含两列(使用layui的栅格系统)。
      • 在第一列中,有一个标签和一个文本输入框。标签用于显示一个验证码图标,输入框用于用户输入图形验证码。
      • 在第二列中,有一个图片元素用于显示图形验证码图片。
    2. JavaScript部分
      • 配置layui的静态资源路径和主入口模块。
      • 初始化时,调用getImgCode函数加载验证码图片,并渲染表单。
      • getImgCode函数通过Ajax请求从服务器获取验证码图片,并将其显示在页面上的图片元素中。

    这段代码主要利用了layui框架来实现页面的布局和交互,同时通过JavaScript和Ajax实现与服务器的通信,以获取并显示图形验证码。

    <div class="layui-form-item">
        <div class="layui-row">
            <div class="layui-col-xs7">
                <label class="layadmin-user-login-icon layui-icon layui-icon-vercode"></label>
                <input type="text" name="code"  lay-verify="required" placeholder="图形验证码" class="layui-input">
            </div>
            <div class="layui-col-xs5">
                <div style="margin-left: 10px;">
                    
                    <img id="codeImg" class="layadmin-user-login-codeimg">
                </div>
            </div>
        </div>
        
        <script>
        layui.config({
            base: '/static/layuiadmin/' //静态资源所在路径
        }).extend({
            index: 'lib/index' //主入口模块
        }).use(['index', 'user'], function(){
            let $ = layui.$,
                form = layui.form;
            // 初始化
            getImgCode();
            form.render();
        }
        /**
         * 获取验证码
         */
        function getImgCode() {
            let url = ctx + '/getImgCode';
            let xhr = new XMLHttpRequest();
            xhr.open('GET', url, true);
            xhr.responseType = "blob";
            xhr.onload = function() {
                if (this.status === 200) {
                    let blob = this.response;
                    document.getElementById("codeImg").src = window.URL.createObjectURL(blob);
                }
            }
            xhr.send();
        }
        </script>
    

    6、验证码过滤

    校验验证码的过滤器,基于Java的Spring框架。

    1. 该过滤器继承了OncePerRequestFilter,确保每次请求只被过滤一次。
    2. doFilterInternal方法中,它首先检查请求是否是登录请求(通过检查请求路径是否为"/login"以及请求方法是否为"POST")。
    3. 如果是登录请求,它会调用validate方法来校验验证码。
    4. validate方法从请求中获取验证码,然后与会话中存储的验证码进行比对。如果验证码不存在、为空或不匹配,将抛出异常。
    5. 如果验证码校验失败,过滤器会捕获异常,并向响应中写入错误信息(以JSON格式)。
    6. 如果请求不是登录请求,过滤器不会进行验证码校验,直接让请求继续向下执行(通过调用filterChain.doFilter)。
    7. 如果登录请求成功通过验证码校验,代码会继续执行后续的过滤器或处理器。
    @Component
    public class ValidateCodeFilter extends OncePerRequestFilter {
        @Override
        protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
            // 登陆请求
            if ("/login".equals(httpServletRequest.getServletPath()) &&
                    "POST".equalsIgnoreCase(httpServletRequest.getMethod())){
                try {
                    validate(httpServletRequest);
                } catch (Exception exception) {
                    httpServletResponse.setCharacterEncoding("utf-8");
                    httpServletResponse.setContentType("application/json;charset=UTF-8");
                    PrintWriter writer = httpServletResponse.getWriter();
                    writer.write(JSON.toJSONString(Result.failure(exception.getMessage())));
                    writer.flush();
                    return;
                }
            }
            // 不是一个登录请求,不做校验 直接通过
            filterChain.doFilter(httpServletRequest, httpServletResponse);
        }
    
        private void validate(HttpServletRequest request) {
            String code = request.getParameter("code");
            if (StringUtils.isBlank(code)){
                throw new RuntimeException("验证码不能为空");
            }
            Object checkCode = request.getSession(false).getAttribute(ConfigConsts.IMAGE_CODE_SESSION);
            if (Objects.isNull(checkCode)) {
                throw new RuntimeException("验证码不存在");
            }
            if (!StringUtils.equalsIgnoreCase(code,checkCode.toString())) {
                throw new RuntimeException("验证码不匹配");
            }
            request.getSession(false).removeAttribute(ConfigConsts.IMAGE_CODE_SESSION);
        }
    }
    

    7、集成mysecurity

    集成Spring Security的安全配置类,用于Web应用的安全性设置。

    1. 通过@EnableWebSecurity@Configuration注解,启用并配置Spring Security。
    2. 使用@EnableGlobalMethodSecurity(prePostEnabled = true)来启用全局方法级别的安全性,允许使用例如@PreAuthorize@PostAuthorize等注解。
    3. 定义了一个名为MySecurityConfig的配置类,该类继承自WebSecurityConfigurerAdapter,用于定制安全性设置。
    4. 通过@Autowired注入了一个名为validateCodeFilter的验证码过滤器实例。
    5. configure(HttpSecurity http)方法中,对应用的安全性进行了详细配置:
      • 允许所有人访问/loginPage/getImgCode这两个路径,不进行任何安全检查。
      • 对所有其他请求,需要用户进行身份验证(即需要登录后才能访问)。
      • 在用户名和密码验证过滤器之前,添加了一个自定义的验证码过滤器(validateCodeFilter),用于在登录过程中校验验证码。

    这段代码的主要目的是增强Web应用的安全性,限制了只有经过身份验证的用户才能访问应用的受保护资源。

    @Configuration
    @EnableWebSecurity
    @EnableGlobalMethodSecurity(prePostEnabled = true)
    public class MySecurityConfig extends WebSecurityConfigurerAdapter {
        @Autowired
        private ValidateCodeFilter validateCodeFilter;
        
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests()
                    // 放过
                    .antMatchers("/loginPage", "/getImgCode").permitAll()
                    .anyRequest().authenticated()
                    .and()
                    // 过滤登录验证码
                    .addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class)
        }
    

    运行结果如下:


    image-20231127202658535.png

    相关文章

      网友评论

          本文标题:springboot实现验证码功能

          本文链接:https://www.haomeiwen.com/subject/mczawdtx.html