当前位置:   article > 正文

若依前后端分离版ruoyi-vue:增加新的登录接口(新用户表),用于小程序或者APP获取token,并使用若依的验证方法,结合腾讯云短信验证码实现手机号+验证码登陆_若依前后端分离无状态身份验证

若依前后端分离无状态身份验证

1.新建—SmsController类

  1. package com.wanuw.user.controller.login;
  2. import com.wanuw.common.constant.Constants;
  3. import com.wanuw.common.core.domain.AjaxResult;
  4. import com.wanuw.user.service.SmsService;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.web.bind.annotation.*;
  7. /**
  8. * 手机端验证码
  9. *
  10. * @author dagang
  11. */
  12. @RestController
  13. @RequestMapping("/sms")
  14. public class SmsController
  15. {
  16. @Autowired
  17. private SmsService smsService;
  18. /**
  19. * 生成手机验证码
  20. */
  21. @PostMapping("/send")
  22. public AjaxResult sendSmsCode(@RequestParam(value = "phoneNumber") String phoneNumber) {
  23. String message = smsService.sendSmsCode(phoneNumber);
  24. return AjaxResult.success(message);
  25. }
  26. /**
  27. * 验证手机验证码
  28. */
  29. @PostMapping("/verify")
  30. public AjaxResult verifySmsCode(@RequestParam(value = "phoneNumber") String phoneNumber,
  31. @RequestParam(value = "smsCode") String smsCode) {
  32. AjaxResult ajax = AjaxResult.success();
  33. String token = smsService.verifySmsCode(phoneNumber, smsCode);
  34. ajax.put(Constants.TOKEN, token);
  35. return ajax;
  36. }
  37. }


2.新建—SmsService类

  1. package com.wanuw.user.service;
  2. import com.baomidou.mybatisplus.extension.service.IService;
  3. import com.wanuw.common.core.domain.user.member.DbUser;
  4. /**
  5. * 手机端用户登录验证
  6. *
  7. * @author dagang
  8. */
  9. public interface SmsService extends IService<DbUser> {
  10. /**
  11. * 生成手机验证码
  12. */
  13. String sendSmsCode(String phoneNumber);
  14. /**
  15. * 验证手机验证码
  16. */
  17. String verifySmsCode(String phoneNumber, String smsCode);
  18. }

3.新建—SmsServiceImpl 实现层

此处注意注入的是:AppAuthenticationProvider

