日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

手把手带你在集成SpringSecurity的SpringBoot应用中添加短信验证码登录认证功能

發(fā)布時(shí)間:2023/12/31 javascript 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 手把手带你在集成SpringSecurity的SpringBoot应用中添加短信验证码登录认证功能 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

本文目錄

    • 前言
    • 1 自定義AuthenticationToken類
    • 2 自定義AuthenticationProvider類
    • 3 自定義MobilePhoneAuthenticationFilter
    • 3 修改UserService類
    • 5 修改短信服務(wù)sendLoginVeryCodeMessage方法
    • 6 修改WebSecurityConfig配置類
    • 7 驗(yàn)證效果

前言

在上一篇文章一文理清SpringSecurity中基于用于名密碼的登錄認(rèn)證流程中筆者有詳細(xì)地介紹了Spring Security登錄認(rèn)證的流程,也為我們?cè)诠ぷ髦忻嫘枰獙?shí)現(xiàn)自定義的登錄認(rèn)證如手機(jī)號(hào)+短信驗(yàn)證碼、郵箱地址+郵箱驗(yàn)證碼以及第三方登錄認(rèn)證等方式的擴(kuò)展做好了準(zhǔn)備。那么本文,筆者就手把手帶大家實(shí)現(xiàn)在集成了Spring Security的SpringBoot項(xiàng)目中如何增加一種手機(jī)號(hào)+短信驗(yàn)證碼的方式實(shí)現(xiàn)登錄認(rèn)證。

最新為了節(jié)約搭建項(xiàng)目的時(shí)間成本,本文功能的實(shí)現(xiàn)在筆者之前改造過的開源項(xiàng)目 blogserver的基礎(chǔ)上進(jìn)行,項(xiàng)目代碼地址筆者會(huì)在文末提供,希望讀者們都能花個(gè)5分鐘左右堅(jiān)持看到文末。

1 自定義AuthenticationToken類

