From 07048dc1608c84651e7a46dfe89f03f376b22ab6 Mon Sep 17 00:00:00 2001 From: Helius <wangdoubleone@gmail.com> Date: Thu, 16 Sep 2021 15:24:04 +0800 Subject: [PATCH] add sms code verify --- src/main/java/cc/mrbird/febs/common/utils/RedisUtils.java | 549 ++++++++++++++++++++++++++ src/main/java/cc/mrbird/febs/common/utils/RequestEncoder.java | 71 +++ src/main/java/cc/mrbird/febs/mall/controller/CommonController.java | 71 +++ src/main/java/cc/mrbird/febs/common/utils/AppContants.java | 80 +++ src/main/java/cc/mrbird/febs/common/utils/ZzSmsSend.java | 68 +++ src/main/java/cc/mrbird/febs/mall/service/CommonService.java | 32 + pom.xml | 41 + src/main/java/cc/mrbird/febs/common/configure/WebMvcConfigure.java | 23 + src/main/java/cc/mrbird/febs/common/interceptor/LoginInterceptor.java | 97 ++++ src/main/java/cc/mrbird/febs/common/utils/SubMailSend.java | 169 ++++++++ 10 files changed, 1,201 insertions(+), 0 deletions(-) diff --git a/pom.xml b/pom.xml index a84b44e..3ca16cf 100644 --- a/pom.xml +++ b/pom.xml @@ -21,9 +21,16 @@ <mybatis.plus.version>3.3.1</mybatis.plus.version> <swagger.ui>2.9.2</swagger.ui> <tomcat.version>9.0.31</tomcat.version> + <hutool.version>5.3.1</hutool.version> </properties> <dependencies> + <dependency> + <groupId>cn.hutool</groupId> + <artifactId>hutool-all</artifactId> + <version>${hutool.version}</version> + </dependency> + <!-- Spring系列 --> <dependency> <groupId>org.springframework.boot</groupId> @@ -213,6 +220,40 @@ <artifactId>xml-apis</artifactId> <version>1.4.01</version> </dependency> + + <!-- submail邮件 start --> + <dependency> + <groupId>commons-logging</groupId> + <artifactId>commons-logging</artifactId> + <version>1.1.1</version> + </dependency> + <dependency> + <groupId>commons-collections</groupId> + <artifactId>commons-collections</artifactId> + <version>3.2.1</version> + </dependency> +<!-- <dependency>--> +<!-- <groupId>org.apache.commons</groupId>--> +<!-- <artifactId>commons-lang3</artifactId>--> +<!-- <version>3.3.2</version>--> +<!-- </dependency>--> + <dependency> + <groupId>net.sf.ezmorph</groupId> + <artifactId>ezmorph</artifactId> + <version>1.0.3</version> + </dependency> + <dependency> + <groupId>net.sf.json-lib</groupId> + <artifactId>json-lib</artifactId> + <version>2.2.3</version> + <classifier>jdk15</classifier> + </dependency> + <dependency> + <groupId>org.apache.httpcomponents</groupId> + <artifactId>httpmime</artifactId> + <version>4.3.5</version> + </dependency> + <!-- submail邮件 end --> </dependencies> <build> diff --git a/src/main/java/cc/mrbird/febs/common/configure/WebMvcConfigure.java b/src/main/java/cc/mrbird/febs/common/configure/WebMvcConfigure.java new file mode 100644 index 0000000..ce2e742 --- /dev/null +++ b/src/main/java/cc/mrbird/febs/common/configure/WebMvcConfigure.java @@ -0,0 +1,23 @@ +package cc.mrbird.febs.common.configure; + +import cc.mrbird.febs.common.interceptor.LoginInterceptor; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.InterceptorRegistration; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +/** + * @author xxx + * @date 2020-08-24 + **/ +@Configuration +public class WebMvcConfigure implements WebMvcConfigurer { + + @Override + public void addInterceptors(InterceptorRegistry registry) { + InterceptorRegistration registration = registry.addInterceptor(new LoginInterceptor()); + registration.addPathPatterns("/api/**"); + registration.excludePathPatterns("/api/login/**"); + registration.excludePathPatterns("/api/common/**"); + } +} diff --git a/src/main/java/cc/mrbird/febs/common/interceptor/LoginInterceptor.java b/src/main/java/cc/mrbird/febs/common/interceptor/LoginInterceptor.java new file mode 100644 index 0000000..81c706b --- /dev/null +++ b/src/main/java/cc/mrbird/febs/common/interceptor/LoginInterceptor.java @@ -0,0 +1,97 @@ +package cc.mrbird.febs.common.interceptor; + +import cc.mrbird.febs.common.entity.FebsResponse; +import cc.mrbird.febs.common.utils.AppContants; +import cc.mrbird.febs.common.utils.RedisUtils; +import cc.mrbird.febs.common.utils.SpringContextUtil; +import cc.mrbird.febs.mall.entity.MallMember; +import cn.hutool.core.util.StrUtil; +import cn.hutool.crypto.asymmetric.KeyType; +import cn.hutool.crypto.asymmetric.RSA; +import com.alibaba.fastjson.JSON; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.http.HttpStatus; +import org.springframework.web.servlet.HandlerInterceptor; +import org.springframework.web.servlet.ModelAndView; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * @author xxx + * @date 2020-08-24 + **/ +@Slf4j +public class LoginInterceptor implements HandlerInterceptor { + + private final RedisUtils redisUtils = SpringContextUtil.getBean(RedisUtils.class); + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + String headerToken = request.getHeader("token"); + if (StringUtils.isBlank(headerToken)) { + responseUnAuth(response); + return false; + } + + String token = resolveToken(headerToken); + + if (token == null || AppContants.TIME_OUT.equals(token)) { + responseUnAuth(response); + return false; + } + + String userJsonStr = redisUtils.getString(token); + if (StringUtils.isBlank(userJsonStr)) { + responseUnAuth(response); + return false; + } + MallMember member = JSON.parseObject(userJsonStr, MallMember.class); + + request.getSession().setAttribute("member", member); + return true; + } + + @Override + public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { + + } + + @Override + public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { + + } + + private void responseUnAuth(HttpServletResponse response) throws IOException { + response.setCharacterEncoding("UTF-8"); + response.setContentType("application/json; charset=utf-8"); + response.getWriter().write(new ObjectMapper().writeValueAsString(new FebsResponse().code(HttpStatus.UNAUTHORIZED))); + } + + private String resolveToken(String token) { + try { + RSA rsa = new RSA(AppContants.PRIVATE_KEY, null); + String[] tokens = StrUtil.split(rsa.decryptStr(token, KeyType.PrivateKey), "_"); + if (verifyTokenExpired(Long.parseLong(tokens[1]))) { + return tokens[0]; + } else { + return AppContants.TIME_OUT; + } + } catch (Exception e) { + log.error("#解析token异常#", e); + return null; + } + } + + private Boolean verifyTokenExpired(Long time) { + boolean isDebug = false; + if (!isDebug) { + long currentTime = System.currentTimeMillis(); + return currentTime - time <= 30000; + } + return true; + } +} diff --git a/src/main/java/cc/mrbird/febs/common/utils/AppContants.java b/src/main/java/cc/mrbird/febs/common/utils/AppContants.java new file mode 100644 index 0000000..4ac326b --- /dev/null +++ b/src/main/java/cc/mrbird/febs/common/utils/AppContants.java @@ -0,0 +1,80 @@ +package cc.mrbird.febs.common.utils; + +import java.math.BigDecimal; + +public class AppContants { + + /** + * 系统用户 + */ + public static final String SYSTEM_USER = "system"; + + public static final String PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCzIfAF0gZs9zn9ENRtz6ocHa8MGljmMmCsjLsRvTIAilBMypMJz/VNooAOhd8GTdsWm8FNGVhRauv7RfxorFJ4Um2UbweUQBIZP2pzZMnclHxhUmYZsn/6IaPzijiUNfEjygtE7ezvso/67ecZJwqfrtlbEjqUbRgo17Qj23suwQIDAQAB"; + + public static final String PRIVATE_KEY = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALMh8AXSBmz3Of0Q1G3PqhwdrwwaWOYyYKyMuxG9MgCKUEzKkwnP9U2igA6F3wZN2xabwU0ZWFFq6/tF/GisUnhSbZRvB5RAEhk/anNkydyUfGFSZhmyf/oho/OKOJQ18SPKC0Tt7O+yj/rt5xknCp+u2VsSOpRtGCjXtCPbey7BAgMBAAECgYAAgn+23IalJ7z0AejA2T7wLotxet+24/zPcOUVY1bxlnMtDMSHWh6mFmjL4cilMXKGqXHO4NwV+zppsCTMPXVMniI1IhfcyECgFjUrpWNCk30DlqhKePtIUCHdyLrc21mMLLMOQD/Hbga5kHZpR8r5poUAJ5Tnm5rjeyggwDj3MwJBAOnY+dyd39cRPtNLH0ANuR0Hd/WuA/RSRNbBTlXIVlc0hF1QXkgIWT2zA4uvwrFsz3F11YdPdfLgUhkFHlQuhVMCQQDEGhJELXqZ3AMlE9ykhUgv9HaCofGuCvzJnBGDKh4B3ufWG728gCNruoaRmzU8TOeVCABIQ2Un3SAenq0ylYUbAkB1y9PJm0lneAtyulPKm18VTW7TNk5No6eDmqqQMbO0iALpUpO7q2Dw4J03n1jusUYp/FaMq61ZpEAW1Go7s5d7AkEArgsJjTLj7ewDaoPfPrD/6XfJOpVqPvKHepOmQ0g9C6H/FtrWIZeEWFdamZ4ruFH08yL/xSLzg1bQ6/wecZecYwJALY4OP1Z81fhNjzg1AQd1CQQJJXUIkQpxXD/zAS5Cgf7XWfELIA4+86WA8qU1ILYHClFuV0SfxyGvI4ZEmpFosg=="; + + /** + * app用户登陆redis前缀 + */ + public static final String APP_LOGIN_PREFIX = "app_"; + + public static final String PC_LOGIN_PREFIX = "pc_"; + + /** + * token头部 + */ + public static final String TOKEN_HEADER = "Authorization"; + + /** + * token start with + */ + public static final String TOKEN_START_WITH = "Bearer "; + + /** + * 账号类型-手机号 + */ + public static final String ACCOUNT_TYPE_MOBILE = "1"; + + /** + * 账号类型-邮箱 + */ + public static final String ACCOUNT_TYPE_EMAIL = "2"; + + /** + * 系统推荐人id + */ + public static final String SYSTEM_REFERER = "rxadr3"; + + /** + * 初始化金额 + */ + public static final BigDecimal INIT_MONEY = BigDecimal.ZERO; + + + public static final Integer INIT_SIMULATE_MONEY = 5000; + + /** + * homeSymbols 接口状态值 币币 + */ + public static final int HOME_SYMBOLS_COIN = 1; + + /** + * homeSymbols 接口状态值 合约 + */ + public static final int HOME_SYMBOLS_CONTRACT = 2; + + /** + * 验证码前缀 手机 + */ + public static final String VERIFY_CODE_PREFIX = "CODE_SMS_"; + + /** + * 图片后缀 + */ + public static final String UPLOAD_IMAGE_SUFFIX = ".jpg"; + + public static final String TIME_OUT = "time_out"; + + public static final String CLOSING_ORDER_PREFIX = "closing_cnt_"; + +} diff --git a/src/main/java/cc/mrbird/febs/common/utils/RedisUtils.java b/src/main/java/cc/mrbird/febs/common/utils/RedisUtils.java new file mode 100644 index 0000000..1ef5240 --- /dev/null +++ b/src/main/java/cc/mrbird/febs/common/utils/RedisUtils.java @@ -0,0 +1,549 @@ +package cc.mrbird.febs.common.utils; + +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; + + +@Component +public class RedisUtils { + + + @Resource + private RedisTemplate<String, Object> redisTemplate; + + + // =============================common============================ + /** + * 指定缓存失效时间 + * @param key 键 + * @param time 时间(秒) + * @return + */ + public boolean expire(String key, long time) { + try { + if (time > 0) { + redisTemplate.expire(key, time, TimeUnit.SECONDS); + } + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 根据key 获取过期时间 + * @param key 键 不能为null + * @return 时间(秒) 返回0代表为永久有效 + */ + public long getExpire(String key) { + return redisTemplate.getExpire(key, TimeUnit.SECONDS); + } + + /** + * 判断key是否存在 + * @param key 键 + * @return true 存在 false不存在 + */ + public boolean hasKey(String key) { + try { + return redisTemplate.hasKey(key); + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 删除缓存 + * @param key 可以传一个值 或多个 + */ + @SuppressWarnings("unchecked") + public void del(String... key) { + if (key != null && key.length > 0) { + if (key.length == 1) { + redisTemplate.delete(key[0]); + } else { + redisTemplate.delete(CollectionUtils.arrayToList(key)); + } + } + } + + // ============================String============================= + /** + * 普通缓存获取 + * @param key 键 + * @return 值 + */ + public Object get(String key) { + return key == null ? null : redisTemplate.opsForValue().get(key); + } + + + /** + * 普通缓存获取 + * @param key 键 + * @return 值 + */ + public String getString(String key) { + Object obj = key == null ? null : redisTemplate.opsForValue().get(key); + if(obj!=null){ + return obj.toString(); + } + return null; + } + + /** + * 普通缓存放入 + * @param key 键 + * @param value 值 + * @return true成功 false失败 + */ + public boolean set(String key, Object value) { + try { + redisTemplate.opsForValue().set(key, value); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 普通缓存放入并设置时间 + * @param key 键 + * @param value 值 + * @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期 + * @return true成功 false 失败 + */ + public boolean set(String key, Object value, long time) { + try { + if (time > 0) { + redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS); + } else { + set(key, value); + } + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + public boolean setNotExist(String key, Object value, long time) { + return redisTemplate.opsForValue().setIfAbsent(key, value, time, TimeUnit.SECONDS); + } + + /** + * 递增 + * @param key 键 + * @param delta 要增加几(大于0) + * @return + */ + public long incr(String key, long delta) { + if (delta < 0) { + throw new RuntimeException("递增因子必须大于0"); + } + return redisTemplate.opsForValue().increment(key, delta); + } + + /** + * 递减 + * @param key 键 + * @param delta 要减少几(小于0) + * @return + */ + public long decr(String key, long delta) { + if (delta < 0) { + throw new RuntimeException("递减因子必须大于0"); + } + return redisTemplate.opsForValue().increment(key, -delta); + } + + + // ================================Map================================= + + /** + * HashGet + * @param key 键 不能为null + * @param item 项 不能为null + * @return 值 + */ + public Object hget(String key, String item) { + return redisTemplate.opsForHash().get(key, item); + } + + /** + * 获取hashKey对应的所有键值 + * @param key 键 + * @return 对应的多个键值 + */ + public Map<Object, Object> hmget(String key) { + return redisTemplate.opsForHash().entries(key); + } + /** + * HashSet + + * @param key 键 + * @param map 对应多个键值 + * @return true 成功 false 失败 + */ + public boolean hmset(String key, Map<String, Object> map) { + try { + redisTemplate.opsForHash().putAll(key, map); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + /** + * HashSet 并设置时间 + * @param key 键 + * @param map 应多个键值 + * @param time 时间(秒) + * @return true成功 false失败 + */ + public boolean hmset(String key, Map<String, Object> map, long time) { + try { + redisTemplate.opsForHash().putAll(key, map); + if (time > 0) { + expire(key, time); + } + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + + /** + * 向一张hash表中放入数据,如果不存在将创建 + * @param key 键 + * @param item 项 + * @param value 值 + * @return true 成功 false失败 + */ + public boolean hset(String key, String item, Object value) { + try { + redisTemplate.opsForHash().put(key, item, value); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + /** + * 向一张hash表中放入数据,如果不存在将创建 + * @param key 键 + * @param item 项 + * @param value 值 + * @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间 + * @return true 成功 false失败 + */ + public boolean hset(String key, String item, Object value, long time) { + try { + redisTemplate.opsForHash().put(key, item, value); + if (time > 0) { + expire(key, time); + } + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + /** + * 删除hash表中的值 + * @param key 键 不能为null + * @param item 项 可以使多个 不能为null + */ + public void hdel(String key, Object... item) { + redisTemplate.opsForHash().delete(key, item); + } + /** + * 判断hash表中是否有该项的值 + * @param key 键 不能为null + * @param item 项 不能为null + * @return true 存在 false不存在 + */ + public boolean hHasKey(String key, String item) { + return redisTemplate.opsForHash().hasKey(key, item); + } + + /** + * hash递增 如果不存在,就会创建一个 并把新增后的值返回 + * @param key 键 + * @param item 项 + * @param by 要增加几(大于0) + * @return + */ + public double hincr(String key, String item, double by) { + return redisTemplate.opsForHash().increment(key, item, by); + } + + /** + * hash递减 + * @param key 键 + * @param item 项 + * @param by 要减少记(小于0) + * @return + */ + public double hdecr(String key, String item, double by) { + return redisTemplate.opsForHash().increment(key, item, -by); + } + // ============================set============================= + /** + * 根据key获取Set中的所有值 + * @param key 键 + * @return + */ + public Set<Object> sGet(String key) { + try { + return redisTemplate.opsForSet().members(key); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + /** + * 根据value从一个set中查询,是否存在 + * @param key 键 + * @param value 值 + * @return true 存在 false不存在 + */ + public boolean sHasKey(String key, Object value) { + try { + return redisTemplate.opsForSet().isMember(key, value); + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + /** + * 将数据放入set缓存 + * @param key 键 + * @param values 值 可以是多个 + * @return 成功个数 + */ + public long sSet(String key, Object... values) { + try { + return redisTemplate.opsForSet().add(key, values); + } catch (Exception e) { + e.printStackTrace(); + + return 0; + } + } + /** + 336 + * 将set数据放入缓存 + 337 + * @param key 键 + * @param time 时间(秒) + * @param values 值 可以是多个 + * @return 成功个数 + */ + public long sSetAndTime(String key, long time, Object... values) { + try { + Long count = redisTemplate.opsForSet().add(key, values); + if (time > 0) + expire(key, time); + return count; + + }catch(Exception e) { + e.printStackTrace(); + return 0; + } + } + /** + * 获取set缓存的长度 + * @param key 键 + * @return + */ + + public long sGetSetSize(String key) { + try { + return redisTemplate.opsForSet().size(key); + + } catch (Exception e) { + e.printStackTrace(); + return 0; + } + + } + + /** + * 移除值为value的 + * @param key 键 + * @param values 值 可以是多个 + * @return 移除的个数 + + */ + public long setRemove(String key, Object... values) { + try { + Long count = redisTemplate.opsForSet().remove(key, values); + return count; + + } catch (Exception e) { + e.printStackTrace(); + return 0; + } + } + // ===============================list================================= + /** + * 获取list缓存的内容 * @param key 键 + * @param start 开始 + * @param end 结束 0 到 -1代表所有值 + * @return + */ + public List<Object> lGet(String key, long start, long end) { + try { + return redisTemplate.opsForList().range(key, start, end); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + + } + + /** + * 获取list缓存的长度 + * @param key 键 + + * @return + */ + public long lGetListSize(String key) { try { + return redisTemplate.opsForList().size(key); + } catch (Exception e) { + + e.printStackTrace(); + return 0; + } + } /** + * 通过索引 获取list中的值 + * @param key 键 + * @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推 + * @return + */ + public Object lGetIndex(String key, long index) { + + try { + return redisTemplate.opsForList().index(key, index); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + /** + * 将list放入缓存 + * @param key 键 + * @param value 值 + * @return + */ + public boolean lSet(String key, Object value) { + try { + redisTemplate.opsForList().rightPush(key, value); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 将list放入缓存 + * @param key 键 + * @param value 值 + * @param time 时间(秒) + * @return + */ + public boolean lSet(String key, Object value, long time) { + try { + redisTemplate.opsForList().rightPush(key, value); + if (time > 0) + expire(key, time); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + /** + * 将list放入缓存 + * @param key 键 + * @param value 值 + * @return + */ + public boolean lSet(String key, List<Object> value) { + try { + redisTemplate.opsForList().rightPushAll(key, value); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + /** + * 将list放入缓存 + * + * @param key 键 + * @param value 值 + * @param time 时间(秒) + * @return + */ + public boolean lSet(String key, List<Object> value, long time) { + try { + redisTemplate.opsForList().rightPushAll(key, value); + if (time > 0) + expire(key, time); + return true; + + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + /** + * 根据索引修改list中的某条数据 + * @param key 键 + * @param index 索引 + * @param value 值 + * @return + */ + public boolean lUpdateIndex(String key, long index, Object value) { + try { + redisTemplate.opsForList().set(key, index, value); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + + /** + * 移除N个值为value + * @param key 键 + * @param count 移除多少个 + * @param value 值 + * @return 移除的个数 + */ + public long lRemove(String key, long count, Object value) { + try { + return redisTemplate.opsForList().remove(key, count, value); + } catch (Exception e) { + e.printStackTrace(); + return 0; + } + } +} diff --git a/src/main/java/cc/mrbird/febs/common/utils/RequestEncoder.java b/src/main/java/cc/mrbird/febs/common/utils/RequestEncoder.java new file mode 100644 index 0000000..71cae5d --- /dev/null +++ b/src/main/java/cc/mrbird/febs/common/utils/RequestEncoder.java @@ -0,0 +1,71 @@ +package cc.mrbird.febs.common.utils; + +import java.security.MessageDigest; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +/** + * 处理请求数据 + * @author submail + * + */ +public class RequestEncoder { + + private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5', + '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; + public static final String MD5 = "MD5"; + public static final String SHA1 = "SHA1"; + /** + * 编码的字符串 + * + * @param algorithm + * @param str + * @return String + */ + public static String encode(String algorithm, String str) { + if (str == null) { + return null; + } + try { + MessageDigest messageDigest = MessageDigest.getInstance(algorithm); + messageDigest.update(str.getBytes("UTF-8")); + return getFormattedText(messageDigest.digest()); + } catch (Exception e) { + throw new RuntimeException(e); + } + + } + + /** + *获取原始字节并将其格式化。 + * @param bytes + * the raw bytes from the digest. + * @return the formatted bytes. + */ + private static String getFormattedText(byte[] bytes) { + int len = bytes.length; + StringBuilder buf = new StringBuilder(len * 2); + for (int j = 0; j < len; j++) { buf.append(HEX_DIGITS[(bytes[j] >> 4) & 0x0f]); + buf.append(HEX_DIGITS[bytes[j] & 0x0f]); + } + return buf.toString(); + } + + public static String formatRequest(Map<String, Object> data){ + Set<String> keySet = data.keySet(); + Iterator<String> it = keySet.iterator(); + StringBuffer sb = new StringBuffer(); + while(it.hasNext()){ + String key = it.next(); + Object value = data.get(key); + if(value instanceof String){ + sb.append(key + "=" + value + "&"); + } + } + if(sb.length() != 0){ + return sb.substring(0, sb.length() - 1); + } + return null; + } +} diff --git a/src/main/java/cc/mrbird/febs/common/utils/SubMailSend.java b/src/main/java/cc/mrbird/febs/common/utils/SubMailSend.java new file mode 100644 index 0000000..9ff0e30 --- /dev/null +++ b/src/main/java/cc/mrbird/febs/common/utils/SubMailSend.java @@ -0,0 +1,169 @@ +package cc.mrbird.febs.common.utils; + + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import net.sf.json.JSONObject; +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.mime.MultipartEntityBuilder; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.protocol.HTTP; +import org.apache.http.util.EntityUtils; + +import java.io.IOException; +import java.util.Date; +import java.util.Map; +import java.util.TreeMap; + +/** + * 邮件发送 + * + * @author wzy + * @date 2020-05-27 + **/ +public class SubMailSend { + + /** + * 时间戳接口配置 + */ + public static final String TIMESTAMP = "https://api.mysubmail.com/service/timestamp"; + /** + * API 请求接口配置 + */ + private static final String URL = "https://api.mysubmail.com/mail/xsend"; + + public static final String TYPE_MD5 = "md5"; + public static final String TYPE_SHA1 = "sha1"; + + private static final String APP_ID = "16082"; + private static final String APP_KEY = "f34c792a1112c16c190ed7190d386c4f"; + private static final String FROM = "hibit@submail.hibit.cc"; + private static final String SIGN_TYPE = ""; + + /** + * 发送验证码邮件 + * + * @param to 对象 + * @param code 验证码 + * @return true or false + */ + public static boolean sendMail(String to, String code) { + JSONObject vars = new JSONObject(); + vars.put("code", code); + + String project = "CVj6P"; + return request(vars, project, to); + } + + /** + * 发送充值成功邮件 + * + * @param to 对象 + * @param time 成功时间 + * @param orderNo 订单编号 + * @return true or false + */ + public static boolean sendRechargeMail(String to, String time, String orderNo) { + JSONObject vars = new JSONObject(); + vars.put("time", time); + vars.put("orderNo", orderNo); + String project = "4DvTC2"; + return request(vars, project, to); + } + + public static boolean sendWithdrawalMail(String to, String time) { + JSONObject vars = new JSONObject(); + vars.put("time", time); + String project = "e3BO91"; + return request(vars, project, to); + } + + + private static boolean request(JSONObject vars, String project, String to) { + TreeMap<String, Object> requestData = new TreeMap<String, Object>(); + requestData.put("appid", APP_ID); + requestData.put("project", project); + requestData.put("to", to); + requestData.put("from", FROM); + if (!vars.isEmpty()) { + requestData.put("vars", vars.toString()); + } + + MultipartEntityBuilder builder = MultipartEntityBuilder.create(); + @SuppressWarnings("deprecation") + ContentType contentType = ContentType.create(HTTP.PLAIN_TEXT_TYPE, HTTP.UTF_8); + for (Map.Entry<String, Object> entry : requestData.entrySet()) { + String key = entry.getKey(); + Object value = entry.getValue(); + if (value instanceof String) { + builder.addTextBody(key, String.valueOf(value), contentType); + } + } + if (SIGN_TYPE.equals(TYPE_MD5) || SIGN_TYPE.equals(TYPE_SHA1)) { + String timestamp = getTimestamp(); + requestData.put("timestamp", timestamp); + requestData.put("sign_type", SIGN_TYPE); + String signStr = APP_ID + APP_KEY + RequestEncoder.formatRequest(requestData) + APP_ID + APP_KEY; + + builder.addTextBody("timestamp", timestamp); + builder.addTextBody("sign_type", SIGN_TYPE); + builder.addTextBody("signature", RequestEncoder.encode(SIGN_TYPE, signStr), contentType); + } else { + builder.addTextBody("signature", APP_KEY, contentType); + } + + HttpPost httpPost = new HttpPost(URL); + httpPost.addHeader("charset", "UTF-8"); + httpPost.setEntity(builder.build()); + try { + CloseableHttpClient closeableHttpClient = HttpClientBuilder.create().build(); + HttpResponse response = closeableHttpClient.execute(httpPost); + HttpEntity httpEntity = response.getEntity(); + if (httpEntity != null) { + String jsonStr = EntityUtils.toString(httpEntity, "UTF-8"); + if ("success".equals(JSONObject.fromObject(jsonStr).getString("status"))) { + return true; + } + } + } catch (IOException e) { + e.printStackTrace(); + } + return false; + } + + + /** + * 获取时间戳 + * + * @return + */ + private static String getTimestamp() { + CloseableHttpClient closeableHttpClient = HttpClientBuilder.create().build(); + HttpGet httpget = new HttpGet(TIMESTAMP); + try { + HttpResponse response = closeableHttpClient.execute(httpget); + HttpEntity httpEntity = response.getEntity(); + String jsonStr = EntityUtils.toString(httpEntity, "UTF-8"); + if (jsonStr != null) { + JSONObject json = JSONObject.fromObject(jsonStr); + return json.getString("timestamp"); + } + closeableHttpClient.close(); + } catch (IOException e) { + e.printStackTrace(); + } + + return null; + } + + public static void main(String[] args) { +// System.out.println(sendMail("546766039@qq.com", "123456")); + + System.out.println(sendRechargeMail("546766039@qq.com", DateUtil.format(new Date(), DatePattern.NORM_DATETIME_PATTERN), "123456")); + } +} diff --git a/src/main/java/cc/mrbird/febs/common/utils/ZzSmsSend.java b/src/main/java/cc/mrbird/febs/common/utils/ZzSmsSend.java new file mode 100644 index 0000000..85e1999 --- /dev/null +++ b/src/main/java/cc/mrbird/febs/common/utils/ZzSmsSend.java @@ -0,0 +1,68 @@ +package cc.mrbird.febs.common.utils; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.core.util.XmlUtil; +import cn.hutool.crypto.SecureUtil; +import cn.hutool.http.HttpUtil; +import lombok.extern.slf4j.Slf4j; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * @author wzy + * @date 2021-03-25 + **/ +@Slf4j +public class ZzSmsSend { + + private static final String URL = "http://zzsms365.com/v2sms.aspx?action=send"; + + private static final String USER_ID = "1654"; + private static final String ACCOUNT = "1369815429"; + private static final String PWD = "1369815429"; + + public static boolean sendVerifyCode(String telphone, String code, int time) { + String content = "【HiBit】您的验证码是{},请在{}分钟内输入,请勿泄露给他人,如非本人操作,请及时修改密码。"; + return send(telphone, StrUtil.format(content, code, time)); + } + + private static boolean send(String telphone, String content) { + Map<String, Object> data = new HashMap<>(); + Long time = System.currentTimeMillis(); + data.put("userid", USER_ID); + data.put("timestamp", time); + data.put("mobile", telphone); + String signStr = ACCOUNT + PWD + time; + String sign = SecureUtil.md5(signStr); + data.put("sign", sign); + data.put("content", content); + + String response = HttpUtil.post(URL, data); + log.info("短信发送:{}", response); + if ("Success".equals(XmlUtil.xmlToMap(response).get("returnstatus"))) { + return true; + } else { +// throw new GlobalException((String) XmlUtil.xmlToMap(response).get("message")); + return false; + } + } + + public static void main(String[] args) { + Map<String, Object> data = new HashMap<>(); + Long time = System.currentTimeMillis(); + data.put("userid", USER_ID); + data.put("timestamp", time); + data.put("mobile", "15773002834"); + String signStr = ACCOUNT + PWD + time; + String sign = SecureUtil.md5(signStr); + data.put("sign", sign); + data.put("content", "【HiBit】尊敬的用户,恭喜您于2010-03-25有一笔充值已成功到账,充值数量为10。"); + + String post = HttpUtil.post(URL, data); + System.out.println(post); + } +} diff --git a/src/main/java/cc/mrbird/febs/mall/controller/CommonController.java b/src/main/java/cc/mrbird/febs/mall/controller/CommonController.java new file mode 100644 index 0000000..0c1db62 --- /dev/null +++ b/src/main/java/cc/mrbird/febs/mall/controller/CommonController.java @@ -0,0 +1,71 @@ +package cc.mrbird.febs.mall.controller; + +import cc.mrbird.febs.common.entity.FebsResponse; +import cc.mrbird.febs.common.exception.FebsException; +import cc.mrbird.febs.common.utils.AppContants; +import cc.mrbird.febs.common.utils.RedisUtils; +import cc.mrbird.febs.common.utils.SubMailSend; +import cc.mrbird.febs.common.utils.ZzSmsSend; +import cn.hutool.core.util.StrUtil; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author wzy + * @date 2021-09-16 + **/ +@Slf4j +@RestController +@RequestMapping(value = "/api/common") +@RequiredArgsConstructor +@Api(value = "CommonController", tags = "公共请求类") +public class CommonController { + + private final RedisUtils redisUtils; + + @ApiOperation(value = "获取验证码接口", notes = "获取验证码通用接口") + @GetMapping(value = "/verifyCode") + public FebsResponse verifyCode(@ApiParam(name = "account", value = "手机号", required = true) @RequestParam(value = "account") String account, + @ApiParam(name = "type", value = "类型1-手机号", required = true) @RequestParam("type") String type) { + log.info("#账号:{}, 类型:{}#", account, type); + + Integer code = (int) ((Math.random() * 9 + 1) * 100000); + if (StrUtil.isNotBlank(redisUtils.getString(AppContants.VERIFY_CODE_PREFIX + account))) { + throw new FebsException("验证码已发送"); + } + + // 发送手机验证码 + if (AppContants.ACCOUNT_TYPE_MOBILE.equals(type)) { + boolean result = ZzSmsSend.sendVerifyCode(account, code.toString(), 2); + if (result) { + Map<String, Object> map = new HashMap<>(); + boolean flag = redisUtils.set(AppContants.VERIFY_CODE_PREFIX + account, code, 120); + map.put("code", flag); + return new FebsResponse().success().message("验证码发送成功"); + } + // 发送邮件验证码 + } else if (AppContants.ACCOUNT_TYPE_EMAIL.equals(type)) { + boolean flag = SubMailSend.sendMail(account, code.toString()); + if (flag) { + redisUtils.set(AppContants.VERIFY_CODE_PREFIX + account, code, 120); + return new FebsResponse().success().message("验证码发送成功"); + } else { + return new FebsResponse().fail().message("验证码发送失败"); + } + } else { + log.info("未定义账号类型"); + throw new FebsException("未定义账号类型"); + } + return new FebsResponse().fail().message("验证码发送失败"); + } +} diff --git a/src/main/java/cc/mrbird/febs/mall/service/CommonService.java b/src/main/java/cc/mrbird/febs/mall/service/CommonService.java new file mode 100644 index 0000000..06e129d --- /dev/null +++ b/src/main/java/cc/mrbird/febs/mall/service/CommonService.java @@ -0,0 +1,32 @@ +package cc.mrbird.febs.mall.service; + +import cc.mrbird.febs.common.utils.AppContants; +import cc.mrbird.febs.common.utils.RedisUtils; +import cn.hutool.core.util.StrUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +/** + * @author wzy + * @date 2021-09-16 + **/ +@Slf4j +@Service +@RequiredArgsConstructor +public class CommonService { + private final RedisUtils redisUtils; + + public boolean verifyCode(String account, String code) { + String cacheCode = redisUtils.getString(AppContants.VERIFY_CODE_PREFIX + account); + if (StrUtil.isBlank(cacheCode)) { + return false; + } + if (code.equals(cacheCode)) { + redisUtils.del(AppContants.VERIFY_CODE_PREFIX + account); + return true; + } else { + return false; + } + } +} -- Gitblit v1.9.1