搞定了!OAuth2使用验证码进行授权

现在验证码登录已经成为很多应用的主流登录方式,但是对于OAuth2授权来说,手机号验证码处理用户认证就非常繁琐,很多同学却不知道怎么接入。

认真研究胖哥Spring Security OAuth2专栏的都会知道一个事,OAuth2其实不管资源拥有者是如何认证的,只要资源拥有者在授权的环节中认证了就可以了,至于你是验证码、账密,甚至是什么指纹虹膜都无所谓。

Id Server实现

因此胖哥好像找到了将验证码接入Id Server的方式,前面胖哥开源了一个Spring Security的登录扩展包spring-security-login-extension,可以一键接入验证码登录和小程序登录,利用这个应该就能实现。因此我就改造了一番成功实现了这一功能。看下效果:

搞定了!OAuth2使用验证码进行授权

和之前相比,用户在授权过程中可以选择账密登录或者手机验证码登录。

这里你变通一下,是不是只要是验证码登录都可以兼容进去了呢?

大致原理

这里需要前后端协同实现。

后端

核心还是扩展包的用法,给HttpSecurity加入LoginFilterSecurityConfigurer配置,这里我改动了一下和原来包中的不太一样。这里登录成功后不能再返回JWT了,需要和账密登录保持一致,核心代码如下:

httpSecurity.apply(new LoginFilterSecurityConfigurer<>())      // 手机号验证码登录模拟          .captchaLogin(captchaLoginConfigurer ->     // 验证码校验 1 在此处配置 优先级最高 2 注册为Spring Bean 可以免配置                  captchaLoginConfigurer.captchaService(this::verifyCaptchaMock)    // 根据手机号查询用户UserDetials  1 在此处配置 优先级最高 2 注册为Spring Bean 可以免配置                           .captchaUserDetailsService(this::loadUserByPhoneMock)                           // 两个登录保持一致                           .successHandler(loginAuthenticationSuccessHandler)                           // 两个登录保持一致                           .failureHandler(authenticationFailureHandler); 

其中loadUserByPhoneMock是模拟CaptchaUserDetailsService接口,根据手机号加载UserDetails:

private UserDetails loadUserByPhoneMock(String phone) throws UsernameNotFoundException {     return  // 用户名           User.withUsername(phone)             // 密码               .password("password")              .passwordEncoder(PasswordEncoderFactories.createDelegatingPasswordEncoder()::encode)               .roles("user", "mobile")               .build();         } 

verifyCaptchaMock是验证码校验逻辑接口CaptchaService的模拟,这里写死为1234,实际开发中应该用缓存实现,从发码接口中存入缓存,在CaptchaService中调用缓存接口取出验证码进行校验:

private boolean verifyCaptchaMock(String phone, String code) {     //todo 自己实现缓存校验逻辑             return code.equals("1234"); } 

验证码发送的接口自由实现,这里不需要去定义规范,记得接入缓存就行了。

前端

前端只需要接入一个可以切换登录方式的登录页就行了。然后把验证码登录接口发送验证码接口配进去就行了,授权登录页面为oauth2_login.html,通过其控制器,胖哥甚至加了一个开关enableCaptchaLogin来决定是否使用验证码认证方式。

@GetMapping("/login") public String oauth2LoginPage(Model model,                          @CurrentSecurityContext(expression = "authentication")                           Authentication authentication,                          @Value("${spring.security.oauth2.server.login.captcha.enabled:true}")                                    boolean enableCaptchaLogin,                  @RequestAttribute(name = "org.springframework.security.web.csrf.CsrfToken", required = false)                                    CsrfToken csrfToken) {       if (!(authentication instanceof AnonymousAuthenticationToken)){          return "redirect:/";      }      if (csrfToken != null) {          model.addAttribute("_csrfToken", csrfToken);      }      SystemSettings systemSettings = new SystemSettings();      model.addAttribute("enableCaptchaLogin",enableCaptchaLogin);      model.addAttribute("systemSettings", systemSettings);      return "oauth2_login"; } 

前端和验证码相关的JS处理:

        if ([[${enableCaptchaLogin}]]){             form.on('submit(mobile-login)', function (data) {                 let loader = layer.load();                 let btn = button.load({elem: '.login'});                 $.ajax({                     url: '/login/captcha',                     data: data.field,                     type: "post",                     dataType: 'json',                     success: function (result) {                         layer.close(loader);                         btn.stop(function () {                             if (result.code === 200) {                                 popup.success(result.msg, function () {                                     location.href = result.data.targetUrl;                                 })                             } else if (result.code === 401) {                                 popup.failure(result.msg);                             }                         })                     }                 });                 return false;             });              $('#captcha-btn').click(function (){                 //TODO 这里接入验证码接口                 popup.success('验证码已发送');             })         }  

关于Id Server

Id Server是一个基于Spring Authorization Server的开源的授权服务器,大大降低OAuth2授权服务器的学习使用难度,提供UI控制台,动态权限控制,方便OAuth2客户端管理,可以一键生成Spring Security配置,开箱即用,支持集成Spring Boot、Spring Cloud等java生态的框架,甚至支持其它语言,少量配置就可部署,代码开源,方便二次开发,支持OAuth2四种客户端认证方式和三种授权模式,支持账密认证和验证码认证。欢迎学习使用并参与代码贡献。

总结

OAuth2使用验证码进行授权已经实现了,适用于所有Id Server提供的DEMO。如果有兴趣可以从以下仓库地址获取最新的验证码授权代码,记得给个Star哦:

https://github.com/NotFound403/id-server 

另外还有人问Id Server和胖哥Spring Security OAuth2专栏的关系,Id Server是一个开源项目,底层的逻辑支撑来自对Spring Authorization Server的分析,掌握专栏的知识可以帮助你对Id Server的自定义改造,Id Server目标是打造一个生产可用的OAuth2授权服务器,降低OAuth2的学习使用成本,希望大家多多支持。

关注公众号:Felordcn 获取更多资讯

个人博客:https://felord.cn

发表评论

相关文章