Spring Security深入浅出--3、记住我实现和源码分析以及实现图片验证码功能

目录

 

实现图片验证码功能

代码重构

记住我

记住我基本原理

代码实现

 记住我源码分析

登陆

服务重新启动


实现图片验证码功能

开发生成图片验证码接口

用来封装image图片


public class ImageCode extends ValidateCode {
	
	private BufferedImage image; 
	
	public ImageCode(BufferedImage image, String code, int expireIn){
		super(code, expireIn);
		this.image = image;
	}
	
	public ImageCode(BufferedImage image, String code, LocalDateTime expireTime){
		super(code, expireTime);
		this.image = image;
	}
	
	public BufferedImage getImage() {
		return image;
	}

	public void setImage(BufferedImage image) {
		this.image = image;
	}

}

将生成的图片放入到session里面

生成图形验证码

	/**
	 * 系统配置
	 */
	@Autowired
	private SecurityProperties securityProperties;
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.imooc.security.core.validate.code.ValidateCodeGenerator#generate(org.
	 * springframework.web.context.request.ServletWebRequest)
	 */
	@Override
	public ImageCode generate(ServletWebRequest request) {
		int width = ServletRequestUtils.getIntParameter(request.getRequest(), "width",
				securityProperties.getCode().getImage().getWidth());
		int height = ServletRequestUtils.getIntParameter(request.getRequest(), "height",
				securityProperties.getCode().getImage().getHeight());
		//生成图片对象
		BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
		//生成图片对象



		Graphics g = image.getGraphics();


		//生成干扰条纹
		Random random = new Random();

		g.setColor(getRandColor(200, 250));
		g.fillRect(0, 0, width, height);
		g.setFont(new Font("Times New Roman", Font.ITALIC, 20));
		g.setColor(getRandColor(160, 200));
		for (int i = 0; i < 155; i++) {
			int x = random.nextInt(width);
			int y = random.nextInt(height);
			int xl = random.nextInt(12);
			int yl = random.nextInt(12);
			g.drawLine(x, y, x + xl, y + yl);
		}
		//生成干扰条纹

		//生成四位随机数
		String sRand = "";
		for (int i = 0; i < securityProperties.getCode().getImage().getLength(); i++) {  //securityProperties.getCode().getImage().getLength()  生成条形码的长度
			String rand = String.valueOf(random.nextInt(10));
			sRand += rand;
			g.setColor(new Color(20 + random.nextInt(110), 20 + random.nextInt(110), 20 + random.nextInt(110)));
			g.drawString(rand, 13 * i + 6, 16);
		}
		//生成四位随机数


		g.dispose();

		return new ImageCode(image, sRand, securityProperties.getCode().getImage().getExpireIn());  //securityProperties.getCode().getImage().getExpireIn()过期时间
	}
	
	/**
	 * 生成随机背景条纹
	 * 
	 * @param fc
	 * @param bc
	 * @return
	 */
	private Color getRandColor(int fc, int bc) {
		Random random = new Random();
		if (fc > 255) {
			fc = 255;
		}
		if (bc > 255) {
			bc = 255;
		}
		int r = fc + random.nextInt(bc - fc);
		int g = fc + random.nextInt(bc - fc);
		int b = fc + random.nextInt(bc - fc);
		return new Color(r, g, b);
	}

	public SecurityProperties getSecurityProperties() {
	return securityProperties;
}

	public void setSecurityProperties(SecurityProperties securityProperties) {
		this.securityProperties = securityProperties;
	}

将该请求加入到安全配置里面

启动之后

当图片验证码发送给security框架之后,我们需要手动写security过滤器来处理图形验证码

创建过滤类ValidateCodeFilter继承OncePerRequestFilter(使得只过滤一次)

将自己写的过滤器加入的security过滤器链中

运行

代码重构

验证码基本参数可配置

首先配置core项目中的属性ImageCodeProperties

创建ValidateCodeProperties来封装各个属性类型(后期还会有短信验证)

 

进入到demo项目中写应用级的配置

请求级的配置

core项目中的ValidateCodeController对象

启动项目指挥,请求里面的width会覆盖配置里面的width,配置里面的width会覆盖默认的width

验证码拦截的接口可配置

 将url进行统一处理

这样的话,直接访问user  user/*的路径都会被拦截下来,并且返回报错信息

验证码的生成逻辑可配置

其实ImageCodeGenerator类也可以 @component注解直接注入,但是通过配置类注解来来创建实现,这样的话可以通过@ConditionalOnMissingBean进行判断是否bean里面已经存在一个相同的bean

如果在其他地方又注入了它的话,这个时候上面的imageCodeGenerator就会失效

记住我

记住我基本原理

浏览器发送认证请求给后台,当UsernamePasswordAuthenticationFilter认证成功之后通过RemenberMeService将token信息保存到TokenRepositoty以及数据库中,然后将token写入到浏览器Cookie中;

当浏览器过了几天再次发送服务请求的时候,直接被RemenberMeAuthenticationFilter拦截下来,读取Cookie中的token,在调用RemeberMeService去数据库查找Token,调用UserDetailsService完成认证。

RememberMeAuthenticationFilter过滤器一般都在自定义过滤器的末尾,当前面的认证都不可行的时候,就尝试的调用它

代码实现

创建persistentTokenRepository的bean,用来调用数据库验证使用的。tokenRepository.setCreateTableOnStartup(true)方法的目的是第一次初始化的时候,在数据库创建对象的表来存放token。

配置过期时间

调用userDetailsService

 

总体逻辑就是调用persistenTokenRepository()方法,去数据库去或者存放对应的token,设置过期时间,然后调用userDetailsService验证加载用户信息。

 记住我源码分析

登陆

 进入到UsernamePasswordAuthenticationFilter类中

认证成功之后,进入到AbstractAuthenticationProcessingFilter方法中

 

 调用rememberMeServices

 

调用tokenRepository向数据库添加新的token

addCookie()的方法就是将token写到浏览器cookie里面

 

 

服务重新启动

判断前面的认证是否认证成功,如果没有认证成功就进入if语句

 

 

 

通过tokenSeries去数据库拿token的值 ,然后就是做token的相关检查

然后就是调用userDetailsService,去获取用户信息

 

 认证成功之后,将认证信息保存到session里面

发布了471 篇原创文章 · 获赞 97 · 访问量 16万+

猜你喜欢

转载自blog.csdn.net/qq_37909508/article/details/104028777