1000字范文,内容丰富有趣,学习的好帮手!
1000字范文 > SpringBoot + SpringSecurity 短信验证码登录功能实现

SpringBoot + SpringSecurity 短信验证码登录功能实现

时间:2018-11-09 23:28:32

相关推荐

SpringBoot + SpringSecurity 短信验证码登录功能实现

实现原理

在之前的文章中,我们介绍了普通的帐号密码登录的方式:SpringBoot + Spring Security 基本使用及个性化登录配置(/article/140429.htm)。但是现在还有一种常见的方式,就是直接通过手机短信验证码登录,这里就需要自己来做一些额外的工作了。

对 SpringSecurity 认证流程详解/article/140800.htm有一定了解的都知道,在帐号密码认证的过程中,涉及到了以下几个类:UsernamePasswordAuthenticationFilter(用于请求参数获取),UsernamePasswordAuthenticationToken(表示用户登录信息),ProviderManager(进行认证校验),

因为是通过的短信验证码登录,所以我们需要对请求的参数,认证过程,用户登录 Token 信息进行一定的重写。当然验证码的过程我们应该放在最前面,如果图形验证码的实现一样。这样的做法的好处是:将验证码认证该过程解耦出来,让其他接口也可以使用到。

基本实现

验证码校验

短信验证码的功能实现,其实和图形验证码的原理是一样的。只不过一个是返回给前端一个图片,一个是给用户发送短消息,这里只需要去调用一下短信服务商的接口就好了。更多的原理可以参考 SpringBoot + SpringSecurity 实现图形验证码功能

AuthenticationToken

在使用帐号密码登录的时候,UsernamePasswordAuthenticationToken 里面包含了用户的帐号,密码,以及其他的是否可用等状态信息。我们是通过手机短信来做登录,所以就没有密码了,这里我们就直接将 UsernamePasswordAuthenticationToken 的代码 copy 过来,把密码相关的信息去掉就可以了

publicclassSmsCodeAuthenticationTokenextendsAbstractAuthenticationToken{privatestaticfinallongserialVersionUID=SpringSecurityCoreVersion.SERIAL_VERSION_UID;privatefinalObjectprincipal;publicSmsCodeAuthenticationToken(Stringmobile){super(null);this.principal=mobile;setAuthenticated(false);}publicSmsCodeAuthenticationToken(Objectprincipal,Collection<?extendsGrantedAuthority>authorities){super(authorities);this.principal=principal;super.setAuthenticated(true);//mustusesuper,asweoverride}publicObjectgetCredentials(){returnnull;}publicObjectgetPrincipal(){returnthis.principal;}publicvoidsetAuthenticated(booleanisAuthenticated)throwsIllegalArgumentException{if(isAuthenticated){thrownewIllegalArgumentException("Cannotsetthistokentotrusted-useconstructorwhichtakesaGrantedAuthoritylistinstead");}super.setAuthenticated(false);}@OverridepublicvoideraseCredentials(){super.eraseCredentials();}}

AuthenticationFilter

在帐户密码登录的流程中,默认使用的是 UsernamePasswordAuthenticationFilter,它的作用是从请求中获取帐户、密码,请求方式校验,生成 AuthenticationToken。这里我们的参数是有一定改变的,所以还是老方法,copy 过来进行简单的修改

publicclassSmsCodeAuthenticationFilterextendsAbstractAuthenticationProcessingFilter{//请求参数keyprivateStringmobileParameter=SecurityConstants.DEFAULT_PARAMETER_NAME_MOBILE;//是否只支持POSTprivatebooleanpostOnly=true;publicSmsCodeAuthenticationFilter(){//请求接口的urlsuper(newAntPathRequestMatcher(SecurityConstants.DEFAULT_LOGIN_PROCESSING_URL_MOBILE,"POST"));}publicAuthenticationattemptAuthentication(HttpServletRequestrequest,HttpServletResponseresponse)throwsAuthenticationException{if(postOnly&&!request.getMethod().equals("POST")){thrownewAuthenticationServiceException("Authenticationmethodnotsupported:"+request.getMethod());}//根据请求参数名,获取请求valueStringmobile=obtainMobile(request);if(mobile==null){mobile="";}mobile=mobile.trim();//生成对应的AuthenticationTokenSmsCodeAuthenticationTokenauthRequest=newSmsCodeAuthenticationToken(mobile);setDetails(request,authRequest);returnthis.getAuthenticationManager().authenticate(authRequest);}/*获取手机号*/protectedStringobtainMobile(HttpServletRequestrequest){returnrequest.getParameter(mobileParameter);}//省略不相关代码}

Provider

在帐号密码登录的过程中,密码的正确性以及帐号是否可用是通过 DaoAuthenticationProvider 来校验的。我们也应该自己实现一个 Provier

publicclassSmsCodeAuthenticationProviderimplementsAuthenticationProvider{privateUserDetailsServiceuserDetailsService;/*身份逻辑验证*@paramauthentication*@return*@throwsAuthenticationException*/@OverridepublicAuthenticationauthenticate(Authenticationauthentication)throwsAuthenticationException{SmsCodeAuthenticationTokenauthenticationToken=(SmsCodeAuthenticationToken)authentication;UserDetailsuser=userDetailsService.loadUserByUsername((String)authenticationToken.getPrincipal());if(user==null){thrownewInternalAuthenticationServiceException("无法获取用户信息");}SmsCodeAuthenticationTokenauthenticationResult=newSmsCodeAuthenticationToken(user,user.getAuthorities());authenticationResult.setDetails(authenticationToken.getDetails());returnauthenticationResult;}@Overridepublicbooleansupports(Class<?>authentication){returnSmsCodeAuthenticationToken.class.isAssignableFrom(authentication);}publicUserDetailsServicegetUserDetailsService(){returnuserDetailsService;}publicvoidsetUserDetailsService(UserDetailsServiceuserDetailsService){this.userDetailsService=userDetailsService;}}

配置

主要的认证流程就是通过以上四个过程实现的, 这里我们再降它们配置一下就可以了

@ComponentpublicclassSmsCodeAuthenticationSecurityConfigextendsSecurityConfigurerAdapter<DefaultSecurityFilterChain,HttpSecurity>{@AutowiredprivateAuthenticationSuccessHandlermyAuthenticationSuccessHandler;@AutowiredprivateAuthenticationFailureHandlermyAuthenticationFailureHandler;@AutowiredprivateUserDetailsServiceuserDetailsService;@Overridepublicvoidconfigure(HttpSecurityhttp)throwsException{SmsCodeAuthenticationFiltersmsCodeAuthenticationFilter=newSmsCodeAuthenticationFilter();smsCodeAuthenticationFilter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class));smsCodeAuthenticationFilter.setAuthenticationSuccessHandler(myAuthenticationSuccessHandler);smsCodeAuthenticationFilter.setAuthenticationFailureHandler(myAuthenticationFailureHandler);SmsCodeAuthenticationProvidersmsCodeAuthenticationProvider=newSmsCodeAuthenticationProvider();smsCodeAuthenticationProvider.setUserDetailsService(userDetailsService);http.authenticationProvider(smsCodeAuthenticationProvider).addFilterAfter(smsCodeAuthenticationFilter,UsernamePasswordAuthenticationFilter.class);}}//BrowerSecurityConfig.java@Overrideprotectedvoidconfigure(HttpSecurityhttp)throwsException{http.apply(smsCodeAuthenticationSecurityConfig);}

代码下载

Spring-Security

/whyalwaysmea/Spring-Security

来源链接:

/article/141972.htm

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。