Spring Boot Shiro权限管理--自定义 FormAuthenticationFilter验证码整合

转载 2016年08月29日 23:25:44
验证码

思路
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);  
    }  
} 




使用shiro的的表单过滤器重写shiro默认的认证规则来实现先验证验证码再验证登录所遇到的问题

我之前写过一篇用shiro实现登录认证的博文,今天就是在这基础上做出修改而成。由于对shiro认识不够深入,折腾了很久,今天主要就是对遇到的问题做出点小总结。 首先我先给出shiro的配置文件: ...

Spring Boot 结合shiro做第三方登录验证

Spring Boot 结合shiro做第三方登录验证1、首先,说一下我的具体实现思路。在做spring boot拦截器的过程中,开始我准备用spring security来实现,但是研究了一段时间之...
  • he1lo
  • he1lo
  • 2016年08月18日 19:47
  • 5283

Spring Boot整合jpa,Shiro进行权限管理

转:http://412887952-qq-com.iteye.com/blog/2299777 本来想写一篇spring boot整合Shiro实现权限验证的文章,发现这篇写的非常不错,就直接...

转载:Spring Boot (十四):springboot整合shiro-登录认证和权限管理

这篇文章我们来学习如何使用Spring Boot集成Apache Shiro。安全应该是互联网公司的一道生命线,几乎任何的公司都会涉及到这方面的需求。在Java领域一般有Spring Security...

Spring Boot Shiro 权限管理

本来是打算接着写关于数据库方面,集成MyBatis的,刚好赶上朋友问到Shiro权限管理,就先总结下发出来了。使用Shiro之前用在Spring MVC中,是通过XML文件进行配置。 既然现在在写S...
  • lsy0903
  • lsy0903
  • 2016年10月24日 13:07
  • 753

spring boot后台管理系统,shiro权限管理, restful风格的接口

随着spring boot的出现,java又上升了一个层次,以往tomcat部署war的形式也改变了,现在可以直接一个jar包、一行命令,真正实现一次编译随处运行的理念了。 该boot-backend...

spring security 4.1添加验证码和动态权限管理

本来想一步一步逐步深入的,可惜突然有了其他的事情,只能把一些高级功能一次性演示出来添加验证码的方式在网上有很多相关的文章,我这里采用的方式是替换标准过滤器链里的UsernamePasswordAuth...

Shiro登录机制验证,自定义FormAuthenticationFilter

自定义登录form拦截器:org.apache.shiro.web.filter.authc.FormAuthenticationFilter 问题描述 使用shiro进行系统...

39.3 Spring Boot Shiro权限管理【从零开始学Spring Boot】

相对于上一小节这个就比较简单了。 主要分这么几个步骤:在pom.xml中加入缓存依赖;注入缓存; (a) 在pom.xml文件中加入依赖: ehcache -->        depend...

(39.1) Spring Boot Shiro权限管理【从零开始学Spring Boot】

(本节提供源代码,在最下面可以下载)距上一个章节过了二个星期了,最近时间也是比较紧,一直没有时间可以写博客,今天难得有点时间,就说说Spring Boot如何集成Shiro吧。这个章节会比较复杂,牵涉...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Spring Boot Shiro权限管理--自定义 FormAuthenticationFilter验证码整合
举报原因:
原因补充:

(最多只允许输入30个字)