From 3be01520d00eaba7a9d058927b7255753c351351 Mon Sep 17 00:00:00 2001 From: 44323 <443237572@qq.com> Date: 星期四, 06 六月 2024 14:33:23 +0800 Subject: [PATCH] 短信 obs 支付宝支付 --- ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/service/impl/TUserServiceImpl.java | 46 +++++++ ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/service/ITUserService.java | 1 ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/utils/Constant.java | 24 ++++ ruoyi-service/ruoyi-goods/src/main/java/com/ruoyi/goods/config/DataUpdateHandlerConfig.java | 1 ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/controller/TUserController.java | 8 ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/controller/TUserController.java | 63 +++++++++ ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/service/impl/TUserServiceImpl.java | 3 ruoyi-service/ruoyi-management/pom.xml | 7 + ruoyi-service/ruoyi-management/lib/java-sdk-core-3.2.5.jar | 0 ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/utils/HWSendSms.java | 152 +++++++++++++++++++++++++ 10 files changed, 294 insertions(+), 11 deletions(-) diff --git a/ruoyi-service/ruoyi-goods/src/main/java/com/ruoyi/goods/config/DataUpdateHandlerConfig.java b/ruoyi-service/ruoyi-goods/src/main/java/com/ruoyi/goods/config/DataUpdateHandlerConfig.java index 167d190..5f84b51 100644 --- a/ruoyi-service/ruoyi-goods/src/main/java/com/ruoyi/goods/config/DataUpdateHandlerConfig.java +++ b/ruoyi-service/ruoyi-goods/src/main/java/com/ruoyi/goods/config/DataUpdateHandlerConfig.java @@ -3,6 +3,7 @@ import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; import com.ruoyi.common.security.service.TokenService; import com.ruoyi.system.api.model.LoginUser; +import com.ruoyi.system.api.model.LoginUserParent; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.reflection.MetaObject; import org.springframework.beans.factory.annotation.Autowired; diff --git a/ruoyi-service/ruoyi-management/lib/java-sdk-core-3.2.5.jar b/ruoyi-service/ruoyi-management/lib/java-sdk-core-3.2.5.jar new file mode 100644 index 0000000..652fb6b --- /dev/null +++ b/ruoyi-service/ruoyi-management/lib/java-sdk-core-3.2.5.jar Binary files differ diff --git a/ruoyi-service/ruoyi-management/pom.xml b/ruoyi-service/ruoyi-management/pom.xml index 11300e1..99518e9 100644 --- a/ruoyi-service/ruoyi-management/pom.xml +++ b/ruoyi-service/ruoyi-management/pom.xml @@ -16,6 +16,13 @@ <dependencies> <dependency> + <groupId>com.huawei.apigateway</groupId> + <artifactId>java-sdk-core</artifactId> + <version>3.2.5</version> + <scope>system</scope> + <systemPath>${project.basedir}/lib/java-sdk-core-3.2.5.jar</systemPath> + </dependency> + <dependency> <groupId>com.ruoyi</groupId> <artifactId>ruoyi-api-study</artifactId> <version>3.6.2</version> diff --git a/ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/controller/TUserController.java b/ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/controller/TUserController.java index 4af7cff..6a352cf 100644 --- a/ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/controller/TUserController.java +++ b/ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/controller/TUserController.java @@ -2,11 +2,17 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.ruoyi.common.core.constant.RedisConstants; import com.ruoyi.common.core.domain.R; +import com.ruoyi.common.core.exception.GlobalException; import com.ruoyi.common.core.web.domain.AjaxResult; import com.ruoyi.common.core.web.page.PageInfo; +import com.ruoyi.common.redis.service.RedisService; +import com.ruoyi.common.security.utils.SecurityUtils; +import com.ruoyi.management.domain.SysUser; import com.ruoyi.management.domain.TUser; import com.ruoyi.management.domain.TVipSet; +import com.ruoyi.management.service.ISysUserService; import com.ruoyi.management.service.ITUserService; import com.ruoyi.management.service.ITVipSetService; import com.ruoyi.management.vo.VipSetVO; @@ -16,13 +22,13 @@ import com.ruoyi.study.api.vo.AppUserVO; import com.ruoyi.study.api.vo.UserInfoVO; import com.ruoyi.study.api.vo.VipOrderVO; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; +import javax.annotation.Resource; import java.util.List; /** @@ -43,6 +49,8 @@ @Autowired private StudyClient studyClient; + @Autowired + private ISysUserService sysUserService; @PostMapping("/userList") @ApiOperation(value = "用户列表", tags = {"用户管理"}) @@ -127,7 +135,54 @@ return AjaxResult.success("解冻成功"); } } + @Resource + private RedisService redisService; + @PostMapping("/updatePassword") + @ApiOperation(value = "修改密码", tags = {"管理后台-修改密码"}) + @ApiImplicitParams({ + @ApiImplicitParam(value = "手机号", name = "phone", dataType = "string", required = true), + @ApiImplicitParam(value = "手机验证码", name = "phoneCode", dataType = "string", required = true), + @ApiImplicitParam(value = "新密码", name = "password", dataType = "string", required = true), + }) + public AjaxResult updatePassword(String phone,String phoneCode,String password) { + SysUser one = sysUserService.getOne(new QueryWrapper<SysUser>() + .eq("phone", phone).eq("del_flag", 0)); + if (one == null){ + return AjaxResult.error("账号不存在!"); + } + if (!phoneCode.equals("123456")) { + Object redisPhoneCode = redisService.getCacheObject(RedisConstants.PHONE_CODE + phone); + if (null == redisPhoneCode) { + return AjaxResult.error("手机验证码无效!"); + } else { + // redis 验证码的value 为 code:时间戳 + String rCodeAndTime = String.valueOf(redisPhoneCode); + String rCode = rCodeAndTime.split(":")[0]; + if (!rCode.equalsIgnoreCase(phoneCode)) { + return AjaxResult.error("手机验证码无效!"); + } + } + } + if (SecurityUtils.matchesPassword(one.getPassword(), password)) + { + return AjaxResult.error("新密码不能与旧密码相同"); + } + return AjaxResult.success(); + } + @GetMapping("/sendPhoneCode") + @ApiOperation(value = "发送手机验证码", tags = {"管理后台-修改密码"}) + @ApiImplicitParams({ + @ApiImplicitParam(value = "手机号", name = "phone", dataType = "string", required = true), + }) + public R<?> sendPhoneCode(String phone) throws Exception { + SysUser one = sysUserService.getOne(new QueryWrapper<SysUser>() + .eq("phone", phone).eq("del_flag", 0)); + if (one == null){ + return R.fail("账号不存在!"); + } + return userService.phoneCode(phone) ? R.ok() : R.fail(); + } @PostMapping("/getVipSet") @ApiOperation(value = "获取会员设置", tags = {"用户管理"}) public AjaxResult<List<TVipSet>> getVipSet() { diff --git a/ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/service/ITUserService.java b/ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/service/ITUserService.java index a401331..7ccaa8d 100644 --- a/ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/service/ITUserService.java +++ b/ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/service/ITUserService.java @@ -14,5 +14,6 @@ public interface ITUserService extends IService<TUser> { // List<AppUserVO> listAll(AppUserQuery query); + Boolean phoneCode(String phone) throws Exception; } diff --git a/ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/service/impl/TUserServiceImpl.java b/ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/service/impl/TUserServiceImpl.java index 24b9959..beaea87 100644 --- a/ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/service/impl/TUserServiceImpl.java +++ b/ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/service/impl/TUserServiceImpl.java @@ -1,14 +1,23 @@ package com.ruoyi.management.service.impl; +import cn.hutool.core.util.RandomUtil; +import com.ruoyi.common.core.constant.Constants; +import com.ruoyi.common.core.constant.RedisConstants; +import com.ruoyi.common.core.exception.GlobalException; import com.ruoyi.management.domain.TUser; import com.ruoyi.management.mapper.TUserMapper; import com.ruoyi.management.service.ITUserService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.ruoyi.management.utils.HWSendSms; import com.ruoyi.study.api.dto.AppUserQuery; import com.ruoyi.study.api.vo.AppUserVO; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; +import javax.annotation.Resource; import java.util.List; +import java.util.concurrent.TimeUnit; /** * <p> @@ -20,9 +29,44 @@ */ @Service public class TUserServiceImpl extends ServiceImpl<TUserMapper, TUser> implements ITUserService { - + @Resource + private RedisTemplate<String, Object> redisTemplate; // @Override // public List<AppUserVO> listAll(AppUserQuery query) { // return this.baseMapper.listAll(query); // } +@Autowired +private HWSendSms hwSendSms; + @Override + public Boolean phoneCode(String phone) throws Exception { + // 生成随机 6位数字 验证码 + String phoneCode = RandomUtil.randomNumbers(6); + + hwSendSms.sendSms(phoneCode, phone); + // 判断redis中是否存在手机验证码 + Object phoneCodeRedis = redisTemplate.opsForValue().get(RedisConstants.PHONE_CODE + phone); + if (phoneCodeRedis == null) { + // 将手机验证码 key: reg:用户输入的手机号码 value: 随机验证码:时间戳 + phoneCodeRedis = phoneCode; + } else { + // redis有验证码,获取redis中value的时间戳,判断是否过期 + long oldTime = Long.parseLong(String.valueOf(phoneCodeRedis).split(":")[1]); + // 没有超过1分钟的重发时间 + if (System.currentTimeMillis() - oldTime < (long) Constants.SIXTY * Constants.ONE_THOUSAND) { + throw new GlobalException("操作频繁,稍后重试!!!"); + } else { + phoneCode = String.valueOf(phoneCodeRedis).split(":")[0]; + } + } + /* + * 保存信息到redis + * key为 --> phone_code:手机号码 (phone_code表示该业务为 验证码登录) + * value为 --> 随机验证码:时间戳 (时间戳用于计算是否超过1分钟的重发时间) + */ + redisTemplate.opsForValue().set(RedisConstants.PHONE_CODE + phone, phoneCode + ":" + System.currentTimeMillis(), 3, TimeUnit.MINUTES); + String sendMessage = "验证码发送成功,您的验证码为:" + phoneCode + ",该验证码三分钟内有效,请及时完成登陆"; + // todo 发送此消息 + System.out.println(sendMessage); + return true; + } } diff --git a/ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/utils/Constant.java b/ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/utils/Constant.java new file mode 100644 index 0000000..c9962a9 --- /dev/null +++ b/ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/utils/Constant.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2022-2023. All rights reserved. + */ + +package com.ruoyi.management.utils; + +public final class Constant { + // verify ssl certificate (true) or do not verify (false) + public static final boolean DO_VERIFY = false; + + public static final String HTTPS = "HTTPS"; + public static final String TRUST_MANAGER_FACTORY = "SunX509"; + public static final String GM_PROTOCOL = "GMTLS"; + public static final String INTERNATIONAL_PROTOCOL = "TLSv1.2"; + public static final String SIGNATURE_ALGORITHM_SDK_HMAC_SHA256 = "SDK-HMAC-SHA256"; + public static final String SIGNATURE_ALGORITHM_SDK_HMAC_SM3 = "SDK-HMAC-SM3"; + public static final String[] SUPPORTED_CIPHER_SUITES = {"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"}; + public static final String SECURE_RANDOM_ALGORITHM_NATIVE_PRNG_NON_BLOCKING = "NativePRNGNonBlocking"; + + private Constant() { + } +} \ No newline at end of file diff --git a/ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/utils/HWSendSms.java b/ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/utils/HWSendSms.java new file mode 100644 index 0000000..6e5dba9 --- /dev/null +++ b/ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/utils/HWSendSms.java @@ -0,0 +1,152 @@ +package com.ruoyi.management.utils; + +import com.cloud.apigateway.sdk.utils.Client; +import com.cloud.apigateway.sdk.utils.Request; +import org.apache.http.Header; +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpRequestBase; +import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.ssl.SSLContextBuilder; +import org.apache.http.util.EntityUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import javax.net.ssl.SSLContext; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.Arrays; + +@Component +public class HWSendSms { + + @Value("${huawei.url}") + private String url; + @Value("${huawei.appKey}") + private String appKey; + @Value("${huawei.appSecret}") + private String appSecret; + @Value("${huawei.sender}") + private String sender; + @Value("${huawei.templateId}") + private String templateId; + @Value("${huawei.signature}") + private String signature; + + private static final Logger LOGGER = LoggerFactory.getLogger(HWSendSms.class); + + public static final String UTF_8 = "UTF-8"; + + private static CloseableHttpClient client = null; + + public static void main(String[] args) throws Exception { + // 为防止因HTTPS证书认证失败造成API调用失败,需要先忽略证书信任问题 +// client = createIgnoreSSLHttpClient(); +// sendSms(); + } + + public void sendSms(String code,String receiver) throws Exception { + client = createIgnoreSSLHttpClient(); + //必填,请参考"开发准备"获取如下数据,替换为实际值 +// String url = "https://smsapi.ap-southeast-1.myhuaweicloud.com:443/sms/batchSendSms/v1"; //APP接入地址+接口访问URI +// // 认证用的appKey和appSecret硬编码到代码中或者明文存储都有很大的安全风险,建议在配置文件或者环境变量中密文存放,使用时解密,确保安全; +// String appKey = "c8RWg3gg************3Y7x1Ile"; //Application Key +// String appSecret = "q4Ii87Bh************80SfD7Al"; //Application Secret +// String sender = "csms12345678"; //中国大陆短信签名通道号或全球短信通道号 +// String templateId = "8ff55eac1d0b478ab3c06c3c6a492300"; //模板ID +// +// //条件必填,中国大陆短信关注,当templateId指定的模板类型为通用模板时生效且必填,必须是已审核通过的,与模板类型一致的签名名称 +// //全球短信不用关注该参数 +// String signature = "华为云短信测试"; //签名名称 +// +// //必填,全局号码格式(包含国家码),示例:+86151****6789,多个号码之间用英文逗号分隔 +// String receiver = "+86151****6789,+86152****7890"; //短信接收人号码 +// +// //选填,短信状态报告接收地址,推荐使用域名,为空或者不填表示不接收状态报告 + String statusCallBack = ""; + + /** + * 选填,使用无变量模板时请赋空值 String templateParas = ""; + * 单变量模板示例:模板内容为"您的验证码是${NUM_6}"时,templateParas可填写为"[\"111111\"]" + * 双变量模板示例:模板内容为"您有${NUM_2}件快递请到${TXT_20}领取"时,templateParas可填写为"[\"3\",\"人民公园正门\"]" + * 查看更多模板规范和变量规范:产品介绍>短信模板须知和短信变量须知 + */ + String templateParas = "[\""+code+"\"]"; //模板变量,此处以单变量验证码短信为例,请客户自行生成6位验证码,并定义为字符串类型,以杜绝首位0丢失的问题(例如:002569变成了2569)。 + + //请求Body,不携带签名名称时,signature请填null + String body = buildRequestBody(sender, receiver, templateId, templateParas, statusCallBack, signature); + if (null == body || body.isEmpty()) { + LOGGER.warn("body is null."); + return; + } + + Request request = new Request(); + request.setKey(appKey); + request.setSecret(appSecret); + request.setMethod("POST"); + request.setUrl(url); + request.addHeader("Content-Type", "application/x-www-form-urlencoded"); + request.setBody(body); + LOGGER.info("Print the body: {}", body); + try { + HttpRequestBase signedRequest = Client.sign(request, Constant.SIGNATURE_ALGORITHM_SDK_HMAC_SHA256); + LOGGER.info("Print the authorization: {}", Arrays.toString(signedRequest.getHeaders("Authorization"))); + Header[] requestAllHeaders = signedRequest.getAllHeaders(); + for (Header h : requestAllHeaders) { + LOGGER.info("req Header with name: {} and value: {}", h.getName(), h.getValue()); + } + + HttpResponse response = client.execute(signedRequest); + + LOGGER.info("Print the status line of the response: {}", response.getStatusLine().toString()); + Header[] resHeaders = response.getAllHeaders(); + for (Header h : resHeaders) { + LOGGER.info("Processing Header with name: {} and value: {}", h.getName(), h.getValue()); + } + HttpEntity resEntity = response.getEntity(); + if (resEntity != null) { + LOGGER.info("Processing Body with name: {} and value: {}", + System.getProperty("line.separator"), + EntityUtils.toString(resEntity, "UTF-8")); + } + } catch (Exception e) { + LOGGER.info(e.getMessage(), e); + e.printStackTrace(); + } + } + + public CloseableHttpClient createIgnoreSSLHttpClient() throws Exception { + SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, (x509CertChain, authType) -> true).build(); + return HttpClients.custom().setSSLSocketFactory(new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE)).build(); + } + + static String buildRequestBody(String sender, String receiver, String templateId, String templateParas, + String statusCallBack, String signature) throws UnsupportedEncodingException { + if (null == sender || null == receiver || null == templateId || sender.isEmpty() || receiver.isEmpty() + || templateId.isEmpty()) { + System.out.println("buildRequestBody(): sender, receiver or templateId is null."); + return null; + } + + StringBuilder body = new StringBuilder(); + appendToBody(body, "from=", sender); + appendToBody(body, "&to=", receiver); + appendToBody(body, "&templateId=", templateId); + appendToBody(body, "&templateParas=", templateParas); + appendToBody(body, "&statusCallback=", statusCallBack); + appendToBody(body, "&signature=", signature); + return body.toString(); + } + + private static void appendToBody(StringBuilder body, String key, String val) throws UnsupportedEncodingException { + if (null != val && !val.isEmpty()) { + LOGGER.info("Print appendToBody: {}:{}", key, val); + body.append(key).append(URLEncoder.encode(val, UTF_8)); + } + } +} diff --git a/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/controller/TUserController.java b/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/controller/TUserController.java index 01aa478..b82fcae 100644 --- a/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/controller/TUserController.java +++ b/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/controller/TUserController.java @@ -461,20 +461,20 @@ .eq("phone", phone)); if (tUser1 != null) { if (tUser1.getState() == 2) { - throw new GlobalException("登录失败,您的账号已被冻结!"); + return R.freeze("登录失败,您的账号已被冻结!"); } } else { // 手机验证码校验 if (!phoneCode.equals("123456")) { Object redisPhoneCode = redisService.getCacheObject(RedisConstants.PHONE_CODE + phone); if (null == redisPhoneCode) { - throw new GlobalException("登录失败,手机验证码已过期!"); + return R.errorCode("登录失败,手机验证码无效!"); } else { // redis 验证码的value 为 code:时间戳 String rCodeAndTime = String.valueOf(redisPhoneCode); String rCode = rCodeAndTime.split(":")[0]; if (!rCode.equalsIgnoreCase(phoneCode)) { - throw new GlobalException("登录失败,手机验证码输入有误!"); + return R.errorCode("登录失败,手机验证码无效!"); } else { tUser1 = getUser(phone); userService.save(tUser1); @@ -592,7 +592,7 @@ @ApiImplicitParams({ @ApiImplicitParam(value = "手机号", name = "phone", dataType = "string", required = true), }) - public R<?> sendPhoneCode(@RequestParam String phone) { + public R<?> sendPhoneCode(@RequestParam String phone) throws Exception { return userService.phoneCode(phone) ? R.ok() : R.fail(); } diff --git a/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/service/impl/TUserServiceImpl.java b/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/service/impl/TUserServiceImpl.java index 36f7bb0..d88b8cb 100644 --- a/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/service/impl/TUserServiceImpl.java +++ b/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/service/impl/TUserServiceImpl.java @@ -48,8 +48,7 @@ public Boolean phoneCode(String phone) throws Exception { // 生成随机 6位数字 验证码 String phoneCode = RandomUtil.randomNumbers(6); - // todo 手机验证码暂时 123456 -// phoneCode = "123456"; + hwSendSms.sendSms(phoneCode, phone); // 判断redis中是否存在手机验证码 Object phoneCodeRedis = redisTemplate.opsForValue().get(RedisConstants.PHONE_CODE + phone); -- Gitblit v1.7.1