若依前后端分离版ruoyi-vue:增加新的登录接口(新用户表),用于小程序或者APP获取token,并使用若依的验证方法,结合腾讯云短信验证码实现手机号+验证码登陆
1.新建—SmsController类
package com.wanuw.user.controller.login;
import com.wanuw.common.constant.Constants;
import com.wanuw.common.core.domain.AjaxResult;
import com.wanuw.user.service.SmsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
/**
* 手机端验证码
*
* @author dagang
*/
@RestController
@RequestMapping("/sms")
public class SmsController
{
@Autowired
private SmsService smsService;
/**
* 生成手机验证码
*/
@PostMapping("/send")
public AjaxResult sendSmsCode(@RequestParam(value = "phoneNumber") String phoneNumber) {
String message = smsService.sendSmsCode(phoneNumber);
return AjaxResult.success(message);
}
/**
* 验证手机验证码
*/
@PostMapping("/verify")
public AjaxResult verifySmsCode(@RequestParam(value = "phoneNumber") String phoneNumber,
@RequestParam(value = "smsCode") String smsCode) {
AjaxResult ajax = AjaxResult.success();
String token = smsService.verifySmsCode(phoneNumber, smsCode);
ajax.put(Constants.TOKEN, token);
return ajax;
}
}
2.新建—SmsService类
package com.wanuw.user.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.wanuw.common.core.domain.user.member.DbUser;
/**
* 手机端用户登录验证
*
* @author dagang
*/
public interface SmsService extends IService<DbUser> {
/**
* 生成手机验证码
*/
String sendSmsCode(String phoneNumber);
/**
* 验证手机验证码
*/
String verifySmsCode(String phoneNumber, String smsCode);
}
3.新建—SmsServiceImpl 实现层
此处注意注入的是:AppAuthenticationProvider
TokenService和RedisCache是若依框架自带
package com.wanuw.user.service.impl;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tencentcloudapi.sms.v20190711.models.SendStatus;
import com.wanuw.common.config.tencent.SmsConfig;
import com.wanuw.common.constant.CacheConstants;
import com.wanuw.common.constant.Constants;
import com.wanuw.common.core.domain.model.LoginUser;
import com.wanuw.common.core.redis.RedisCache;
import com.wanuw.common.exception.ServiceException;
import com.wanuw.common.exception.user.CaptchaException;
import com.wanuw.common.exception.user.CaptchaExpireException;
import com.wanuw.common.exception.user.UserNotExistsException;
import com.wanuw.common.exception.user.UserPasswordNotMatchException;
import com.wanuw.common.utils.ChineseNameUtils;
import com.wanuw.common.utils.MessageUtils;
import com.wanuw.common.utils.SecurityUtils;
import com.wanuw.common.utils.tencent.SmsUtil;
import com.wanuw.framework.manager.AsyncManager;
import com.wanuw.framework.manager.factory.AsyncFactory;
import com.wanuw.framework.web.service.TokenService;
import com.wanuw.common.core.domain.user.member.DbUser;
import com.wanuw.member.mapper.DbUserMapper;
import com.wanuw.member.service.IDbUserService;
import com.wanuw.user.controller.login.AppAuthenticationProvider;
import com.wanuw.user.service.SmsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;
/**
* 手机端用户登录验证
*
* @author dagang
*/
@Service
public class SmsServiceImpl extends ServiceImpl<DbUserMapper, DbUser> implements SmsService {
@Autowired
private TokenService tokenService;
@Resource
private AppAuthenticationProvider authenticationManager;
@Resource
private SmsConfig smsConfig;
@Autowired
private RedisCache redisCache;
@Autowired
private IDbUserService dbUserService;
/**
* 创建手机验证码
*/
@Override
public String sendSmsCode(String phoneNumber) {
// 下发手机号码,采用e.164标准,+[国家或地区码][手机号]
String[] phoneNumbers = {"+86" + phoneNumber};
// 生成6位随机数字字符串
String smsCode = RandomUtil.randomNumbers(6);
// 模板参数:若无模板参数,则设置为空(参数1为随机验证码,参数2为有效时间)
String[] templateParams = {smsCode, smsConfig.getExpireTime().toString()};
// 发送短信验证码
SendStatus[] sendStatuses = SmsUtil.sendSms(smsConfig, templateParams, phoneNumbers);
if ("Ok".equals(sendStatuses[0].getCode())) {
// 创建短信验证码缓存的key并设置过期时间
String key = CacheConstants.CAPTCHA_TELPHONE_CODE_KEY + phoneNumber;
redisCache.setCacheObject(key, smsCode, smsConfig.getExpireTime(), TimeUnit.MINUTES);
return "验证码发送成功";
} else {
return "验证码发送失败:" + sendStatuses[0].getMessage();
//return "验证码发送失败:";
}
}
/**
* 验证手机验证码
*/
@Override
public String verifySmsCode(String phoneNumber, String smsCode) {
//1.验证码校验
checkCode(phoneNumber, smsCode);
//2.检查用户手机号是否已经注册,若未注册,直接注册成用户
LambdaQueryWrapper<DbUser> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(DbUser::getUserTel, phoneNumber);
DbUser dbUser = dbUserService.getOne(queryWrapper);
if (dbUser == null) {
//说明未注册过账户,开始注册账户
DbUser dbUserNew = new DbUser();
dbUserNew.setUserTel(phoneNumber);
//添加默认密码123456
dbUserNew.setPassword(SecurityUtils.encryptPassword("123456"));
//这是个生成随机汉字名字的工具
dbUserNew.setUserNickname(ChineseNameUtils.randomChineseName());
dbUserNew.setUserName(phoneNumber);
dbUserService.save(dbUserNew);
}
String username = phoneNumber;
String password = "123456";
//自定义用户名和密码
// 用户验证
Authentication authentication;
try {
// 原来其实就这么一句话:该方法会去调用UserDetailsServiceImpl.loadUserByUsername。指的是原来若依自定义的UserDetailsServiceImpl
//此处会让人很迷惑,特别是对新手来说。其实就是调用了AppUserDetailsServiceImpl中的loadUserByUsername方法
//而这个方法的是通过AppAuthenticationProvider中去发起的。所以这个authenticationManager 其实就是注入的AppAuthenticationProvider
//这个地方一定要注意!!!!!
authentication = authenticationManager
.authenticate(new UsernamePasswordAuthenticationToken(username, password));
} catch (Exception e) {
if (e instanceof BadCredentialsException) {
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
throw new UserPasswordNotMatchException();
} else {
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
throw new ServiceException(e.getMessage());
}
}
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
LoginUser loginUser = (LoginUser) authentication.getPrincipal();
//recordLoginInfo(dbUser.getId());
// 生成token
return tokenService.createToken(loginUser);
}
/**
*
* @param phoneNumber 电话号码
* @param smsCode 验证码
*/
public void checkCode(String phoneNumber, String smsCode) {
// 创建key
String key = CacheConstants.CAPTCHA_TELPHONE_CODE_KEY + phoneNumber;
String captcha = redisCache.getCacheObject(key);
//校验传入数据是否为空
if (phoneNumber == null || smsCode == null) {
AsyncManager.me().execute(AsyncFactory.recordLogininfor(phoneNumber, Constants.LOGIN_FAIL, MessageUtils.message("not.null")));
throw new UserNotExistsException();
}
//校验验证码位数
if (smsCode.length() != 6) {
AsyncManager.me().execute(AsyncFactory.recordLogininfor(phoneNumber, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
throw new UserPasswordNotMatchException();
}
// 判断指定key是否存在并且未过期
if (captcha == null)
{
AsyncManager.me().execute(AsyncFactory.recordLogininfor(phoneNumber, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")));
throw new CaptchaExpireException();
}
// 验证输入的验证码是否正确
if (!smsCode.equalsIgnoreCase(captcha))
{
AsyncManager.me().execute(AsyncFactory.recordLogininfor(phoneNumber, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
throw new CaptchaException();
}
// 验证成功后删除验证码缓存
redisCache.deleteObject(key);
}
}
4.新建—AppUserDetailsServiceImpl类
package com.wanuw.user.controller.login;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.wanuw.common.core.domain.model.LoginUser;
import com.wanuw.common.exception.ServiceException;
import com.wanuw.common.utils.StringUtils;
import com.wanuw.common.core.domain.user.member.DbUser;
import com.wanuw.member.mapper.DbUserMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
/**
* 手机端验证码
*
* @author dagang
*/
@Slf4j
@Service
public class AppUserDetailsServiceImpl implements UserDetailsService {
@Autowired
private DbUserMapper dbUserMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//验证登录用户,使用的是mybatis-plus语法查询的用户数据
//因为是手机号登录,上面形参其实是手机号码,可以改成phone,本人偷懒,未改
DbUser dbUser = dbUserMapper.selectOne(new LambdaQueryWrapper<DbUser>()
.eq(DbUser::getUserTel, username));
if (StringUtils.isNull(dbUser)) {
log.info("登录用户:{} 不存在.", username);
throw new ServiceException("登录用户:" + username + " 不存在");
} else if (dbUser.getDeleted() == 1) {
log.info("登录用户:{} 已被删除.", username);
throw new ServiceException("对不起,您的账号:" + username + " 已被删除");
} else if (dbUser.getUserStatus() == 1) {
log.info("登录用户:{} 已被停用.", username);
throw new ServiceException("对不起,您的账号:" + username + " 已停用");
}
//返回UserDetails用户对象
return createLoginUser(dbUser);
}
public UserDetails createLoginUser(DbUser dbUser) {
/**
* 参数一:第一个是用户的ID,用户后期使用SecurityUtils.getUserId()时获取上下文中存储的用户ID数据,若未设置,SecurityUtils.getUserId()获取数据位null
* 参数二:整个用户数据传入,后面会保存在Redis中,登陆校验时会用到
*/
return new LoginUser(dbUser.getId(),dbUser);
}
}
5.新建—AppAuthenticationProvider
package com.wanuw.user.controller.login;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import java.util.Collection;
/**
* 手机端验证码
*
* @author dagang
*/
@Slf4j
@Component
public class AppAuthenticationProvider implements AuthenticationProvider {
@Autowired
private AppUserDetailsServiceImpl userDetailsService;
@SneakyThrows
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
// 这个获取表单输入中返回的用户名,此处获取到的是手机号码
String userName = authentication.getName();
// 这里构建来判断用户是否存在和密码是否正确
// 这里调用我们的自己写的AppUserDetailsServiceImpl获取用户的方法;
UserDetails userInfo = userDetailsService.loadUserByUsername(userName);
Collection<? extends GrantedAuthority> authorities = userInfo.getAuthorities();
// 构建返回的用户登录成功的token
return new UsernamePasswordAuthenticationToken(userInfo, userInfo.getPassword(), authorities);
}
@Override
public boolean supports(Class<?> authentication) {
//return authentication.equals(UsernamePasswordAuthenticationToken.class);
// 这里直接改成 return true;表示是支持这个执行
return true;
}
}
6.修改—LoginUser
路径:src/main/java/com/wanuw/common/core/domain/model/LoginUser.java
添加新用户表实体类,一定要添加Getter和Setter,之前未添加导致存入Redis后没有用户实体类的信息,查找了好久,主要是我水平有限,可能水平高的人一下就会找到原因了。
package com.wanuw.common.core.domain.model;
import com.alibaba.fastjson2.annotation.JSONField;
import com.wanuw.common.core.domain.entity.SysUser;
import com.wanuw.common.core.domain.user.member.DbUser;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
import java.util.Set;
/**
* 登录用户身份权限
*
* @author ruoyi
*/
public class LoginUser implements UserDetails
{
private static final long serialVersionUID = 1L;
/**
* 用户ID
*/
private Long userId;
/**
* 部门ID
*/
private Long deptId;
/**
* 用户唯一标识
*/
private String token;
/**
* 登录时间
*/
private Long loginTime;
/**
* 过期时间
*/
private Long expireTime;
/**
* 登录IP地址
*/
private String ipaddr;
/**
* 登录地点
*/
private String loginLocation;
/**
* 浏览器类型
*/
private String browser;
/**
* 操作系统
*/
private String os;
/**
* 权限列表
*/
private Set<String> permissions;
/**
* 用户信息
*/
private SysUser user;
/**
* App用户数据
*/
private DbUser dbUser;
public DbUser getDbUser() {
return dbUser;
}
public void setDbUser(DbUser dbUser) {
this.dbUser = dbUser;
}
@JSONField(serialize = false)
@Override
public String getPassword()
{
if (user != null) {
return user.getPassword();
} else {
return dbUser.getPassword();
}
}
@Override
public String getUsername()
{
if (user != null) {
return user.getUserName();
} else {
return dbUser.getUserTel();
}
}
public LoginUser(Long userId, DbUser dbUser)
{
this.userId = userId;
this.dbUser = dbUser;
}
public LoginUser()
{
}
public LoginUser(SysUser user, Set<String> permissions)
{
this.user = user;
this.permissions = permissions;
}
public LoginUser(DbUser dbUser)
{
this.dbUser = dbUser;
}
public LoginUser(Long userId, Long deptId, SysUser user, Set<String> permissions)
{
this.userId = userId;
this.deptId = deptId;
this.user = user;
this.permissions = permissions;
}
public Long getUserId()
{
return userId;
}
public void setUserId(Long userId)
{
this.userId = userId;
}
public Long getDeptId()
{
return deptId;
}
public void setDeptId(Long deptId)
{
this.deptId = deptId;
}
public String getToken()
{
return token;
}
public void setToken(String token)
{
this.token = token;
}
/**
* 账户是否未过期,过期无法验证
*/
@JSONField(serialize = false)
@Override
public boolean isAccountNonExpired()
{
return true;
}
/**
* 指定用户是否解锁,锁定的用户无法进行身份验证
*
* @return
*/
@JSONField(serialize = false)
@Override
public boolean isAccountNonLocked()
{
return true;
}
/**
* 指示是否已过期的用户的凭据(密码),过期的凭据防止认证
*
* @return
*/
@JSONField(serialize = false)
@Override
public boolean isCredentialsNonExpired()
{
return true;
}
/**
* 是否可用 ,禁用的用户不能身份验证
*
* @return
*/
@JSONField(serialize = false)
@Override
public boolean isEnabled()
{
return true;
}
public Long getLoginTime()
{
return loginTime;
}
public void setLoginTime(Long loginTime)
{
this.loginTime = loginTime;
}
public String getIpaddr()
{
return ipaddr;
}
public void setIpaddr(String ipaddr)
{
this.ipaddr = ipaddr;
}
public String getLoginLocation()
{
return loginLocation;
}
public void setLoginLocation(String loginLocation)
{
this.loginLocation = loginLocation;
}
public String getBrowser()
{
return browser;
}
public void setBrowser(String browser)
{
this.browser = browser;
}
public String getOs()
{
return os;
}
public void setOs(String os)
{
this.os = os;
}
public Long getExpireTime()
{
return expireTime;
}
public void setExpireTime(Long expireTime)
{
this.expireTime = expireTime;
}
public Set<String> getPermissions()
{
return permissions;
}
public void setPermissions(Set<String> permissions)
{
this.permissions = permissions;
}
public SysUser getUser()
{
return user;
}
public void setUser(SysUser user)
{
this.user = user;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities()
{
return null;
}
}
截图注意项:
7.修改—解决运行冲突
路径:src/main/java/com/wanuw/framework/config/SecurityConfig.java
添加注解:@Qualifier("userDetailsServiceImpl")
此时启动项目不会报冲突的错,其实就是给起了一个不冲突的名字
千万千万要添加!!!
此时已经添加完成了。可以启动测试了!
==============================分割线===================================
附上:
1.DbUser实体类,做参考
package com.wanuw.common.core.domain.user.member;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import com.wanuw.common.annotation.Excel;
import com.wanuw.common.core.domain.BaseEntity;
import lombok.*;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* 会员对象 db_user
*
* @author dagang
* @date 2023-11-09
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
@TableName("db_user")
public class DbUser extends BaseEntity {
private static final long serialVersionUID = 1L;
/**
* 会员主键
*/
@TableId(value = "id")
private Long id;
/**
* 用户名
*/
@TableField(value = "user_name")
@Excel(name = "用户名")
private String userName;
/**
* 手机号
*/
@TableField(value = "user_tel")
@Excel(name = "手机号")
private String userTel;
/**
* 密码
*/
@TableField(value = "password")
private String password;
/**
* 推广号(不能重复 无上级默认1010110)
*/
@TableField(value = "user_code")
private String userCode;
/**
* 用户昵称(注册时随机字母)
*/
@TableField(value = "user_nickname")
private String userNickname;
/**
* 头像
*/
@TableField(value = "user_image")
private String userImage;
/**
* 性别
*/
@TableField(value = "user_sex")
private Integer userSex;
/**
* 所在地(辽宁,沈阳)
*/
@TableField(value = "user_adddress")
private String userAdddress;
/**
* 会员简介
*/
@TableField(value = "user_text")
private String userText;
}
2.腾讯短信工具类SmsUtils
package com.wanuw.common.utils.tencent;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.HttpProfile;
import com.tencentcloudapi.sms.v20190711.SmsClient;
import com.tencentcloudapi.sms.v20190711.models.SendSmsRequest;
import com.tencentcloudapi.sms.v20190711.models.SendSmsResponse;
import com.tencentcloudapi.sms.v20190711.models.SendStatus;
import com.wanuw.common.config.tencent.SmsConfig;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class SmsUtil {
public static SendStatus[] sendSms(SmsConfig smsConfig, String[] templateParams, String[] phoneNumbers) {
try {
/* 必要步骤:
* 实例化一个认证对象,入参需要传入腾讯云账户密钥对secretId,secretKey。
* 这里采用的是从环境变量读取的方式,需要在环境变量中先设置这两个值。
* 您也可以直接在代码中写死密钥对,但是小心不要将代码复制、上传或者分享给他人,
* 以免泄露密钥对危及您的财产安全。
* SecretId、SecretKey 查询: https://console.cloud.tencent.com/cam/capi */
Credential cred = new Credential(smsConfig.getSecretId(), smsConfig.getSecretKey());
// 实例化一个http选项,可选,没有特殊需求可以跳过
HttpProfile httpProfile = new HttpProfile();
// 设置代理(无需要直接忽略)
// httpProfile.setProxyHost("真实代理ip");
// httpProfile.setProxyPort(真实代理端口);
/* SDK默认使用POST方法。
* 如果您一定要使用GET方法,可以在这里设置。GET方法无法处理一些较大的请求 */
httpProfile.setReqMethod("POST");
/* SDK有默认的超时时间,非必要请不要进行调整
* 如有需要请在代码中查阅以获取最新的默认值 */
httpProfile.setConnTimeout(60);
/* 指定接入地域域名,默认就近地域接入域名为 sms.tencentcloudapi.com ,也支持指定地域域名访问,例如广州地域的域名为 sms.ap-guangzhou.tencentcloudapi.com */
httpProfile.setEndpoint("sms.tencentcloudapi.com");
/* 非必要步骤:
* 实例化一个客户端配置对象,可以指定超时时间等配置 */
ClientProfile clientProfile = new ClientProfile();
/* SDK默认用TC3-HMAC-SHA256进行签名
* 非必要请不要修改这个字段 */
clientProfile.setSignMethod("HmacSHA256");
clientProfile.setHttpProfile(httpProfile);
/* 实例化要请求产品(以sms为例)的client对象
* 第二个参数是地域信息,可以直接填写字符串ap-guangzhou,支持的地域列表参考 https://cloud.tencent.com/document/api/382/52071#.E5.9C.B0.E5.9F.9F.E5.88.97.E8.A1.A8 */
SmsClient client = new SmsClient(cred, "ap-guangzhou",clientProfile);
/* 实例化一个请求对象,根据调用的接口和实际情况,可以进一步设置请求参数
* 您可以直接查询SDK源码确定接口有哪些属性可以设置
* 属性可能是基本类型,也可能引用了另一个数据结构
* 推荐使用IDE进行开发,可以方便的跳转查阅各个接口和数据结构的文档说明 */
SendSmsRequest req = new SendSmsRequest();
/* 填充请求参数,这里request对象的成员变量即对应接口的入参
* 您可以通过官网接口文档或跳转到request对象的定义处查看请求参数的定义
* 基本类型的设置:
* 帮助链接:
* 短信控制台: https://console.cloud.tencent.com/smsv2
* 腾讯云短信小助手: https://cloud.tencent.com/document/product/382/3773#.E6.8A.80.E6.9C.AF.E4.BA.A4.E6.B5.81 */
/* 短信应用ID: 短信SdkAppId在 [短信控制台] 添加应用后生成的实际SdkAppId,示例如1400006666 */
// 应用 ID 可前往 [短信控制台](https://console.cloud.tencent.com/smsv2/app-manage) 查看
req.setSmsSdkAppid(smsConfig.getAppId());
/* 短信签名内容: 使用 UTF-8 编码,必须填写已审核通过的签名 */
// 签名信息可前往 [国内短信](https://console.cloud.tencent.com/smsv2/csms-sign) 或 [国际/港澳台短信](https://console.cloud.tencent.com/smsv2/isms-sign) 的签名管理查看
req.setSign(smsConfig.getSign());
/* 模板 ID: 必须填写已审核通过的模板 ID */
// 模板 ID 可前往 [国内短信](https://console.cloud.tencent.com/smsv2/csms-template) 或 [国际/港澳台短信](https://console.cloud.tencent.com/smsv2/isms-template) 的正文模板管理查看
req.setTemplateID(smsConfig.getTemplateId());
/* 模板参数: 模板参数的个数需要与 TemplateId 对应模板的变量个数保持一致,若无模板参数,则设置为空 */
req.setTemplateParamSet(templateParams);
/* 下发手机号码,采用 E.164 标准,+[国家或地区码][手机号]
* 示例如:+8613711112222, 其中前面有一个+号 ,86为国家码,13711112222为手机号,最多不要超过200个手机号 */
req.setPhoneNumberSet(phoneNumbers);
/* 用户的 session 内容(无需要可忽略): 可以携带用户侧 ID 等上下文信息,server 会原样返回 */
String sessionContext = "";
req.setSessionContext(sessionContext);
/* 短信码号扩展号(无需要可忽略): 默认未开通,如需开通请联系 [腾讯云短信小助手] */
String extendCode = "";
req.setExtendCode(extendCode);
/* 国内短信无需填写该项;国际/港澳台短信已申请独立 SenderId 需要填写该字段,默认使用公共 SenderId,无需填写该字段。注:月度使用量达到指定量级可申请独立 SenderId 使用,详情请联系 [腾讯云短信小助手](https://cloud.tencent.com/document/product/382/3773#.E6.8A.80.E6.9C.AF.E4.BA.A4.E6.B5.81)。*/
String senderid = "";
req.setSenderId(senderid);
/* 通过 client 对象调用 SendSms 方法发起请求。注意请求方法名与请求对象是对应的
* 返回的 res 是一个 SendSmsResponse 类的实例,与请求对象对应 */
SendSmsResponse res = client.SendSms(req);
// 输出json格式的字符串回包
log.info("json格式字符串返回包:{}", SendSmsResponse.toJsonString(res));
return res.getSendStatusSet();
// 也可以取出单个值,您可以通过官网接口文档或跳转到response对象的定义处查看返回字段的定义
// System.out.println(res.getRequestId());
/* 当出现以下错误码时,快速解决方案参考
* [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)
* [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)
* [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)
* [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)
* 更多错误,可咨询[腾讯云助手](https://tccc.qcloud.com/web/im/index.html#/chat?webAppId=8fa15978f85cb41f7e2ea36920cb3ae1&title=Sms)
*/
} catch (TencentCloudSDKException e) {
e.printStackTrace();
throw new RuntimeException(e.getMessage());
}
}
}
3.SmsComfig配置类
package com.wanuw.common.config.tencent;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@ConfigurationProperties(prefix = "tencent.sms")
@Configuration
@Data
public class SmsConfig {
/**
* 腾讯云API密钥的SecretId
*/
private String secretId;
/**
* 腾讯云API密钥的SecretKey
*/
private String secretKey;
/**
* 短信应用的SDKAppID
*/
private String appId;
/**
* 签名内容
*/
private String sign;
/**
* 模板ID
*/
private String templateId;
/**
* 过期时间
*/
private Integer expireTime;
/**
* 缓存前缀
*/
private String phonePrefix;
}
4.腾讯云yml配置
根据自己腾讯云实际情况填写,下面只是个样子,*为加密
tencent:
sms:
# 配置腾讯云API密钥的SecretId
secretId: ********************************
# 配置腾讯云API密钥的SecretKey
secretKey: ******************************
# 配置短信应用的SDKAppID
appId: 1400*****
# 配置签名内容
sign: "******"
# 配置模板ID
templateId: 19*****
# 配置过期时间
expireTime: 5
# 配置redis存储的key的前缀
phonePrefix: tel_captcha_codes
测试:测试工具为Apifox
1.发送短信验证码
2.收取到的验证码
3.验证验证码,获取token
4.使用token获取数据
=============================结束================================
附言:
本人是个新手,不懂的还有很多,若是有不完善或者不对的地方可以留言提醒,谢谢!
感谢:
参考文章链接:https://blog.csdn.net/yyongsheng/article/details/127584458