zoukankan      html  css  js  c++  java
  • Spring Boot Shiro权限管理--自定义 FormAuthenticationFilter验证码整合

    思路
    shiro使用FormAuthenticationFilter进行表单认证,验证校验的功能应该加在FormAuthenticationFilter中,在认证之前进行验证码校验。

    需要写FormAuthenticationFilter的子类,继承FormAuthenticationFilter,改写它的认证方法,在认证之前进行验证码校验。

    自定义FormAuthenticationFilter

    package com.example.config.shiro;
    
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpSession;
    
    import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
    
    public class CustomFormAuthenticationFilter extends FormAuthenticationFilter{
        @Override  
        protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {  
            // 在这里进行验证码的校验  
            HttpServletRequest httpServletRequest = (HttpServletRequest) request;  
            HttpSession session = httpServletRequest.getSession();  
      
            // 取出验证码  
            String validateCode = (String) session.getAttribute("validateCode");  
            // 取出页面的验证码  
            // 输入的验证和session中的验证进行对比  
            String randomcode = httpServletRequest.getParameter("randomcode");  
            if (randomcode != null && validateCode != null && !randomcode.equals(validateCode)) {  
                // 如果校验失败,将验证码错误失败信息,通过shiroLoginFailure设置到request中  
                httpServletRequest.setAttribute("shiroLoginFailure", "kaptchaValidateFailed");//自定义登录异常  
                // 拒绝访问,不再校验账号和密码  
                return true;  
            }  
            return super.onAccessDenied(request, response);  
        }  
    }

    在ShiroConfiguration.java中的shiroFilter方法注入自定义FormAuthenticationFilter

    @Bean
        public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
            System.out.println("ShiroConfiguration.shiroFilter()");
            ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
            
            Map<String, Filter> filters = shiroFilterFactoryBean.getFilters();//获取filters
            filters.put("authc", new CustomFormAuthenticationFilter());//将自定义 的FormAuthenticationFilter注入shiroFilter中  
            // 必须设置SecuritManager
            shiroFilterFactoryBean.setSecurityManager(securityManager);
    
            // 拦截器
            Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
    
            // 配置退出过滤器,其中的具体代码Shiro已经替我们实现了
            filterChainDefinitionMap.put("/logout", "logout");
            //验证码可以匿名访问
            filterChainDefinitionMap.put("/validatecodeServlet", "anon");
            
            //配置记住我或认证通过可以访问的地址
    
            filterChainDefinitionMap.put("/index", "user");
            filterChainDefinitionMap.put("/", "user");
            
            // <!-- 过滤链定义,从上向下顺序执行,一般将 /**放在最为下边 -->:这是一个坑呢,一不小心代码就不好使了;
            // <!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
            
            filterChainDefinitionMap.put("/**", "authc");
    
            // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
            shiroFilterFactoryBean.setLoginUrl("/login");
            // 登录成功后要跳转的链接
            shiroFilterFactoryBean.setSuccessUrl("/index");
            // 未授权界面;
            shiroFilterFactoryBean.setUnauthorizedUrl("/403");
            
            shiroFilterFactoryBean
                    .setFilterChainDefinitionMap(filterChainDefinitionMap);
            return shiroFilterFactoryBean;
    
        }

    ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();

    Map<String, Filter> filters = shiroFilterFactoryBean.getFilters();//获取filters
    filters.put("authc", new CustomFormAuthenticationFilter());//将自定义 的FormAuthenticationFilter注入shiroFilter中  

     登录方法加入自定义的异常kaptchaValidateFailed

    @RequestMapping(value = "/login", method = RequestMethod.POST)  
        public String login(HttpServletRequest request, Map<String, Object> map) {  
            System.out.println("HomeController.login");  
            // 登录失败从request中获取shiro处理的异常信息  
            // shiroLoginFailure:就是shiro异常类的全类名  
            String exception = (String) request.getAttribute("shiroLoginFailure");  
            String msg = "";  
            if (exception != null) {  
                if (UnknownAccountException.class.getName().equals(exception)) {  
                    System.out.println("UnknownAccountException -->帐号不存在:");  
                    msg = "UnknownAccountException -->帐号不存在:";  
                } else if (IncorrectCredentialsException.class.getName().equals(exception)) {  
                    System.out.println("IncorrectCredentialsException -- > 密码不正确:");  
                    msg = "IncorrectCredentialsException -- > 密码不正确:";  
                } else if ("kaptchaValidateFailed".equals(exception)) {  
                    System.out.println("kaptchaValidateFailed -- > 验证码错误");  
                    msg = "kaptchaValidateFailed -- > 验证码错误";  
                } else {  
                    msg = "else >> " + exception;  
                    System.out.println("else -- >" + exception);  
                }  
            }  
            map.put("msg", msg);  
            // 此方法不处理登录成功,由shiro进行处理.  
            return "/login";  
        }  

    login.html

    <!DOCTYPE html>  
    <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
          xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
    <head>  
    <meta charset="UTF-8" />  
    <title>Insert title here</title>  
    </head>  
    <body>  
                错误信息:<h4 th:text="${msg}"></h4>  
           <form action="" method="post">  
               <p>账号:<input type="text" name="username" value="admin"/></p>  
               <p>密码:<input type="text" name="password" value="123456"/></p>  
               <p>验证码:<input type="text" name="randomcode"/>
               <img th:src="@{/validatecodeServlet}" height="20px" width="60px" onclick="random(this)"/></p> 
               <P><input type="checkbox" name="rememberMe" />记住我</P> 
               <p><input type="submit" value="登录"/></p>  
           </form>  
           <script th:inline="javascript">
              function random(tmp){
                   tmp.src="/validatecodeServlet?rnd="+Math.random();
              }
           </script>
    </body>  
    </html> 

    验证码Servlet

    package com.example.servlet;
    
    import java.awt.Color;
    import java.awt.Font;
    import java.awt.Graphics;
    import java.awt.image.BufferedImage;
    import java.io.IOException;
    import java.io.OutputStream;
    import java.util.Random;
    
    import javax.imageio.ImageIO;
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpSession;
    
    
    @WebServlet(urlPatterns="/validatecodeServlet")
    public class ValidatecodeServlet extends HttpServlet{
         /**
         * 
         */
        private static final long serialVersionUID = 1L;
    
        @Override  
            protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {  
                System.out.println(">>>>>>>>>>doGet()<<<<<<<<<<<");  
                doPost(req, resp);  
            }  
          
            @Override  
            protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {  
                System.out.println(">>>>>>>>>>doPost()<<<<<<<<<<<");  
                int width = 60;
                int height = 32;
                //create the image
                BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
                Graphics g = image.getGraphics();
                // set the background color
                g.setColor(new Color(0xDCDCDC));
                g.fillRect(0, 0, width, height);
                // draw the border
                g.setColor(Color.black);
                g.drawRect(0, 0, width - 1, height - 1);
                // create a random instance to generate the codes
                Random rdm = new Random();
                String hash1 = Integer.toHexString(rdm.nextInt());
                System.out.print(hash1);
                // make some confusion
                for (int i = 0; i < 50; i++) {
                    int x = rdm.nextInt(width);
                    int y = rdm.nextInt(height);
                    g.drawOval(x, y, 0, 0);
                }
                // generate a random code
                String capstr = hash1.substring(0, 4);
                HttpSession session = req.getSession(true);
                //将生成的验证码存入session
                session.setAttribute("validateCode", capstr);
                g.setColor(new Color(0, 100, 0));
                g.setFont(new Font("Candara", Font.BOLD, 24));
                g.drawString(capstr, 8, 24);
                g.dispose();
                //输出图片
                resp.setContentType("image/jpeg");
                OutputStream strm = resp.getOutputStream();
                ImageIO.write(image, "jpeg", strm);
                strm.close();   
               
            }  
    }

    Application.java

    package com.example;  
      
    import org.springframework.boot.SpringApplication;  
    import org.springframework.boot.autoconfigure.SpringBootApplication;  
    import org.springframework.boot.web.servlet.ServletComponentScan;
    @ServletComponentScan 
    @SpringBootApplication  
    public class Application {  
         public static void main(String[] args) {  
            SpringApplication.run(Application.class, args);  
        }  
    } 

     

  • 相关阅读:
    如何使用Python的Django框架创建自己的网站
    AJPFX总结内部类
    AJPFX总结OpenJDK 和 HashMap大量数据处理时,避免垃圾回收延迟的技巧二
    AJPFX总结OpenJDK 和 HashMap大量数据处理时,避免垃圾回收延迟的技巧一
    AJPFX总结面向对象(this和super的区别和应用)
    AJPFX关于读取properties 配置文件 返回属性值
    AJPFX关于java中的方法
    AJPFX关于表结构的相关语句
    AJPFX关于Swing组件的总结
    AJPFX:不用递归巧妙求出1000的阶乘所有零和尾部零的个数
  • 原文地址:https://www.cnblogs.com/but009/p/7568007.html
Copyright © 2011-2022 走看看