TokenService和RedisCache是若依框架自带

  1. package com.wanuw.user.service.impl;
  2. import cn.hutool.core.util.RandomUtil;
  3. import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  4. import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
  5. import com.tencentcloudapi.sms.v20190711.models.SendStatus;
  6. import com.wanuw.common.config.tencent.SmsConfig;
  7. import com.wanuw.common.constant.CacheConstants;
  8. import com.wanuw.common.constant.Constants;
  9. import com.wanuw.common.core.domain.model.LoginUser;
  10. import com.wanuw.common.core.redis.RedisCache;
  11. import com.wanuw.common.exception.ServiceException;
  12. import com.wanuw.common.exception.user.CaptchaException;
  13. import com.wanuw.common.exception.user.CaptchaExpireException;
  14. import com.wanuw.common.exception.user.UserNotExistsException;
  15. import com.wanuw.common.exception.user.UserPasswordNotMatchException;
  16. import com.wanuw.common.utils.ChineseNameUtils;
  17. import com.wanuw.common.utils.MessageUtils;
  18. import com.wanuw.common.utils.SecurityUtils;
  19. import com.wanuw.common.utils.tencent.SmsUtil;
  20. import com.wanuw.framework.manager.AsyncManager;
  21. import com.wanuw.framework.manager.factory.AsyncFactory;
  22. import com.wanuw.framework.web.service.TokenService;
  23. import com.wanuw.common.core.domain.user.member.DbUser;
  24. import com.wanuw.member.mapper.DbUserMapper;
  25. import com.wanuw.member.service.IDbUserService;
  26. import com.wanuw.user.controller.login.AppAuthenticationProvider;
  27. import com.wanuw.user.service.SmsService;
  28. import org.springframework.beans.factory.annotation.Autowired;
  29. import org.springframework.security.authentication.BadCredentialsException;
  30. import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
  31. import org.springframework.security.core.Authentication;
  32. import org.springframework.stereotype.Service;
  33. import javax.annotation.Resource;
  34. import java.util.concurrent.TimeUnit;
  35. /**
  36. * 手机端用户登录验证
  37. *
  38. * @author dagang
  39. */
  40. @Service
  41. public class SmsServiceImpl extends ServiceImpl<DbUserMapper, DbUser> implements SmsService {
  42. @Autowired
  43. private TokenService tokenService;
  44. @Resource
  45. private AppAuthenticationProvider authenticationManager;
  46. @Resource
  47. private SmsConfig smsConfig;
  48. @Autowired
  49. private RedisCache redisCache;
  50. @Autowired
  51. private IDbUserService dbUserService;
  52. /**
  53. * 创建手机验证码
  54. */
  55. @Override
  56. public String sendSmsCode(String phoneNumber) {
  57. // 下发手机号码,采用e.164标准,+[国家或地区码][手机号]
  58. String[] phoneNumbers = {"+86" + phoneNumber};
  59. // 生成6位随机数字字符串
  60. String smsCode = RandomUtil.randomNumbers(6);
  61. // 模板参数:若无模板参数,则设置为空(参数1为随机验证码,参数2为有效时间)
  62. String[] templateParams = {smsCode, smsConfig.getExpireTime().toString()};
  63. // 发送短信验证码
  64. SendStatus[] sendStatuses = SmsUtil.sendSms(smsConfig, templateParams, phoneNumbers);
  65. if ("Ok".equals(sendStatuses[0].getCode())) {
  66. // 创建短信验证码缓存的key并设置过期时间
  67. String key = CacheConstants.CAPTCHA_TELPHONE_CODE_KEY + phoneNumber;
  68. redisCache.setCacheObject(key, smsCode, smsConfig.getExpireTime(), TimeUnit.MINUTES);
  69. return "验证码发送成功";
  70. } else {
  71. return "验证码发送失败:" + sendStatuses[0].getMessage();
  72. //return "验证码发送失败:";
  73. }
  74. }
  75. /**
  76. * 验证手机验证码
  77. */
  78. @Override
  79. public String verifySmsCode(String phoneNumber, String smsCode) {
  80. //1.验证码校验
  81. checkCode(phoneNumber, smsCode);
  82. //2.检查用户手机号是否已经注册,若未注册,直接注册成用户
  83. LambdaQueryWrapper<DbUser> queryWrapper = new LambdaQueryWrapper<>();
  84. queryWrapper.eq(DbUser::getUserTel, phoneNumber);
  85. DbUser dbUser = dbUserService.getOne(queryWrapper);
  86. if (dbUser == null) {
  87. //说明未注册过账户,开始注册账户
  88. DbUser dbUserNew = new DbUser();
  89. dbUserNew.setUserTel(phoneNumber);
  90. //添加默认密码123456
  91. dbUserNew.setPassword(SecurityUtils.encryptPassword("123456"));
  92. //这是个生成随机汉字名字的工具
  93. dbUserNew.setUserNickname(ChineseNameUtils.randomChineseName());
  94. dbUserNew.setUserName(phoneNumber);
  95. dbUserService.save(dbUserNew);
  96. }
  97. String username = phoneNumber;
  98. String password = "123456";
  99. //自定义用户名和密码
  100. // 用户验证
  101. Authentication authentication;
  102. try {
  103. // 原来其实就这么一句话:该方法会去调用UserDetailsServiceImpl.loadUserByUsername。指的是原来若依自定义的UserDetailsServiceImpl
  104. //此处会让人很迷惑,特别是对新手来说。其实就是调用了AppUserDetailsServiceImpl中的loadUserByUsername方法
  105. //而这个方法的是通过AppAuthenticationProvider中去发起的。所以这个authenticationManager 其实就是注入的AppAuthenticationProvider
  106. //这个地方一定要注意!!!!!
  107. authentication = authenticationManager
  108. .authenticate(new UsernamePasswordAuthenticationToken(username, password));
  109. } catch (Exception e) {
  110. if (e instanceof BadCredentialsException) {
  111. AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
  112. throw new UserPasswordNotMatchException();
  113. } else {
  114. AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
  115. throw new ServiceException(e.getMessage());
  116. }
  117. }
  118. AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
  119. LoginUser loginUser = (LoginUser) authentication.getPrincipal();
  120. //recordLoginInfo(dbUser.getId());
  121. // 生成token
  122. return tokenService.createToken(loginUser);
  123. }
  124. /**
  125. *
  126. * @param phoneNumber 电话号码
  127. * @param smsCode 验证码
  128. */
  129. public void checkCode(String phoneNumber, String smsCode) {
  130. // 创建key
  131. String key = CacheConstants.CAPTCHA_TELPHONE_CODE_KEY + phoneNumber;
  132. String captcha = redisCache.getCacheObject(key);
  133. //校验传入数据是否为空
  134. if (phoneNumber == null || smsCode == null) {
  135. AsyncManager.me().execute(AsyncFactory.recordLogininfor(phoneNumber, Constants.LOGIN_FAIL, MessageUtils.message("not.null")));
  136. throw new UserNotExistsException();
  137. }
  138. //校验验证码位数
  139. if (smsCode.length() != 6) {
  140. AsyncManager.me().execute(AsyncFactory.recordLogininfor(phoneNumber, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
  141. throw new UserPasswordNotMatchException();
  142. }
  143. // 判断指定key是否存在并且未过期
  144. if (captcha == null)
  145. {
  146. AsyncManager.me().execute(AsyncFactory.recordLogininfor(phoneNumber, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")));
  147. throw new CaptchaExpireException();
  148. }
  149. // 验证输入的验证码是否正确
  150. if (!smsCode.equalsIgnoreCase(captcha))
  151. {
  152. AsyncManager.me().execute(AsyncFactory.recordLogininfor(phoneNumber, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
  153. throw new CaptchaException();
  154. }
  155. // 验证成功后删除验证码缓存
  156. redisCache.deleteObject(key);
  157. }
  158. }

4.新建—AppUserDetailsServiceImpl类

  1. package com.wanuw.user.controller.login;
  2. import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  3. import com.wanuw.common.core.domain.model.LoginUser;
  4. import com.wanuw.common.exception.ServiceException;
  5. import com.wanuw.common.utils.StringUtils;
  6. import com.wanuw.common.core.domain.user.member.DbUser;
  7. import com.wanuw.member.mapper.DbUserMapper;
  8. import lombok.extern.slf4j.Slf4j;
  9. import org.springframework.beans.factory.annotation.Autowired;
  10. import org.springframework.security.core.userdetails.UserDetails;
  11. import org.springframework.security.core.userdetails.UserDetailsService;
  12. import org.springframework.security.core.userdetails.UsernameNotFoundException;
  13. import org.springframework.stereotype.Service;
  14. /**
  15. * 手机端验证码
  16. *
  17. * @author dagang
  18. */
  19. @Slf4j
  20. @Service
  21. public class AppUserDetailsServiceImpl implements UserDetailsService {
  22. @Autowired
  23. private DbUserMapper dbUserMapper;
  24. @Override
  25. public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
  26. //验证登录用户,使用的是mybatis-plus语法查询的用户数据
  27. //因为是手机号登录,上面形参其实是手机号码,可以改成phone,本人偷懒,未改
  28. DbUser dbUser = dbUserMapper.selectOne(new LambdaQueryWrapper<DbUser>()
  29. .eq(DbUser::getUserTel, username));
  30. if (StringUtils.isNull(dbUser)) {
  31. log.info("登录用户:{} 不存在.", username);
  32. throw new ServiceException("登录用户:" + username + " 不存在");
  33. } else if (dbUser.getDeleted() == 1) {
  34. log.info("登录用户:{} 已被删除.", username);
  35. throw new ServiceException("对不起,您的账号:" + username + " 已被删除");
  36. } else if (dbUser.getUserStatus() == 1) {
  37. log.info("登录用户:{} 已被停用.", username);
  38. throw new ServiceException("对不起,您的账号:" + username + " 已停用");
  39. }
  40. //返回UserDetails用户对象
  41. return createLoginUser(dbUser);
  42. }
  43. public UserDetails createLoginUser(DbUser dbUser) {
  44. /**
  45. * 参数一:第一个是用户的ID,用户后期使用SecurityUtils.getUserId()时获取上下文中存储的用户ID数据,若未设置,SecurityUtils.getUserId()获取数据位null
  46. * 参数二:整个用户数据传入,后面会保存在Redis中,登陆校验时会用到
  47. */
  48. return new LoginUser(dbUser.getId(),dbUser);
  49. }
  50. }

5.新建—AppAuthenticationProvider

  1. package com.wanuw.user.controller.login;
  2. import lombok.SneakyThrows;
  3. import lombok.extern.slf4j.Slf4j;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.security.authentication.AuthenticationProvider;
  6. import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
  7. import org.springframework.security.core.Authentication;
  8. import org.springframework.security.core.AuthenticationException;
  9. import org.springframework.security.core.GrantedAuthority;
  10. import org.springframework.security.core.userdetails.UserDetails;
  11. import org.springframework.stereotype.Component;
  12. import java.util.Collection;
  13. /**
  14. * 手机端验证码
  15. *
  16. * @author dagang
  17. */
  18. @Slf4j
  19. @Component
  20. public class AppAuthenticationProvider implements AuthenticationProvider {
  21. @Autowired
  22. private AppUserDetailsServiceImpl userDetailsService;
  23. @SneakyThrows
  24. @Override
  25. public Authentication authenticate(Authentication authentication) throws AuthenticationException {
  26. // 这个获取表单输入中返回的用户名,此处获取到的是手机号码
  27. String userName = authentication.getName();
  28. // 这里构建来判断用户是否存在和密码是否正确
  29. // 这里调用我们的自己写的AppUserDetailsServiceImpl获取用户的方法;
  30. UserDetails userInfo = userDetailsService.loadUserByUsername(userName);
  31. Collection<? extends GrantedAuthority> authorities = userInfo.getAuthorities();
  32. // 构建返回的用户登录成功的token
  33. return new UsernamePasswordAuthenticationToken(userInfo, userInfo.getPassword(), authorities);
  34. }
  35. @Override
  36. public boolean supports(Class<?> authentication) {
  37. //return authentication.equals(UsernamePasswordAuthenticationToken.class);
  38. // 这里直接改成 return true;表示是支持这个执行
  39. return true;
  40. }
  41. }

6.修改—LoginUser

路径:src/main/java/com/wanuw/common/core/domain/model/LoginUser.java

添加新用户表实体类,一定要添加Getter和Setter,之前未添加导致存入Redis后没有用户实体类的信息,查找了好久,主要是我水平有限,可能水平高的人一下就会找到原因了。

  1. package com.wanuw.common.core.domain.model;
  2. import com.alibaba.fastjson2.annotation.JSONField;
  3. import com.wanuw.common.core.domain.entity.SysUser;
  4. import com.wanuw.common.core.domain.user.member.DbUser;
  5. import org.springframework.security.core.GrantedAuthority;
  6. import org.springframework.security.core.userdetails.UserDetails;
  7. import java.util.Collection;
  8. import java.util.Set;
  9. /**
  10. * 登录用户身份权限
  11. *
  12. * @author ruoyi
  13. */
  14. public class LoginUser implements UserDetails
  15. {
  16. private static final long serialVersionUID = 1L;
  17. /**
  18. * 用户ID
  19. */
  20. private Long userId;
  21. /**
  22. * 部门ID
  23. */
  24. private Long deptId;
  25. /**
  26. * 用户唯一标识
  27. */
  28. private String token;
  29. /**
  30. * 登录时间
  31. */
  32. private Long loginTime;
  33. /**
  34. * 过期时间
  35. */
  36. private Long expireTime;
  37. /**
  38. * 登录IP地址
  39. */
  40. private String ipaddr;
  41. /**
  42. * 登录地点
  43. */
  44. private String loginLocation;
  45. /**
  46. * 浏览器类型
  47. */
  48. private String browser;
  49. /**
  50. * 操作系统
  51. */
  52. private String os;
  53. /**
  54. * 权限列表
  55. */
  56. private Set<String> permissions;
  57. /**
  58. * 用户信息
  59. */
  60. private SysUser user;
  61. /**
  62. * App用户数据
  63. */
  64. private DbUser dbUser;
  65. public DbUser getDbUser() {
  66. return dbUser;
  67. }
  68. public void setDbUser(DbUser dbUser) {
  69. this.dbUser = dbUser;
  70. }
  71. @JSONField(serialize = false)
  72. @Override
  73. public String getPassword()
  74. {
  75. if (user != null) {
  76. return user.getPassword();
  77. } else {
  78. return dbUser.getPassword();
  79. }
  80. }
  81. @Override
  82. public String getUsername()
  83. {
  84. if (user != null) {
  85. return user.getUserName();
  86. } else {
  87. return dbUser.getUserTel();
  88. }
  89. }
  90. public LoginUser(Long userId, DbUser dbUser)
  91. {
  92. this.userId = userId;
  93. this.dbUser = dbUser;
  94. }
  95. public LoginUser()
  96. {
  97. }
  98. public LoginUser(SysUser user, Set<String> permissions)
  99. {
  100. this.user = user;
  101. this.permissions = permissions;
  102. }
  103. public LoginUser(DbUser dbUser)
  104. {
  105. this.dbUser = dbUser;
  106. }
  107. public LoginUser(Long userId, Long deptId, SysUser user, Set<String> permissions)
  108. {
  109. this.userId = userId;
  110. this.deptId = deptId;
  111. this.user = user;
  112. this.permissions = permissions;
  113. }
  114. public Long getUserId()
  115. {
  116. return userId;
  117. }
  118. public void setUserId(Long userId)
  119. {
  120. this.userId = userId;
  121. }
  122. public Long getDeptId()
  123. {
  124. return deptId;
  125. }
  126. public void setDeptId(Long deptId)
  127. {
  128. this.deptId = deptId;
  129. }
  130. public String getToken()
  131. {
  132. return token;
  133. }
  134. public void setToken(String token)
  135. {
  136. this.token = token;
  137. }
  138. /**
  139. * 账户是否未过期,过期无法验证
  140. */
  141. @JSONField(serialize = false)
  142. @Override
  143. public boolean isAccountNonExpired()
  144. {
  145. return true;
  146. }
  147. /**
  148. * 指定用户是否解锁,锁定的用户无法进行身份验证
  149. *
  150. * @return
  151. */
  152. @JSONField(serialize = false)
  153. @Override
  154. public boolean isAccountNonLocked()
  155. {
  156. return true;
  157. }
  158. /**
  159. * 指示是否已过期的用户的凭据(密码),过期的凭据防止认证
  160. *
  161. * @return
  162. */
  163. @JSONField(serialize = false)
  164. @Override
  165. public boolean isCredentialsNonExpired()
  166. {
  167. return true;
  168. }
  169. /**
  170. * 是否可用 ,禁用的用户不能身份验证
  171. *
  172. * @return
  173. */
  174. @JSONField(serialize = false)
  175. @Override
  176. public boolean isEnabled()
  177. {
  178. return true;
  179. }
  180. public Long getLoginTime()
  181. {
  182. return loginTime;
  183. }
  184. public void setLoginTime(Long loginTime)
  185. {
  186. this.loginTime = loginTime;
  187. }
  188. public String getIpaddr()
  189. {
  190. return ipaddr;
  191. }
  192. public void setIpaddr(String ipaddr)
  193. {
  194. this.ipaddr = ipaddr;
  195. }
  196. public String getLoginLocation()
  197. {
  198. return loginLocation;
  199. }
  200. public void setLoginLocation(String loginLocation)
  201. {
  202. this.loginLocation = loginLocation;
  203. }
  204. public String getBrowser()
  205. {
  206. return browser;
  207. }
  208. public void setBrowser(String browser)
  209. {
  210. this.browser = browser;
  211. }
  212. public String getOs()
  213. {
  214. return os;
  215. }
  216. public void setOs(String os)
  217. {
  218. this.os = os;
  219. }
  220. public Long getExpireTime()
  221. {
  222. return expireTime;
  223. }
  224. public void setExpireTime(Long expireTime)
  225. {
  226. this.expireTime = expireTime;
  227. }
  228. public Set<String> getPermissions()
  229. {
  230. return permissions;
  231. }
  232. public void setPermissions(Set<String> permissions)
  233. {
  234. this.permissions = permissions;
  235. }
  236. public SysUser getUser()
  237. {
  238. return user;
  239. }
  240. public void setUser(SysUser user)
  241. {
  242. this.user = user;
  243. }
  244. @Override
  245. public Collection<? extends GrantedAuthority> getAuthorities()
  246. {
  247. return null;
  248. }
  249. }

截图注意项:

7.修改—解决运行冲突

路径:src/main/java/com/wanuw/framework/config/SecurityConfig.java

添加注解:@Qualifier("userDetailsServiceImpl")

 此时启动项目不会报冲突的错,其实就是给起了一个不冲突的名字

千万千万要添加!!!

此时已经添加完成了。可以启动测试了!

==============================分割线===================================

附上:

1.DbUser实体类,做参考

  1. package com.wanuw.common.core.domain.user.member;
  2. import com.baomidou.mybatisplus.annotation.TableField;
  3. import com.baomidou.mybatisplus.annotation.TableId;
  4. import com.baomidou.mybatisplus.annotation.TableLogic;
  5. import com.baomidou.mybatisplus.annotation.TableName;
  6. import com.wanuw.common.annotation.Excel;
  7. import com.wanuw.common.core.domain.BaseEntity;
  8. import lombok.*;
  9. import java.math.BigDecimal;
  10. import java.time.LocalDateTime;
  11. /**
  12. * 会员对象 db_user
  13. *
  14. * @author dagang
  15. * @date 2023-11-09
  16. */
  17. @Data
  18. @Builder
  19. @AllArgsConstructor
  20. @NoArgsConstructor
  21. @EqualsAndHashCode(callSuper = true)
  22. @TableName("db_user")
  23. public class DbUser extends BaseEntity {
  24. private static final long serialVersionUID = 1L;
  25. /**
  26. * 会员主键
  27. */
  28. @TableId(value = "id")
  29. private Long id;
  30. /**
  31. * 用户名
  32. */
  33. @TableField(value = "user_name")
  34. @Excel(name = "用户名")
  35. private String userName;
  36. /**
  37. * 手机号
  38. */
  39. @TableField(value = "user_tel")
  40. @Excel(name = "手机号")
  41. private String userTel;
  42. /**
  43. * 密码
  44. */
  45. @TableField(value = "password")
  46. private String password;
  47. /**
  48. * 推广号(不能重复 无上级默认1010110)
  49. */
  50. @TableField(value = "user_code")
  51. private String userCode;
  52. /**
  53. * 用户昵称(注册时随机字母)
  54. */
  55. @TableField(value = "user_nickname")
  56. private String userNickname;
  57. /**
  58. * 头像
  59. */
  60. @TableField(value = "user_image")
  61. private String userImage;
  62. /**
  63. * 性别
  64. */
  65. @TableField(value = "user_sex")
  66. private Integer userSex;
  67. /**
  68. * 所在地(辽宁,沈阳)
  69. */
  70. @TableField(value = "user_adddress")
  71. private String userAdddress;
  72. /**
  73. * 会员简介
  74. */
  75. @TableField(value = "user_text")
  76. private String userText;
  77. }

2.腾讯短信工具类SmsUtils

  1. package com.wanuw.common.utils.tencent;
  2. import com.tencentcloudapi.common.Credential;
  3. import com.tencentcloudapi.common.exception.TencentCloudSDKException;
  4. import com.tencentcloudapi.common.profile.ClientProfile;
  5. import com.tencentcloudapi.common.profile.HttpProfile;
  6. import com.tencentcloudapi.sms.v20190711.SmsClient;
  7. import com.tencentcloudapi.sms.v20190711.models.SendSmsRequest;
  8. import com.tencentcloudapi.sms.v20190711.models.SendSmsResponse;
  9. import com.tencentcloudapi.sms.v20190711.models.SendStatus;
  10. import com.wanuw.common.config.tencent.SmsConfig;
  11. import lombok.extern.slf4j.Slf4j;
  12. @Slf4j
  13. public class SmsUtil {
  14. public static SendStatus[] sendSms(SmsConfig smsConfig, String[] templateParams, String[] phoneNumbers) {
  15. try {
  16. /* 必要步骤:
  17. * 实例化一个认证对象,入参需要传入腾讯云账户密钥对secretId,secretKey。
  18. * 这里采用的是从环境变量读取的方式,需要在环境变量中先设置这两个值。
  19. * 您也可以直接在代码中写死密钥对,但是小心不要将代码复制、上传或者分享给他人,
  20. * 以免泄露密钥对危及您的财产安全。
  21. * SecretId、SecretKey 查询: https://console.cloud.tencent.com/cam/capi */
  22. Credential cred = new Credential(smsConfig.getSecretId(), smsConfig.getSecretKey());
  23. // 实例化一个http选项,可选,没有特殊需求可以跳过
  24. HttpProfile httpProfile = new HttpProfile();
  25. // 设置代理(无需要直接忽略)
  26. // httpProfile.setProxyHost("真实代理ip");
  27. // httpProfile.setProxyPort(真实代理端口);
  28. /* SDK默认使用POST方法。
  29. * 如果您一定要使用GET方法,可以在这里设置。GET方法无法处理一些较大的请求 */
  30. httpProfile.setReqMethod("POST");
  31. /* SDK有默认的超时时间,非必要请不要进行调整
  32. * 如有需要请在代码中查阅以获取最新的默认值 */
  33. httpProfile.setConnTimeout(60);
  34. /* 指定接入地域域名,默认就近地域接入域名为 sms.tencentcloudapi.com ,也支持指定地域域名访问,例如广州地域的域名为 sms.ap-guangzhou.tencentcloudapi.com */
  35. httpProfile.setEndpoint("sms.tencentcloudapi.com");
  36. /* 非必要步骤:
  37. * 实例化一个客户端配置对象,可以指定超时时间等配置 */
  38. ClientProfile clientProfile = new ClientProfile();
  39. /* SDK默认用TC3-HMAC-SHA256进行签名
  40. * 非必要请不要修改这个字段 */
  41. clientProfile.setSignMethod("HmacSHA256");
  42. clientProfile.setHttpProfile(httpProfile);
  43. /* 实例化要请求产品(以sms为例)的client对象
  44. * 第二个参数是地域信息,可以直接填写字符串ap-guangzhou,支持的地域列表参考 https://cloud.tencent.com/document/api/382/52071#.E5.9C.B0.E5.9F.9F.E5.88.97.E8.A1.A8 */
  45. SmsClient client = new SmsClient(cred, "ap-guangzhou",clientProfile);
  46. /* 实例化一个请求对象,根据调用的接口和实际情况,可以进一步设置请求参数
  47. * 您可以直接查询SDK源码确定接口有哪些属性可以设置
  48. * 属性可能是基本类型,也可能引用了另一个数据结构
  49. * 推荐使用IDE进行开发,可以方便的跳转查阅各个接口和数据结构的文档说明 */
  50. SendSmsRequest req = new SendSmsRequest();
  51. /* 填充请求参数,这里request对象的成员变量即对应接口的入参
  52. * 您可以通过官网接口文档或跳转到request对象的定义处查看请求参数的定义
  53. * 基本类型的设置:
  54. * 帮助链接:
  55. * 短信控制台: https://console.cloud.tencent.com/smsv2
  56. * 腾讯云短信小助手: https://cloud.tencent.com/document/product/382/3773#.E6.8A.80.E6.9C.AF.E4.BA.A4.E6.B5.81 */
  57. /* 短信应用ID: 短信SdkAppId在 [短信控制台] 添加应用后生成的实际SdkAppId,示例如1400006666 */
  58. // 应用 ID 可前往 [短信控制台](https://console.cloud.tencent.com/smsv2/app-manage) 查看
  59. req.setSmsSdkAppid(smsConfig.getAppId());
  60. /* 短信签名内容: 使用 UTF-8 编码,必须填写已审核通过的签名 */
  61. // 签名信息可前往 [国内短信](https://console.cloud.tencent.com/smsv2/csms-sign) 或 [国际/港澳台短信](https://console.cloud.tencent.com/smsv2/isms-sign) 的签名管理查看
  62. req.setSign(smsConfig.getSign());
  63. /* 模板 ID: 必须填写已审核通过的模板 ID */
  64. // 模板 ID 可前往 [国内短信](https://console.cloud.tencent.com/smsv2/csms-template) 或 [国际/港澳台短信](https://console.cloud.tencent.com/smsv2/isms-template) 的正文模板管理查看
  65. req.setTemplateID(smsConfig.getTemplateId());
  66. /* 模板参数: 模板参数的个数需要与 TemplateId 对应模板的变量个数保持一致,若无模板参数,则设置为空 */
  67. req.setTemplateParamSet(templateParams);
  68. /* 下发手机号码,采用 E.164 标准,+[国家或地区码][手机号]
  69. * 示例如:+8613711112222, 其中前面有一个+号 ,86为国家码,13711112222为手机号,最多不要超过200个手机号 */
  70. req.setPhoneNumberSet(phoneNumbers);
  71. /* 用户的 session 内容(无需要可忽略): 可以携带用户侧 ID 等上下文信息,server 会原样返回 */
  72. String sessionContext = "";
  73. req.setSessionContext(sessionContext);
  74. /* 短信码号扩展号(无需要可忽略): 默认未开通,如需开通请联系 [腾讯云短信小助手] */
  75. String extendCode = "";
  76. req.setExtendCode(extendCode);
  77. /* 国内短信无需填写该项;国际/港澳台短信已申请独立 SenderId 需要填写该字段,默认使用公共 SenderId,无需填写该字段。注:月度使用量达到指定量级可申请独立 SenderId 使用,详情请联系 [腾讯云短信小助手](https://cloud.tencent.com/document/product/382/3773#.E6.8A.80.E6.9C.AF.E4.BA.A4.E6.B5.81)。*/
  78. String senderid = "";
  79. req.setSenderId(senderid);
  80. /* 通过 client 对象调用 SendSms 方法发起请求。注意请求方法名与请求对象是对应的
  81. * 返回的 res 是一个 SendSmsResponse 类的实例,与请求对象对应 */
  82. SendSmsResponse res = client.SendSms(req);
  83. // 输出json格式的字符串回包
  84. log.info("json格式字符串返回包:{}", SendSmsResponse.toJsonString(res));
  85. return res.getSendStatusSet();
  86. // 也可以取出单个值,您可以通过官网接口文档或跳转到response对象的定义处查看返回字段的定义
  87. // System.out.println(res.getRequestId());
  88. /* 当出现以下错误码时,快速解决方案参考
  89. * [FailedOperation.SignatureIncorrectOrUnapproved](https://cloud.tencent.com/document/product/382/9558#.E7.9F.AD.E4.BF.A1.E5.8F.91.E9.80.81.E6.8F.90.E7.A4.BA.EF.BC.9Afailedoperation.signatureincorrectorunapproved-.E5.A6.82.E4.BD.95.E5.A4.84.E7.90.86.EF.BC.9F)
  90. * [FailedOperation.TemplateIncorrectOrUnapproved](https://cloud.tencent.com/document/product/382/9558#.E7.9F.AD.E4.BF.A1.E5.8F.91.E9.80.81.E6.8F.90.E7.A4.BA.EF.BC.9Afailedoperation.templateincorrectorunapproved-.E5.A6.82.E4.BD.95.E5.A4.84.E7.90.86.EF.BC.9F)
  91. * [UnauthorizedOperation.SmsSdkAppIdVerifyFail](https://cloud.tencent.com/document/product/382/9558#.E7.9F.AD.E4.BF.A1.E5.8F.91.E9.80.81.E6.8F.90.E7.A4.BA.EF.BC.9Aunauthorizedoperation.smssdkappidverifyfail-.E5.A6.82.E4.BD.95.E5.A4.84.E7.90.86.EF.BC.9F)
  92. * [UnsupportedOperation.ContainDomesticAndInternationalPhoneNumber](https://cloud.tencent.com/document/product/382/9558#.E7.9F.AD.E4.BF.A1.E5.8F.91.E9.80.81.E6.8F.90.E7.A4.BA.EF.BC.9Aunsupportedoperation.containdomesticandinternationalphonenumber-.E5.A6.82.E4.BD.95.E5.A4.84.E7.90.86.EF.BC.9F)
  93. * 更多错误,可咨询[腾讯云助手](https://tccc.qcloud.com/web/im/index.html#/chat?webAppId=8fa15978f85cb41f7e2ea36920cb3ae1&title=Sms)
  94. */
  95. } catch (TencentCloudSDKException e) {
  96. e.printStackTrace();
  97. throw new RuntimeException(e.getMessage());
  98. }
  99. }
  100. }

3.SmsComfig配置类

  1. package com.wanuw.common.config.tencent;
  2. import lombok.Data;
  3. import org.springframework.boot.context.properties.ConfigurationProperties;
  4. import org.springframework.context.annotation.Configuration;
  5. @ConfigurationProperties(prefix = "tencent.sms")
  6. @Configuration
  7. @Data
  8. public class SmsConfig {
  9. /**
  10. * 腾讯云API密钥的SecretId
  11. */
  12. private String secretId;
  13. /**
  14. * 腾讯云API密钥的SecretKey
  15. */
  16. private String secretKey;
  17. /**
  18. * 短信应用的SDKAppID
  19. */
  20. private String appId;
  21. /**
  22. * 签名内容
  23. */
  24. private String sign;
  25. /**
  26. * 模板ID
  27. */
  28. private String templateId;
  29. /**
  30. * 过期时间
  31. */
  32. private Integer expireTime;
  33. /**
  34. * 缓存前缀
  35. */
  36. private String phonePrefix;
  37. }

4.腾讯云yml配置

根据自己腾讯云实际情况填写,下面只是个样子,*为加密

  1. tencent:
  2. sms:
  3. # 配置腾讯云API密钥的SecretId
  4. secretId: ********************************
  5. # 配置腾讯云API密钥的SecretKey
  6. secretKey: ******************************
  7. # 配置短信应用的SDKAppID
  8. appId: 1400*****
  9. # 配置签名内容
  10. sign: "******"
  11. # 配置模板ID
  12. templateId: 19*****
  13. # 配置过期时间
  14. expireTime: 5
  15. # 配置redis存储的key的前缀
  16. phonePrefix: tel_captcha_codes

测试:测试工具为Apifox

1.发送短信验证码

2.收取到的验证码

3.验证验证码,获取token

4.使用token获取数据

=============================结束================================

附言:

        本人是个新手,不懂的还有很多,若是有不完善或者不对的地方可以留言提醒,谢谢!

感谢:

参考文章链接:https://blog.csdn.net/yyongsheng/article/details/127584458

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/408006
推荐阅读
相关标签
  

闽ICP备14008679号