我們自定義的MobilePhoneAuthenticationToken類繼承自AbstractAuthenticationToken類,主要提供一個(gè)帶參構(gòu)造方法并重寫getCredentials、getPrincipal、setAuthenticated、eraseCredential和getName`等方法

public class MobilePhoneAuthenticationToken extends AbstractAuthenticationToken {// 登錄身份,這里是手機(jī)號(hào)private Object principal;// 登錄憑證,這里是短信驗(yàn)證碼private Object credentials;/*** 構(gòu)造方法* @param authorities 權(quán)限集合* @param principal 登錄身份* @param credentials 登錄憑據(jù)*/public MobilePhoneAuthenticationToken(Collection<? extends GrantedAuthority> authorities, Object principal, Object credentials) {super(authorities);this.principal = principal;this.credentials = credentials;super.setAuthenticated(true);}@Overridepublic Object getCredentials() {return credentials;}@Overridepublic Object getPrincipal() {return principal;}// 不允許通過set方法設(shè)置認(rèn)證標(biāo)識(shí)@Overridepublic void setAuthenticated(boolean authenticated) {if (authenticated) {throw new IllegalArgumentException("Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");}super.setAuthenticated(false);}// 擦除登錄憑據(jù)@Overridepublic void eraseCredentials() {super.eraseCredentials();credentials = null;}// 獲取認(rèn)證token的名字@Overridepublic String getName() {return "mobilePhoneAuthenticationToken";} }

2 自定義AuthenticationProvider類

我們自定義的MobilePhoneAuthenticationProvider類的時(shí)候 我們參照了AbstractUserDetailsAuthenticationProvider類的源碼, 同時(shí)實(shí)現(xiàn)了AuthenticationProvider、InitializingBean和MessageSourceAware等三個(gè)接口

同時(shí)為了實(shí)現(xiàn)手機(jī)號(hào)+短信驗(yàn)證碼登錄認(rèn)證的功能,我們?cè)谶@個(gè)類中添加了UserService和RedisTemplate兩個(gè)類屬性,作為MobilePhoneAuthenticationProvider類的兩個(gè)構(gòu)造參數(shù)

該類的編碼完成后的源碼如下:

public class MobilePhoneAuthenticationProvider implements AuthenticationProvider, InitializingBean, MessageSourceAware {private UserService userService;private RedisTemplate redisTemplate;private boolean forcePrincipalAsString = false;private static final Logger logger = LoggerFactory.getLogger(MobilePhoneAuthenticationProvider.class);protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();private UserDetailsChecker userDetailsChecker = new AccountStatusUserDetailsChecker();public MobilePhoneAuthenticationProvider(UserService userService, RedisTemplate redisTemplate) {this.userService = userService;this.redisTemplate = redisTemplate;}/*** 認(rèn)證方法* @param authentication 認(rèn)證token* @return successAuthenticationToken* @throws AuthenticationException 認(rèn)證異常*/@Overridepublic Authentication authenticate(Authentication authentication) throws AuthenticationException {// 首先判斷authentication參數(shù)必須是一個(gè)MobilePhoneAuthenticationToken類型對(duì)象Assert.isInstanceOf(MobilePhoneAuthenticationToken.class, authentication,()-> this.messages.getMessage("MobilePhoneAuthenticationProvider.onlySupports", "Only MobilePhoneAuthenticationToken is supported"));// 獲取authentication參數(shù)的principal屬性作為手機(jī)號(hào)String phoneNo = authentication.getPrincipal().toString();if (StringUtils.isEmpty(phoneNo)) {logger.error("phoneNo cannot be null");throw new BadCredentialsException("phoneNo cannot be null");}// 獲取authentication參數(shù)的credentials屬性作為短信驗(yàn)證碼String phoneCode = authentication.getCredentials().toString();if (StringUtils.isEmpty(phoneCode)) {logger.error("phoneCode cannot be null");throw new BadCredentialsException("phoneCode cannot be null");}try {// 調(diào)用userService服務(wù)根據(jù)手機(jī)號(hào)查詢用戶信息CustomUser user = (CustomUser) userService.loadUserByPhoneNum(Long.parseLong(phoneNo));// 校驗(yàn)用戶賬號(hào)是否過期、是否被鎖住、是否有效等屬性userDetailsChecker.check(user);// 根據(jù)手機(jī)號(hào)組成的key值去redis緩存中查詢發(fā)送短信驗(yàn)證碼時(shí)存儲(chǔ)的驗(yàn)證碼String storedPhoneCode = (String) redisTemplate.opsForValue().get("loginVerifyCode:"+phoneNo);if (storedPhoneCode==null) {logger.error("phoneCode is expired");throw new BadCredentialsException("phoneCode is expired");}// 用戶登錄攜帶的短信驗(yàn)證碼與redis中根據(jù)手機(jī)號(hào)查詢出來的登錄認(rèn)證短信驗(yàn)證碼不一致則拋出驗(yàn)證碼錯(cuò)誤異常if (!phoneCode.equals(storedPhoneCode)) {logger.error("the phoneCode is not correct");throw new BadCredentialsException("the phoneCode is not correct");}// 把完成的用戶信息賦值給組成返回認(rèn)證token中的principal屬性值Object principalToReturn = user;// 如果強(qiáng)制把用戶信息轉(zhuǎn)成字符串,則只返回用戶的手機(jī)號(hào)碼if(isForcePrincipalAsString()) {principalToReturn = user.getPhoneNum();}// 認(rèn)證成功則返回一個(gè)MobilePhoneAuthenticationToken實(shí)例對(duì)象,principal屬性為較為完整的用戶信息MobilePhoneAuthenticationToken successAuthenticationToken = new MobilePhoneAuthenticationToken(user.getAuthorities(), principalToReturn, phoneCode);return successAuthenticationToken;} catch (UsernameNotFoundException e) {// 用戶手機(jī)號(hào)不存在,如果用戶已注冊(cè)提示用戶先去個(gè)人信息頁面添加手機(jī)號(hào)碼信息,否則提示用戶使用手機(jī)號(hào)注冊(cè)成為用戶后再登錄logger.error("user " + phoneNo + "not found, if you have been register as a user, please goto the page of edit user information to add you phone number, " +"else you must register as a user use you phone number");throw new BadCredentialsException("user " + phoneNo + "not found, if you have been register as a user, please goto the page of edit user information to add you phone number, " +"else you must register as a user use you phone number");} catch (NumberFormatException e) {logger.error("invalid phoneNo, due it is not a number");throw new BadCredentialsException("invalid phoneNo, due do phoneNo is not a number");}}/*** 只支持自定義的MobilePhoneAuthenticationToken類的認(rèn)證*/@Overridepublic boolean supports(Class<?> aClass) {return aClass.isAssignableFrom(MobilePhoneAuthenticationToken.class);}@Overridepublic void afterPropertiesSet() throws Exception {Assert.notNull(this.messages, "A message source must be set");Assert.notNull(this.redisTemplate, "A RedisTemplate must be set");Assert.notNull(this.userService, "A UserDetailsService must be set");}@Overridepublic void setMessageSource(MessageSource messageSource) {this.messages = new MessageSourceAccessor(messageSource);}public void setForcePrincipalAsString(boolean forcePrincipalAsString) {this.forcePrincipalAsString = forcePrincipalAsString;}public boolean isForcePrincipalAsString() {return forcePrincipalAsString;} }

在這個(gè)自定義的認(rèn)證器類中主要在authenticate方法中完成自定義的認(rèn)證邏輯,最后認(rèn)證成功之后返回一個(gè)新的

MobilePhoneAuthenticationToken對(duì)象,principal屬性為認(rèn)證通過后的用戶詳細(xì)信息。

3 自定義MobilePhoneAuthenticationFilter

該類我們參照UsernamePasswordAuthenticationFilter類的源碼實(shí)現(xiàn)一個(gè)專門用于手機(jī)號(hào)+驗(yàn)證碼登錄認(rèn)證的認(rèn)證過濾器,它的源碼如下,我們主要在attemptAuthentication方法中完成從HttpServletRequest類型請(qǐng)求參數(shù)中提取手機(jī)號(hào)和短信驗(yàn)證碼等請(qǐng)求參數(shù)。然后組裝成一個(gè)MobilePhoneAuthenticationToken對(duì)象,用于調(diào)用this.getAuthenticationManager().authenticate方法時(shí)作為參數(shù)傳入。

實(shí)現(xiàn)重寫attemptAuthentication方法后的MobilePhoneAuthenticationFilter類的源碼如下:

/*** 自定義手機(jī)登錄認(rèn)證過濾器*/ public class MobilePhoneAuthenticationFilter extends AbstractAuthenticationProcessingFilter {public static final String SPRING_SECURITY_PHONE_NO_KEY = "phoneNo";public static final String SPRING_SECURITY_PHONE_CODE_KEY = "phoneCode";private String phoneNoParameter = SPRING_SECURITY_PHONE_NO_KEY;private String phoneCodeParameter = SPRING_SECURITY_PHONE_CODE_KEY;private boolean postOnly = true;public MobilePhoneAuthenticationFilter(String defaultFilterProcessesUrl) {super(defaultFilterProcessesUrl);}public MobilePhoneAuthenticationFilter(RequestMatcher requiresAuthenticationRequestMatcher) {super(requiresAuthenticationRequestMatcher);}@Overridepublic Authentication attemptAuthentication(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws AuthenticationException, IOException, ServletException {if (postOnly && !httpServletRequest.getMethod().equals("POST")) {throw new AuthenticationServiceException("Authentication method not supported: " + httpServletRequest.getMethod());}String phoneNo = obtainPhoneNo(httpServletRequest);if (phoneNo==null) {phoneNo = "";} else {phoneNo = phoneNo.trim();}String phoneCode = obtainPhoneCode(httpServletRequest);if (phoneCode==null) {phoneCode = "";} else {phoneCode = phoneCode.trim();}MobilePhoneAuthenticationToken authRequest = new MobilePhoneAuthenticationToken(new ArrayList<>(), phoneNo, phoneCode);this.setDetails(httpServletRequest, authRequest);return this.getAuthenticationManager().authenticate(authRequest);}@Nullableprotected String obtainPhoneNo(HttpServletRequest request) {return request.getParameter(phoneNoParameter);}@Nullableprotected String obtainPhoneCode(HttpServletRequest request) {return request.getParameter(phoneCodeParameter);}protected void setDetails(HttpServletRequest request, MobilePhoneAuthenticationToken authRequest) {authRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));} }

3 修改UserService類

UserService類主要在用來查詢用戶自定義信息,我們?cè)谠擃愔刑砑痈鶕?jù)手機(jī)號(hào)查詢用戶信息方法。注意如果用戶表中沒有手機(jī)號(hào)碼字段,需要給表新增一個(gè)存儲(chǔ)手機(jī)號(hào)碼的字段,列類型為bigint, 實(shí)體類中該字段為Long類型

UserService類中實(shí)現(xiàn)根據(jù)用戶手機(jī)號(hào)查詢用戶信息的實(shí)現(xiàn)代碼如下:

@Service @Transactional public class UserService implements CustomUserDetailsService {@ResourceUserMapper userMapper;@ResourceRolesMapper rolesMapper;@ResourcePasswordEncoder passwordEncoder;private static final Logger logger = LoggerFactory.getLogger(UserService.class);/*** 根據(jù)用戶手機(jī)號(hào)查詢用戶詳細(xì)信息* @param phoneNum 手機(jī)號(hào)* @return customUser* @throws UsernameNotFoundException*/@Overridepublic UserDetails loadUserByPhoneNum(Long phoneNum) throws UsernameNotFoundException {logger.info("用戶登錄認(rèn)證, phoneNum={}", phoneNum);UserDTO userDTO = userMapper.loadUserByPhoneNum(phoneNum);if (userDTO == null) {// 拋UsernameNotFoundException異常throw new UsernameNotFoundException("user " + phoneNum + " not exist!");}CustomUser customUser = convertUserDTO2CustomUser(userDTO);return customUser;}/*** UserDTO轉(zhuǎn)CustomUser對(duì)象* @param userDTO* @return user*/private CustomUser convertUserDTO2CustomUser(UserDTO userDTO) {//查詢用戶的角色信息,并返回存入user中List<Role> roles = rolesMapper.getRolesByUid(userDTO.getId());// 權(quán)限大的角色排在前面roles.sort(Comparator.comparing(Role::getId));CustomUser user = new CustomUser(userDTO.getUsername(), userDTO.getPassword(),userDTO.getEnabled()==1, true, true,true, new ArrayList<>());user.setId(userDTO.getId());user.setNickname(userDTO.getNickname());user.setPhoneNum(userDTO.getPhoneNum());user.setEmail(userDTO.getEmail());user.setUserface(userDTO.getUserface());user.setRegTime(userDTO.getRegTime());user.setUpdateTime(userDTO.getUpdateTime());user.setRoles(roles);user.setCurrentRole(roles.get(0));return user;}}

UserDTO和CustomUser兩個(gè)實(shí)體類源碼如下:

public class UserDTO implements Serializable {private Long id;private String username;private String password;private String nickname;private Long phoneNum;// 有效標(biāo)識(shí):0-無效;1-有效private int enabled;private String email;private String userface;private Timestamp regTime;private Timestamp updateTime;// ......省略各個(gè)屬性的set和get方法 } public class CustomUser extends User {private Long id;private String nickname;private Long phoneNum;private List<Role> roles;// 當(dāng)前角色private Role currentRole;private String email;private String userface;@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")private Date regTime;@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")private Date updateTime;public CustomUser(String username, String password, Collection<? extends GrantedAuthority> authorities) {super(username, password, authorities);}public CustomUser(String username, String password, boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities) {super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);}@Override@JsonIgnorepublic List<GrantedAuthority> getAuthorities() {List<GrantedAuthority> authorities = new ArrayList<>();for (Role role : roles) {authorities.add(new SimpleGrantedAuthority("ROLE_" + role.getRoleCode()));}return authorities;}// ......省略其他屬性的set和get方法}

Mapper層實(shí)現(xiàn)根據(jù)手機(jī)號(hào)碼查詢用戶詳細(xì)信息代碼如下:
UserMapper.java

@Repository public interface UserMapper {UserDTO loadUserByPhoneNum(@Param("phoneNum") Long phoneNum);// ......省略其他抽象方法 }

UserMapper.xml

<select id="loadUserByPhoneNum" resultType="org.sang.pojo.dto.UserDTO">SELECT id, username, nickname,password, phoneNum, enabled, email, userface, regTime, updateTimeFROM `user`WHERE phoneNum = #{phoneNum,jdbcType=BIGINT} </select>

5 修改短信服務(wù)sendLoginVeryCodeMessage方法

關(guān)于在SpringBoot項(xiàng)目中如何集成騰訊云短信服務(wù)實(shí)現(xiàn)發(fā)送短信驗(yàn)證碼功能,可以參考我之前發(fā)表在公眾號(hào)的文章SpringBoot項(xiàng)目中快速集成騰訊云短信SDK實(shí)現(xiàn)手機(jī)驗(yàn)證碼功能

只是需要稍作修改,因?yàn)榘l(fā)短信驗(yàn)證碼時(shí)要求國內(nèi)手機(jī)號(hào)前綴為+86,后面接的是用戶的11位手機(jī)號(hào)碼。而我們的數(shù)據(jù)庫中存儲(chǔ)的是11位手機(jī)號(hào)碼,使用手機(jī)號(hào)+短信驗(yàn)證碼登錄時(shí)使用的也是11位手機(jī)號(hào)碼。因此將短信驗(yàn)證碼存入redis緩存時(shí)需要將這里手機(jī)號(hào)的+86前綴去掉。

如果這里不改,那么數(shù)據(jù)庫中用戶的手機(jī)號(hào)碼字段就要設(shè)計(jì)成一個(gè)字符串類型,前端用戶登錄時(shí)傳入的手機(jī)號(hào)參數(shù)也應(yīng)該加上+86前綴。為了避免更多地方修改,我們就在這里修改好了。

SmsService.java

public SendSmsResponse sendLoginVeryCodeMessage(String phoneNum) {SendSmsRequest req = new SendSmsRequest();req.setSenderId(null);req.setSessionContext(null);req.setSign("阿福談Java技術(shù)棧");req.setSmsSdkAppid(smsProperty.getAppid());req.setTemplateID(SmsEnum.PHONE_CODE_LOGIN.getTemplateId());req.setPhoneNumberSet(new String[]{phoneNum});String verifyCode = getCode();String[] params = new String[]{verifyCode, "10"};req.setTemplateParamSet(params);logger.info("req={}", JSON.toJSONString(req));try {SendSmsResponse res = smsClient.SendSms(req);if ("Ok".equals(res.getSendStatusSet()[0].getCode())) {// 截掉+86字段,發(fā)送短信驗(yàn)證碼成功則將驗(yàn)證碼保存到redis緩存中(目前只針對(duì)國內(nèi)短息業(yè)務(wù))phoneNum = phoneNum.substring(3);redisTemplate.opsForValue().set("loginVerifyCode:"+phoneNum, verifyCode, 10, TimeUnit.MINUTES);}return res;} catch (TencentCloudSDKException e) {logger.error("send message failed", e);throw new RuntimeException("send message failed, caused by " + e.getMessage());}// 其他代碼省略

6 修改WebSecurityConfig配置類

最后我們需要修改WebSecurityConfig配置類,定義MobilePhoneAuthenticationProvider和AuthenticationManager兩個(gè)類的bean方法,同時(shí)在兩個(gè)configure方法中增加新的邏輯處理。

最后WebSecurityConfig配置類的完整代碼如下:

@Configuration public class WebSecurityConfig extends WebSecurityConfigurerAdapter {@Resourceprivate UserService userService;@ResourceRedisTemplate<String, Object> redisTemplate;@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userService);MobilePhoneAuthenticationProvider mobilePhoneAuthenticationProvider = this.mobilePhoneAuthenticationProvider();auth.authenticationProvider(mobilePhoneAuthenticationProvider);}@Overrideprotected void configure(HttpSecurity http) throws Exception {// 添加手機(jī)登錄認(rèn)證過濾器,在構(gòu)造函數(shù)中設(shè)置攔截認(rèn)證請(qǐng)求路徑MobilePhoneAuthenticationFilter mobilePhoneAuthenticationFilter = new MobilePhoneAuthenticationFilter("/mobile/login");mobilePhoneAuthenticationFilter.setAuthenticationSuccessHandler(new FormLoginSuccessHandler());mobilePhoneAuthenticationFilter.setAuthenticationFailureHandler(new FormLoginFailedHandler());// 下面這個(gè)authenticationManager必須設(shè)置,否則在MobilePhoneAuthenticationFilter#attemptAuthentication// 方法中調(diào)用this.getAuthenticationManager().authenticate(authRequest)方法時(shí)會(huì)報(bào)NullPointExceptionmobilePhoneAuthenticationFilter.setAuthenticationManager(authenticationManagerBean());mobilePhoneAuthenticationFilter.setAllowSessionCreation(true);http.addFilterAfter(mobilePhoneAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);// 配置跨域http.cors().configurationSource(corsConfigurationSource());// 禁用spring security框架的退出登錄,使用自定義退出登錄http.logout().disable();http.authorizeRequests().antMatchers("/user/reg").anonymous().antMatchers("/sendLoginVerifyCode").anonymous().antMatchers("/doc.html").hasAnyRole("user", "admin").antMatchers("/admin/**").hasRole("admin")///admin/**的URL都需要有超級(jí)管理員角色,如果使用.hasAuthority()方法來配置,需要在參數(shù)中加上ROLE_,如下:hasAuthority("ROLE_超級(jí)管理員").anyRequest().authenticated()//其他的路徑都是登錄后即可訪問.and().formLogin().loginPage("http://localhost:3000/#/login").successHandler(new FormLoginSuccessHandler()).failureHandler(new FormLoginFailedHandler()).loginProcessingUrl("/user/login").usernameParameter("username").passwordParameter("password").permitAll().and().logout().permitAll().and().csrf().disable().exceptionHandling().accessDeniedHandler(getAccessDeniedHandler());}@Overridepublic void configure(WebSecurity web) throws Exception {web.ignoring().antMatchers("/blogimg/**","/index.html","/static/**");}@BeanAccessDeniedHandler getAccessDeniedHandler() {return new AuthenticationAccessDeniedHandler();}//配置跨域訪問資源private CorsConfigurationSource corsConfigurationSource() {UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();CorsConfiguration corsConfiguration = new CorsConfiguration();corsConfiguration.addAllowedOrigin("*"); //同源配置,*表示任何請(qǐng)求都視為同源,若需指定ip和端口可以改為如“l(fā)ocalhost:8080”,多個(gè)以“,”分隔;corsConfiguration.addAllowedHeader("*");//header,允許哪些header,本案中使用的是token,此處可將*替換為token;corsConfiguration.addAllowedMethod("*"); //允許的請(qǐng)求方法,PSOT、GET等corsConfiguration.setAllowCredentials(true);// 注冊(cè)跨域配置source.registerCorsConfiguration("/**",corsConfiguration); //配置允許跨域訪問的urlreturn source;}@Override@Beanpublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();}@Beanpublic MobilePhoneAuthenticationProvider mobilePhoneAuthenticationProvider() {MobilePhoneAuthenticationProvider mobilePhoneAuthenticationProvider = new MobilePhoneAuthenticationProvider(userService, redisTemplate);return mobilePhoneAuthenticationProvider;} }

7 驗(yàn)證效果

編碼完成后,我們?cè)趩?dòng)Mysql服務(wù)器和Redis服務(wù)器后啟動(dòng)我們的SpringBoot項(xiàng)目

首先在Postman中調(diào)用發(fā)送短信驗(yàn)證碼接口


驗(yàn)證碼發(fā)送成功后返回如下響應(yīng)信息:

{"status": 200,"msg": "success","data": {"code": "Ok","phoneNumber": "+8618682244076","fee": 1,"message": "send success"} }

同時(shí)手機(jī)上也會(huì)受到6位短信驗(yàn)證碼,有效期10分鐘

然后我們使用自己的手機(jī)號(hào)+收到的6位短信驗(yàn)證碼調(diào)用登錄接口


登錄成功后返回如下響應(yīng)信息:

{"msg": "login success","userInfo": {"accountNonExpired": true,"accountNonLocked": true,"authorities": [{"authority": "ROLE_admin"},{"authority": "ROLE_user"},{"authority": "ROLE_test1"}],"credentialsNonExpired": true,"currentRole": {"id": 1,"roleCode": "admin","roleName": "管理員"},"email": "heshengfu2018@163.com","enabled": true,"id": 3,"nickname": "程序員阿福","phoneNum": 18682244076,"regTime": 1624204813000,"roles": [{"$ref": "$.userInfo.currentRole"},{"id": 2,"roleCode": "user","roleName": "普通用戶"},{"id": 3,"roleCode": "test1","roleName": "測(cè)試角色1"}],"username": "heshengfu"},"status": "success" }

到這里,實(shí)現(xiàn)在集成SpringSecurity的SpringBoot應(yīng)用中增加手機(jī)號(hào)+短信碼的方式登錄認(rèn)證的功能也就實(shí)現(xiàn)了。各位讀者朋友如果覺得文章對(duì)你有幫助,歡迎給我的這篇文章點(diǎn)個(gè)在看并轉(zhuǎn)發(fā)給身邊的程序員同事和朋友,謝謝!后面有時(shí)間筆者會(huì)在前端用戶登錄界面調(diào)用本次實(shí)現(xiàn)的后臺(tái)接口實(shí)現(xiàn)手機(jī)號(hào)+短信驗(yàn)證碼功能。

以下是這邊文章在本人的gitee倉庫的源碼地址,需要研究的完整代碼的朋友可以克隆到自己本地。

blogserver項(xiàng)目gitee克隆地址: https://gitee.com/heshengfu1211/blogserver.git

本文首發(fā)個(gè)人微信公眾號(hào)【阿福談Web編程】,覺得我的文章對(duì)你有幫助或者有什么疑問需要與我進(jìn)行交流的讀者朋友歡迎關(guān)注我的微信公眾號(hào)。關(guān)注后可在我的微信公眾號(hào)菜單欄里點(diǎn)擊【聯(lián)系作者】,就會(huì)發(fā)送筆者的微信二維碼給你。筆者期待在技術(shù)精進(jìn)的路上遇到越來越多同行的盆友,讓我們?cè)贗T技術(shù)學(xué)習(xí)的路上不孤單!

總結(jié)

以上是生活随笔為你收集整理的手把手带你在集成SpringSecurity的SpringBoot应用中添加短信验证码登录认证功能的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。