六、Spring Security认证和授权-实现自定义短信验证码登陆功能

一、图片验证码验证流程回顾

上期已经实现了图片验证码的功能,我们来回顾一下大概流程:
1、 客户端生成一个唯一标识,然后发起图片验证码请求,请求路径中携带这个唯一标识,例如:http://localhost:8066/auth/code/image/039988e0-1994-11eb-8a54-abdddf75aa45
2、 服务端接收到获取验证码请求,读取请求路径中的唯一标识(例如:039988e0-1994-11eb-8a54-abdddf75aa45);生成4位随机数作为验证码,合成验证码图片(创建验证码);使用Redis存储验证码,唯一标识为key,验证码为value(存储验证码);将验证码图片返回给客户端(发送验证码);
3、 用户填写登录信息和验证码信息,提交登录表单,携带唯一标识。
4、 服务端拦截器拦截登录请求,获取唯一标识;读取Redis中的数据与用户输入的验证码比较,相同则放行,不同则抛出异常,用户登录失败;
5、 验证码校验通过后进入Spring Security拦截器,执行表单登录认证流程。

二、短信验证码实现与原理分析

六、Spring Security认证和授权-实现自定义短信验证码登陆功能
今天我们要实现短信登录功能,大概流程和图片验证码类似:
六、Spring Security认证和授权-实现自定义短信验证码登陆功能
六、Spring Security认证和授权-实现自定义短信验证码登陆功能

1、 客户端生成一个唯一标识,用户输入手机号码,然后发起获取短信验证码请求,请求路径中携带这个唯一标识和手机号码,例如:http://localhost:8066/auth/code/sms/35eb6df0-19a2-11eb-8cb2-9f448bedcdca?phone=18888888888&deviceId=35eb6df0-19a2-11eb-8cb2-9f448bedcdca
2、 服务端接收到获取验证码请求,读取请求路径中的唯一标识(例如:039988e0-1994-11eb-8a54-abdddf75aa45);校验手机号码是否存在,不存在则抛出异常,存在则生成6位随机数作为验证码 (创建验证码);使用Redis存储验证码,唯一标识为key,验证码为value(存储验证码);调用发送短息功能,向用户手机号码发送验证码 (发送验证码);
3、 用户手机收到验证码后,填写验证码信息,提交登录请求,携带唯一标识。
4、 服务端拦截器拦截登录请求,获取唯一标识;读取Redis中的数据与用户输入的验证码比较,相同则放行,不同则抛出异常,用户登录失败;
5、 验证码校验通过后进入Spring Security拦截器,执行手机号码登录认证流程。

三、比较图片验证码和短信验证码的异同比较

两种验证方式的模式的相同的,都是获取验证码、校验验证码。值得注意的是,不同点主要在第5条,进入Spring Security拦截器,是被不同的拦截器拦截认证的。图片验证码是被UsernamePasswordAuthenticationFilter拦截认证,这个是Spring Security自带的拦截器;短信验证码需要自定义拦截器,我们基于对UsernamePasswordAuthenticationFilter拦截器的理解,来实现自定义的手机号码登录拦截认证逻辑。

四、 短信验证码功能实现

由于上期的图形验证码验证流程已经定义好了验证码获取统一入口、验证码处理器接口ValidateCodeProcessor及其抽象类AbstractValidateCodeProcessor,还有基于redis的验证码存取器,此处不再赘述,不清楚的同学可以翻看上篇课程哦。
1、 短信验证码生成器SmsCodeGenerator实现ValidateCodeGenerator接口:
六、Spring Security认证和授权-实现自定义短信验证码登陆功能

2、 定义短信验证码发送器接口SmsCodeSender及默认实现类:
六、Spring Security认证和授权-实现自定义短信验证码登陆功能
六、Spring Security认证和授权-实现自定义短信验证码登陆功能

3、 配置默认的短讯发送器,默认短信发送器是因为我们没有接入短信发送功能,发送短信可以购买各大厂商的短信发送业务,有兴趣的同学可以尝试;由于使用了@ConditionalOnMissingBean(SmsCodeSender.class)注解,当容器中不存在SmsCodeSender的bean时才会加载默认发送器,所以小伙伴们可以自定义短信发送器实现SmsCodeSender接口,加入到容器中就可以覆盖默认的发送器:
六、Spring Security认证和授权-实现自定义短信验证码登陆功能

4、 短信验证码处理器SmsCodeProcessor继承AbstractValidateCodeProcessor,重写send()方法,调用短信发送器,实现短信发送功能(此处为了方便测试登录,直接将验证码放在返回提示信息中返回了,这点很不安全哦,生产上可不能这么玩,否则只要输入正确的手机号码,用户就能在客户端看到验证码了哦!):
六、Spring Security认证和授权-实现自定义短信验证码登陆功能

5、 到此,短息验证码生成和校验功能已经实现,下面需要模仿UsernamePasswordAuthenticationFilter功能实现手机号码登录认证流程。
6、 定义短信登录验证信息封装类SmsCodeAuthenticationToken继承AbstractAuthenticationToken,定义两个重要的构造方法,接收手机号码认证信息,一个参数的表示未认证,两个参数的表示已认证,分别会调用父类的方法进行设置:
六、Spring Security认证和授权-实现自定义短信验证码登陆功能

7、 定义短信登录验证逻辑SmsCodeAuthenticationProvider,由于短信验证码的验证在过滤器里已完成,这里直接读取用户信息即可。Authenticate()根据手机号码查询用户信息,并创建一个已授权的SmsCodeAuthenticationToken。Supports()方法会被AuthenticationManager调用,来判断是否支持指定token。

六、Spring Security认证和授权-实现自定义短信验证码登陆功能
六、Spring Security认证和授权-实现自定义短信验证码登陆功能

8、 自定义短信登录拦截器SmsCodeAuthenticationFilter实现抽象类AbstractAuthenticationProcessingFilter,主要方法为attemptAuthentication(),会用请求参数中的手机号码生成一个未认证的SmsCodeAuthenticationToken,然后使用AuthenticationManager匹配到SmsCodeAuthenticationProvider对手机号码认证。
六、Spring Security认证和授权-实现自定义短信验证码登陆功能

9、 认证成功后将会把认证成功信息放进SecurityContext完成整个认证流程。
六、Spring Security认证和授权-实现自定义短信验证码登陆功能

五、资源管理系统演示

项目演示地址:http://175.24.75.121/#/login
用户名:visitor
密码:visitor
六、Spring Security认证和授权-实现自定义短信验证码登陆功能
六、Spring Security认证和授权-实现自定义短信验证码登陆功能

六、GITHUB

前端工程:https://github.com/STIll-clx/rms-admin-web
后端工程:https://github.com/STIll-clx/rms

七、专题导航

上一节:五、Spring Security认证和授权-实现图片验证码功能

欢迎点赞加关注!(๑′ᴗ‵๑)I Lᵒᵛᵉᵧₒᵤ❤