图文详解应用登陆验证码的多种实现方案

file

在本号的一系列Spring Security文章中,前后介绍了各类登陆验证及受权中的知识点,如:spring-security简介并与shiro对比、 formLogin模式登陆认证、动态数据登陆验证与权限分配、帐户屡次登陆失败锁定、RememberMe记住我功能,等等文章。笔者以为以上的这些实际上都很简单,咱们没有涉及到分布式应用。本节将以分布式的应用背景,讲解验证码实现的多种方式。本小节先从理论的角度为你们讲解,具体实现笔者还会再写。前端

  • session存储验证码,不适用于分布式应用
  • 共享session存储验证码,适用于分布式应用
  • 基于对称算法的验证码,适用于分布式应用

1、验证码的组成部分

验证码实际上和谜语有点像,分为谜面和谜底。谜面一般是图片,谜底一般为文字。谜面用于展示,谜底用于校验。nginx

  • 对于字符型验证码。好比:谜面是显示字符串"ABGH"的图片,谜底是字符串"ABGH"
  • 对于计算类验证码。好比:谜面是“1+1=”的图片,谜底是“2”
  • 对于拖拽类的验证码。好比:谜面是一个拖拽式的拼图,谜底是拼图位置的坐标

总之,无论什么形式的谜面,最后用户的输入内容要和谜底进行验证。redis

2、session存储验证码

图中蓝色为服务端、澄粉色为客户端。算法

file

这是一种最典型的验证码实现方式,实现方式也比较简单。spring

  • 应用服务端随机的生成验证码文字
  • 将验证码文字存到session里面
  • 根据验证码文字生成验证码图片,响应给客户端
  • 检查用户输入的内容与验证码谜底是否一致

这种实现方式的优势就是比较简单,缺点就是:由于一套应用部署一个session,当咱们把应用部署多套如:A、B、C,他们各自有一个session而且不共享。致使的结果就是验证码和图片由A生成,可是验证请求发送到了B,这样就不可能验证经过。数据库

3、共享session存储验证码

在第二小节讲到的问题,实际上不是验证码的问题,而是如何保证session惟一性或共享性的问题。主要的解决方案有两种:segmentfault

file

  • 一般咱们实现负载均衡应用的前端都是使用nginx或者haproxy,两者均可以配置负载均衡策略。其中一种策略就是:你的客户端ip上一次请求的是A应用,你的下一次请求还转发给A应用。这样就保证了session的惟一性。可是这种方式有可能会致使A、B、C应用其中一个或两个分配了大量的请求,而另一个处理不多的请求,致使负载并不均衡。
  • 另一种很是通用的方式就是将分布式应用的session统一管理,也就是说原来A、B、C各自的session都存在本身的内存中,如今更改成统一存储到一个地方,你们一块儿用。这样就实现了session的惟一和共享,是实现分布式应用session管理的有效途径。在Spring框架内,最成熟的解决方案就是spring session + redis 。可自行参考实现。

4、基于对称算法的验证码

可能出于主机资源的考虑,可能出于系统架构的考量,有些应用是无状态的。安全

  • 什么是无状态应用:就是不保存用户状态的应用。
  • 什么是用户状态:好比当你登录以后,在session中保存的用户的名称、组织等等信息。
  • 因此能够简单的理解,无状态应用就是无session应用。固然这并不彻底准确。

那么对于这些无状态的应用,咱们就没法使用session,或者换个说法从团队开发规范上就不让使用session。那么咱们的验证码该怎么作?springboot

file

  • 一样,首先要生成随机的验证码(谜底),可是不作任何存储操做
  • 将谜底(验证码文字)加上时间串、应用信息等组成一个字符串进行加密。必须是对称加密,也就是说能够解密的加密算法。
  • 生成验证码图片,并与加密后的密文,经过cookies一并返回给客户端。
  • 当用户输入验证码提交登陆以后,服务端解密cookies中的密文(主要是验证码文字),与用户的输入进行验证比对。

这种作法的缺陷是显而易见的:实际上就是将验证码文字在客户端服务端之间走了一遍。虽然是加密后的验证码文字,可是有加密就必须有解密,不然没法验证。因此更为稳妥的作法是为每个用户生成密钥,并将密钥保存到数据库里面,在对应的阶段内调用密钥进行加密或者解密。cookie

从密码学的角度讲,没有一种对称的加密算法是绝对安全的。因此更重要的是保护好你的密钥。正如没有一把锁头是绝对安全的,更重要的是保护好你的钥匙。

期待您的关注

相关文章
相关标签/搜索