美文网首页
Springboot整合Shiro:集成Kaptcha验证码

Springboot整合Shiro:集成Kaptcha验证码

作者: 张小黑的猫 | 来源:发表于2019-05-28 18:49 被阅读0次

    接上一篇博客 > Springboot整合Shiro:MD5加密方式
    效果图:

    kaptcha.gif

    (1)pom.xml引入依赖

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

    (2)创建KaptchaConfig.java配置类

    package com.demo.shirodemo.shiro;
    
    /**
     * @Description
     * @Author 张小黑的猫
     * @data 2019-05-28 13:59
     */
    
    import com.google.code.kaptcha.impl.DefaultKaptcha;
    import com.google.code.kaptcha.util.Config;
    import org.springframework.context.annotation.Bean;
    import org.springframework.stereotype.Component;
    
    import java.util.Properties;
    
    @Component
    public class KaptchaConfig {
    
        private final static String CODE_LENGTH = "4";
        private final static String SESSION_KEY = "verification_session_key";
    
        @Bean
        public DefaultKaptcha defaultKaptcha() {
            DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
            Properties properties = new Properties();
            // 设置边框
            properties.setProperty("kaptcha.border", "no");
            // 设置边框颜色
            properties.setProperty("kaptcha.border.color", "105,179,90");
            // 设置字体颜色
            properties.setProperty("kaptcha.textproducer.font.color", "blue");
            // 设置图片宽度
            properties.setProperty("kaptcha.image.width", "173");
            // 设置图片高度
            properties.setProperty("kaptcha.image.height", "40");
            // 设置字体尺寸
            properties.setProperty("kaptcha.textproducer.font.size", "32");
            // 设置图片样式
            properties.setProperty("kaptcha.obscurificator.impl","com.google.code.kaptcha.impl.ShadowGimpy");
            // 设置session key
            properties.setProperty("kaptcha.session.key", SESSION_KEY);
            // 设置验证码长度
            properties.setProperty("kaptcha.textproducer.char.length", CODE_LENGTH);
            // 设置字体
            properties.setProperty("kaptcha.textproducer.font.names", "宋体,楷体,黑体");
            Config config = new Config(properties);
            defaultKaptcha.setConfig(config);
            return defaultKaptcha;
        }
    }
    
    

    (3)LoginController添加获取验证码的方法:

     /**
         * 获取验证码
         * @param response
         */
        @GetMapping("/getCode")
        public void getGifCode(HttpServletResponse response, HttpServletRequest request) throws IOException {
            byte[] verByte = null;
            ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream();
            try {
                //生产验证码字符串并保存到session中
                String createText = defaultKaptcha.createText();
                request.getSession().setAttribute(SHIRO_VERIFY_SESSION,createText);
                //使用生产的验证码字符串返回一个BufferedImage对象并转为byte写入到byte数组中
                BufferedImage challenge = defaultKaptcha.createImage(createText);
                ImageIO.write(challenge,"jpg",jpegOutputStream);
            } catch (IllegalArgumentException e){
                response.sendError(HttpServletResponse.SC_NOT_FOUND);
                return;
            } catch (IOException e){
                e.printStackTrace();
            }
            //定义response输出类型为image/jpeg类型,使用response输出流输出图片的byte数组
            verByte = jpegOutputStream.toByteArray();
            response.setHeader("Cache-Control", "no-store");
            response.setHeader("Pragma", "no-cache");
            response.setDateHeader("Expires", 0);
            response.setContentType("image/jpeg");
            ServletOutputStream responseOutputStream = response.getOutputStream();
            responseOutputStream.write(verByte);
            responseOutputStream.flush();
            responseOutputStream.close();
        }
    

    (4)更改login.html

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>Login</title>
    </head>
    <body>
    <form action="/login" method="post">
        <span th:text="${msg}" style="color: red"></span><br>
        用户名:<input type="text" name="username"><br>
        密&emsp;码:<input type="password" name="password"><br>
        验证码:<input type="text" name="verifyCode" placeholder="请输入验证码"><br>
        <a href="#" style="color: blue" onclick="refreshCode()">换一个</a>
        <img id="verifyCode" src="/getCode" style="margin-left: 16px"><br>
        <input type="checkbox" name="rememberMe">记住我<br>
        <input type="submit" value="Login">
    </form>
    <script>
        function refreshCode() {
            document.getElementById("verifyCode").setAttribute("src","/getCode");
        }
    </script>
    </body>
    </html>
    

    (5)在ShiroConfig中配置/getCode可以游客方式访问

     filterChainMap.put("/getCode","anon");
    

    (6)修改登录方法

    @PostMapping("/login")
        public String login(String username, String password,String verifyCode, boolean rememberMe, Model model) {
    
            UsernamePasswordToken token = new UsernamePasswordToken(username, password);
            Subject currentUser = SecurityUtils.getSubject();
    
            // 获取session中的验证码
            String verCode = (String) currentUser.getSession().getAttribute(SHIRO_VERIFY_SESSION);
            if("".equals(verifyCode)||(!verCode.equals(verifyCode))){
                model.addAttribute("msg",ERROR_KAPTCHA);
                return ERROR_CODE_URL;
            }
            try {
                //主体提交登录请求到SecurityManager
                token.setRememberMe(rememberMe);
                currentUser.login(token);
            } catch (IncorrectCredentialsException ice) {
                model.addAttribute("msg", ERROR_PASSWORD);
            } catch (UnknownAccountException uae) {
                model.addAttribute("msg", ERROR_ACCOUNT);
            } catch (AuthenticationException ae) {
                model.addAttribute("msg", ERROR_STATUS);
            }
            if (currentUser.isAuthenticated()) {
                model.addAttribute("username", username);
                return SUCCESS_CODE_URL;
            } else {
                token.clear();
                return ERROR_CODE_URL;
            }
        }
    

    附:LoginController.java

    package com.demo.shirodemo.controller;
    
    import com.demo.shirodemo.shiro.User;
    import com.google.code.kaptcha.impl.DefaultKaptcha;
    import org.apache.shiro.SecurityUtils;
    import org.apache.shiro.authc.AuthenticationException;
    import org.apache.shiro.authc.IncorrectCredentialsException;
    import org.apache.shiro.authc.UnknownAccountException;
    import org.apache.shiro.authc.UsernamePasswordToken;
    import org.apache.shiro.subject.Subject;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PostMapping;
    
    import javax.imageio.ImageIO;
    import javax.servlet.ServletOutputStream;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.awt.image.BufferedImage;
    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    
    /**
     * @Description 登录
     * @Author 张小黑的猫
     * @data 2019-05-22 18:17
     */
    @Controller
    public class LoginController {
    
        /**
         * session中的验证码
         */
        private String SHIRO_VERIFY_SESSION = "verifySessionCode";
        /**
         * 错误后的跳转地址
         */
        private String ERROR_CODE_URL = "login";
        /**
         * 成功后的跳转地址
         */
        private String SUCCESS_CODE_URL = "/success";
        /**
         * 验证失败提示
         */
        private String ERROR_PASSWORD = "密码不正确";
        private String ERROR_ACCOUNT = "账户不存在";
        private String ERROR_STATUS = "状态不正常";
        private String ERROR_KAPTCHA = "验证码不正确";
    
        @Autowired
        private DefaultKaptcha defaultKaptcha;
    
        @GetMapping("/login")
        public String login() {
            return ERROR_CODE_URL;
        }
    
        @GetMapping({"/","/success"})
        public String success(Model model){
            Subject currentUser = SecurityUtils.getSubject();
            User user = (User) currentUser.getPrincipal();
            model.addAttribute("username", user.getUsername());
            return "success";
        }
    
        @GetMapping("/403")
        public String page_403() {
            return "403";
        }
    
    
        @PostMapping("/login")
        public String login(String username, String password,String verifyCode, boolean rememberMe, Model model) {
    
            UsernamePasswordToken token = new UsernamePasswordToken(username, password);
            Subject currentUser = SecurityUtils.getSubject();
    
            // 获取session中的验证码
            String verCode = (String) currentUser.getSession().getAttribute(SHIRO_VERIFY_SESSION);
            if("".equals(verifyCode)||(!verCode.equals(verifyCode))){
                model.addAttribute("msg",ERROR_KAPTCHA);
                return ERROR_CODE_URL;
            }
            try {
                //主体提交登录请求到SecurityManager
                token.setRememberMe(rememberMe);
                currentUser.login(token);
            } catch (IncorrectCredentialsException ice) {
                model.addAttribute("msg", ERROR_PASSWORD);
            } catch (UnknownAccountException uae) {
                model.addAttribute("msg", ERROR_ACCOUNT);
            } catch (AuthenticationException ae) {
                model.addAttribute("msg", ERROR_STATUS);
            }
            if (currentUser.isAuthenticated()) {
                model.addAttribute("username", username);
                return SUCCESS_CODE_URL;
            } else {
                token.clear();
                return ERROR_CODE_URL;
            }
        }
    
        /**
         * 获取验证码
         * @param response
         */
        @GetMapping("/getCode")
        public void getGifCode(HttpServletResponse response, HttpServletRequest request) throws IOException {
            byte[] verByte = null;
            ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream();
            try {
                //生产验证码字符串并保存到session中
                String createText = defaultKaptcha.createText();
                request.getSession().setAttribute(SHIRO_VERIFY_SESSION,createText);
                //使用生产的验证码字符串返回一个BufferedImage对象并转为byte写入到byte数组中
                BufferedImage challenge = defaultKaptcha.createImage(createText);
                ImageIO.write(challenge,"jpg",jpegOutputStream);
            } catch (IllegalArgumentException e){
                response.sendError(HttpServletResponse.SC_NOT_FOUND);
                return;
            } catch (IOException e){
                e.printStackTrace();
            }
            //定义response输出类型为image/jpeg类型,使用response输出流输出图片的byte数组
            verByte = jpegOutputStream.toByteArray();
            response.setHeader("Cache-Control", "no-store");
            response.setHeader("Pragma", "no-cache");
            response.setDateHeader("Expires", 0);
            response.setContentType("image/jpeg");
            ServletOutputStream responseOutputStream = response.getOutputStream();
            responseOutputStream.write(verByte);
            responseOutputStream.flush();
            responseOutputStream.close();
        }
    
    }
    

    OK!完成~~~
    共同学习,欢迎指正修改~ 喵喵喵❤

    相关文章

      网友评论

          本文标题:Springboot整合Shiro:集成Kaptcha验证码

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