1.这里使用的是RestTemplate调用公司云平台上的短信接口为例 你也可以在网上下载第三方短信平台依赖包,但都是大同小异可参考https://www.cnblogs.com/liabio/p/11718388.html
package com.iflytek.edu.hnezzhxy.controller; import com.alibaba.fastjson.JSONObject; import com.iflytek.edu.hnezzhxy.common.config.Constants; import com.iflytek.edu.hnezzhxy.common.enums.ResponseCodeEnum; import com.iflytek.edu.hnezzhxy.dao.ZsbmUserDao; import com.iflytek.edu.hnezzhxy.model.ZsbmUser; import com.iflytek.edu.hnezzhxy.util.AESUtil; import com.iflytek.edu.hnezzhxy.util.MD5Util; import com.iflytek.edu.hnezzhxy.util.ResponseResultUtil; import com.iflytek.edu.hnezzhxy.util.UUIDUtil; import com.iflytek.edu.hnezzhxy.vo.ResultVO; import io.swagger.annotations.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; import org.thymeleaf.util.StringUtils; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; import javax.validation.constraints.Pattern; import java.sql.Timestamp; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; /** * @description 登陆处理类 * @create 2020/06/18 15:44 * @version 1.0 */ @RestController @Validated @Api(tags = "登陆相关接口") public class LoginController { private static final Logger logger = LoggerFactory.getLogger(LoginController.class); /** 短信申请接口地址 **/ @Value(value = "${phone.apiUrl}") private String apiUrl; /** 产品标识 **/ @Value(value = "${phone.appId}") private String appId; /** 短信模板id **/ @Value(value = "${phone.tId}") private String tId; /** 短信验证码失效时间 **/ @Value(value = "${phone.minute}") private Integer minute; /** 密钥 **/ @Value(value = "${phone.key}") private String key; /** 用户接口 **/ @Autowired private ZsbmUserDao zsbmUserDao; /** redis模板 **/ @Autowired private RedisTemplate<String, String> redisTemplate; /** * @description 用户登陆接口 * @param phoneNum 手机号 * @param passWord 用户密码 * @param tokens 令牌 * @param request * @return ResultVO */ @RequestMapping("/login") @ApiOperation(value="用户登陆接口信息", httpMethod="POST", notes="用户登陆接口信息") @ApiImplicitParams({ @ApiImplicitParam(name="phoneNum",value="手机号",required=true,paramType="query",dataType="String"), @ApiImplicitParam(name="passWord",value="密码",required=true,paramType="query",dataType="String"), @ApiImplicitParam(name="tokens",value="密码的AES加密方式",paramType="query",dataType="String") }) public ResultVO<ZsbmUser> login(@NotBlank(message = "手机号不能为空!") @Pattern(regexp = "^(((13[0-9]{1})|(15[0-9]{1})|(17[0-9]{1})|(18[0-9]{1}))+\\d{8})$",message = "手机号格式不正确!") @RequestParam(value="phoneNum") String phoneNum, @NotBlank(message = "密码不能为空!")@RequestParam(value="passWord") String passWord, @RequestParam(value="tokens", required = false, defaultValue = "6ay4dlwd4enjbf90") String tokens, HttpServletRequest request) { HttpSession session = request.getSession(); //由于前端穿过来的是=AES加密方式,需要解密然后再通过md5加密去查询 String pass =this.aesDecrypt(passWord,tokens); if(StringUtils.isEmpty(pass)){ logger.error("AES解密失败!"); return new ResponseResultUtil().success(ResponseCodeEnum.AES_DEC_FAIL.getCode(), ResponseCodeEnum.AES_DEC_FAIL.getMessage(),null,true); } String md5Pass = MD5Util.string2MD5(pass); ZsbmUser user = zsbmUserDao.selectUserByUserNameAndPassWord(phoneNum, md5Pass); if(user!=null){ session.setAttribute(Constants.SESSION_USER_Attribute,user); logger.info("用户信息!"+user); logger.info("登陆成功!"); return new ResultVO(ResponseCodeEnum.LOGIN_SUCCESS.getCode(),ResponseCodeEnum.LOGIN_SUCCESS.getMessage(),user,true); }else{ logger.error("用户名或密码错误!"); return new ResponseResultUtil().success(ResponseCodeEnum.UNLOGIN_ERROR.getCode(), ResponseCodeEnum.UNLOGIN_ERROR.getMessage(),null,true); } } /** * @description 短信发送业务逻辑 * @param phoneNum 电话号码 * @param flag true 代表密码找回 false 代表注册 * @return ResultVO */ @RequestMapping("/sendPost") @ApiOperation(value="短信注册或密码找回验证码发送",httpMethod ="POST", notes="短信注册或密码找回验证码发送") @ApiImplicitParams({ @ApiImplicitParam(name="phoneNum",value="手机号",required=true,paramType="query",dataType="String"), @ApiImplicitParam(name="flag",value="注册或者密码找回标识:true为密码找回,false注册,不传默认false",paramType="query",dataType="Boolean") }) public ResultVO sendPost(@NotBlank(message = "手机号不能为空!") @Pattern(regexp = "^(((13[0-9]{1})|(15[0-9]{1})|(17[0-9]{1})|(18[0-9]{1}))+\\d{8})$",message = "手机号格式不正确!") @RequestParam(value="phoneNum") String phoneNum, @RequestParam(value="flag",required = false,defaultValue = "false") Boolean flag){ ResultVO resultVO=new ResultVO(null,null,null,true); String phone=zsbmUserDao.selectPhoneIsExist(phoneNum); //true 代表是密码找回 false是注册 if(flag){ if(StringUtils.isEmpty(phone)){ return new ResponseResultUtil().error(ResponseCodeEnum.PHONE_NO_REGISTER.getCode(),ResponseCodeEnum.PHONE_NO_REGISTER.getMessage()); }else{ this.sendVerificationCode(resultVO,phoneNum); } }else{ //判断手机号是否被注册 if(StringUtils.isEmpty(phone)){ this.sendVerificationCode(resultVO,phoneNum); }else{ resultVO.setCode(ResponseCodeEnum.HAS_REGISTER.getCode()); resultVO.setMessage(ResponseCodeEnum.HAS_REGISTER.getMessage()); } } return resultVO; } /** * @description 发送验证码 * @param resultVO * @param phoneNum 电话号码 * @return ResultVO */ private ResultVO sendVerificationCode(ResultVO resultVO,String phoneNum){ //随机生成固定6位数验证码 String code = String.valueOf((int)((Math.random()*9+1)*100000)); StringBuilder sb = new StringBuilder(); sb.append("appid=").append(appId).append("&phone=").append(phoneNum) .append("&tid=").append(tId).append("&tp={Code:'").append(code).append("',Minute:'") .append(minute).append("'}&key=").append(key); logger.info("拼接后后字符串为" + sb.toString()); String sign = MD5Util.string2MD5(sb.toString()).toUpperCase(); logger.info("md5加密后的密钥转大写后为" + sign); String[] phones = phoneNum.split(","); Map<String, Object> map = new HashMap<>(5); Map<String, Object> m = new HashMap<>(2); m.put(Constants.VALID_CODE_Attribute, code); m.put(Constants.VALID_CODE_MINUTE_Attribute, minute); map.put(Constants.VALID_CODE_APPID_Attribute, appId); map.put(Constants.VALID_CODE_PHONE_Attribute, phones); map.put(Constants.VALID_CODE_TID_Attribute, tId); map.put(Constants.VALID_CODE_TP_Attribute, m); map.put(Constants.VALID_CODE_SIGN_Attribute, sign); logger.info("http Post 请求发送包为" + JSONObject.toJSONString(map)); String jsonStr = new RestTemplate().postForObject(apiUrl, map, String.class); logger.info("短信接收平台返回的结果为json字符串:" + jsonStr); if (jsonStr != null ) { JSONObject jsonObj =(JSONObject) JSONObject.parse(jsonStr); if(jsonObj!=null&&Constants.CLOUD_RETURN_CODE.equals(jsonObj.get(Constants.CLOUD_RETURN_CODE_Attribute))){ //防止多个用户发送手机验证码,覆盖redis里的key值 String validCode=new StringBuilder().append(phoneNum).append(":").append(code).toString(); redisTemplate.opsForValue().set(validCode, code, 5, TimeUnit.MINUTES); }else{ logger.error(ResponseCodeEnum.DX_CLOUD_fAIL.getMessage()); return new ResponseResultUtil().error(ResponseCodeEnum.DX_CLOUD_fAIL.getCode(),ResponseCodeEnum.DX_CLOUD_fAIL.getMessage()); } } resultVO.setCode(ResponseCodeEnum.PHONE_SEND_SUCCESS.getCode()); resultVO.setMessage(ResponseCodeEnum.PHONE_SEND_SUCCESS.getMessage()); return resultVO; } /** * @description 用户注册 * @param phoneNum 手机号 * @param passWord 密码 * @param roleId 角色id * @param validCode 验证码 * @return */ @RequestMapping("/register") @ApiOperation(value="用户注册",httpMethod ="POST", notes="用户注册") @ApiImplicitParams({ @ApiImplicitParam(name="phoneNum",value="手机号",required=true,paramType="query",dataType="String"), @ApiImplicitParam(name="passWord",value="密码",required=true,paramType="query",dataType="String"), @ApiImplicitParam(name="roleId",value="角色ID",required=true,paramType="query",dataType="String"), @ApiImplicitParam(name="tokens",value="AES加密规则",paramType="query",dataType="String"), @ApiImplicitParam(name="validCode",value="6位数短信验证码",required=true,paramType="query",dataType="String") }) public ResultVO register(@NotBlank(message = "手机号不能为空!") @Pattern(regexp = "^(((13[0-9]{1})|(15[0-9]{1})|(17[0-9]{1})|(18[0-9]{1}))+\\d{8})$",message = "手机号格式不正确") @RequestParam(value = "phoneNum") String phoneNum, @NotBlank(message = "密码不能为空!") @RequestParam(value = "passWord") String passWord, @NotNull(message = "身份不能为空!") @RequestParam(value = "roleId") Integer roleId, @RequestParam(value="tokens", required = false, defaultValue = "6ay4dlwd4enjbf90") String tokens, @NotNull(message = "验证码不能为空!") @Pattern (regexp = "^\\d{6}$",message = "手机短信验证码必须是6位数!")@RequestParam(value = "validCode") String validCode){ String vCode=new StringBuilder().append(phoneNum).append(":").append(validCode).toString(); Object code = redisTemplate.opsForValue().get(vCode); if(code!=null){ String pass =this.aesDecrypt(passWord,tokens); if(StringUtils.isEmpty(pass)){ logger.error("AES解密失败!"); return new ResponseResultUtil().success(ResponseCodeEnum.AES_DEC_FAIL.getCode(), ResponseCodeEnum.AES_DEC_FAIL.getMessage(),null,true); } if(validCode.equals(code)){ String phone = zsbmUserDao.selectPhoneIsExist(phoneNum); if(StringUtils.isEmpty(phone)){ zsbmUserDao.addUser(UUIDUtil.uuid(),MD5Util.string2MD5(pass),phoneNum,roleId); }else{ return new ResponseResultUtil().success(ResponseCodeEnum.HAS_REGISTER.getCode(),ResponseCodeEnum.HAS_REGISTER.getMessage(),null,true); } }else{ return new ResponseResultUtil().success(ResponseCodeEnum.VALIDATE_WRITER_ERROR.getCode(),ResponseCodeEnum.VALIDATE_WRITER_ERROR.getMessage(),null,true); } }else{ return new ResponseResultUtil().success(ResponseCodeEnum.VALIDATE_EXPIRE.getCode(),ResponseCodeEnum.VALIDATE_EXPIRE.getMessage(),null,true); } return new ResponseResultUtil().success(ResponseCodeEnum.REGISTER_SUCCESS.getCode(),ResponseCodeEnum.REGISTER_SUCCESS.getMessage(),null,true); } /** * @description 密码找回 * @param phoneNum 手机号 * @param passWord 新密码 * @param validCode 验证码 * @return ResultVO */ @RequestMapping("/retrievePass") @ApiOperation(value="密码找回",httpMethod ="POST", notes="密码找回") @ApiImplicitParams({ @ApiImplicitParam(name="phoneNum",value="手机号",required=true,paramType="query",dataType="String"), @ApiImplicitParam(name="passWord",value="密码",required=true,paramType="query",dataType="String"), @ApiImplicitParam(name="tokens",value="AES加密规则",paramType="query",dataType="String"), @ApiImplicitParam(name="validCode",value="6位数短信验证码",required=true,paramType="query",dataType="String") }) public ResultVO retrievePass( @NotBlank(message = "手机号不能为空!") @Pattern(regexp = "^(((13[0-9]{1})|(15[0-9]{1})|(17[0-9]{1})|(18[0-9]{1}))+\\d{8})$",message = "手机号格式不正确!") @RequestParam(value = "phoneNum") String phoneNum, @NotBlank(message = "密码不能为空!") @RequestParam(value = "passWord") String passWord, @RequestParam(value="tokens", required = false, defaultValue = "6ay4dlwd4enjbf90") String tokens, @NotNull(message = "验证码不能为空!") @Pattern (regexp = "^\\d{6}$",message = "手机短信验证码必须是6位数!") @RequestParam(value = "validCode") String validCode) { String vCode=new StringBuilder().append(phoneNum).append(":").append(validCode).toString(); Object code = redisTemplate.opsForValue().get(vCode); if(code!=null){ String pass =this.aesDecrypt(passWord,tokens); if(StringUtils.isEmpty(pass)){ logger.error("AES解密失败!"); return new ResponseResultUtil().success(ResponseCodeEnum.AES_DEC_FAIL.getCode(), ResponseCodeEnum.AES_DEC_FAIL.getMessage(),null,true); } if(validCode.equals(code)){ Timestamp systemdate = new Timestamp(System.currentTimeMillis()); zsbmUserDao.updateUserPassWord(phoneNum,MD5Util.string2MD5(pass),systemdate); }else{ return new ResponseResultUtil().success(ResponseCodeEnum.VALIDATE_WRITER_ERROR.getCode(),ResponseCodeEnum.VALIDATE_WRITER_ERROR.getMessage(),null,true); } }else{ return new ResponseResultUtil().success(ResponseCodeEnum.VALIDATE_EXPIRE.getCode(),ResponseCodeEnum.VALIDATE_EXPIRE.getMessage(),null,true); } return new ResponseResultUtil().success(ResponseCodeEnum.USERPASS_UPDATE_SUCCESS.getCode(),ResponseCodeEnum.USERPASS_UPDATE_SUCCESS.getMessage(),null,true); } /** * @description AES解密 * @param passWord AES加密的密码 * @param tokens AES加密规则 * @return ResultVO */ private String aesDecrypt(String passWord,String tokens){ try { logger.info("AES加密后的密码为:"+passWord); logger.info("AES的tokens令牌为:"+tokens); return AESUtil.Decrypt(passWord, tokens); } catch (Exception e) { e.printStackTrace(); logger.error("AES解密失败!"); } return null; } /** * @description 获取登陆状态信息 * @param session * @return ResultVO */ @RequestMapping("/getLoginStatus") @ApiOperation(value="获取登陆状态信息",httpMethod ="GET", notes="获取登陆状态信息") public ResultVO getLoginStatus(HttpSession session){ Object object = session.getAttribute(Constants.SESSION_USER_Attribute); if(object!=null){ ZsbmUser zsbmUser=(ZsbmUser)object; return new ResultVO<ZsbmUser>(ResponseCodeEnum.SUCCESS.getCode(),ResponseCodeEnum.SUCCESS.getMessage(),zsbmUser,true); } return new ResponseResultUtil().success(ResponseCodeEnum.UNLOGIN_ERROR.getCode(), ResponseCodeEnum.UNLOGIN_ERROR.getMessage(),null,true); } /** * @description 退出登录 * @param session * @return ResultVO */ @RequestMapping("/getLoginOut") @ApiOperation(value="退出登陆",httpMethod ="GET", notes="退出登陆") public ResultVO getLoginOut(HttpSession session){ Object object = session.getAttribute(Constants.SESSION_USER_Attribute); if(object!=null){ session.removeAttribute(Constants.SESSION_USER_Attribute); } return new ResponseResultUtil().success(ResponseCodeEnum.LOGINOUT_SUCCESS.getCode(), ResponseCodeEnum.LOGINOUT_SUCCESS.getMessage(),null,true); } }2.properties或者.yml文件配置
phone: apiUrl: https://pretest.xfpaas.com/dripsms/smssafes # 测试环境短信接口申请地址 appId: CSW3Y0RD #产品标识 tId: 12087 #短信模板ID minute: 5 #短信验证码几分钟失效 key: d3c39d38bb59f9428398364fe7a83.常量类
package com.iflytek.edu.hnezzhxy.common.config; /** * 常量类 * @version 1.0 * @description * @create 2020/06/23 19:40 */ public class Constants { /** 短信验证码属性 **/ public static final String VALID_CODE_Attribute = "Code"; /** 云平台返回的验证码属性 **/ public static final String CLOUD_RETURN_CODE_Attribute = "code"; /** 云平台返回的验证码 **/ public static final String CLOUD_RETURN_CODE = "000000"; /** 短信验证码过期属性 **/ public static final String VALID_CODE_MINUTE_Attribute = "Minute"; /** 短信产品标识属性 **/ public static final String VALID_CODE_APPID_Attribute = "appid"; /** 手机号属性 **/ public static final String VALID_CODE_PHONE_Attribute = "phone"; /** 模板id属性 **/ public static final String VALID_CODE_TID_Attribute = "tid"; /** 验证码和过期时间的结合属性 **/ public static final String VALID_CODE_TP_Attribute = "tp"; /** 密钥属性 **/ public static final String VALID_CODE_SIGN_Attribute = "sign"; /** 存在seesion里的用户属性 **/ public static final String SESSION_USER_Attribute = "user"; /** 管理员角色 **/ public static final String ROLE_ADMIN = "admin"; /** 编码格式 **/ public static final String ECODE_UTF8="UTF-8"; /** excel2003 **/ public static final String EXCEL2003 = "xls"; /** excel2007 **/ public static final String EXCEL2007 = "xlsx"; /** 图像类型信息 **/ public static final String TYPE_IMAGE= "0"; /** 成绩 **/ public static final String TYPE_SCORE= "1"; }4.响应码枚举类
package com.iflytek.edu.hnezzhxy.common.enums; /** * @description 请求响应状态码和提示信息枚举类 * @create 2020/06/18 15:44 * @version 1.0 */ public enum ResponseCodeEnum { /** 请求成功状态码和提示信息 **/ SUCCESS(200, "success"), /** 尚未登录 **/ UNLOGIN_ERROR(0, "尚未登录!"), /** 登陆成功 **/ LOGIN_SUCCESS(1,"登陆成功!"), /** 注册成功 **/ REGISTER_SUCCESS(2,"注册成功!"), /** 验证码过期 **/ VALIDATE_EXPIRE(3,"验证码过期!"), /** 用户密码修改成功 **/ VALIDATE_WRITER_ERROR(4,"验证码填写错误!"), /** 用户密码修改成功 **/ USERPASS_UPDATE_SUCCESS(5,"用户密码修改成功!"), /** 手机号已经被注册 **/ HAS_REGISTER(6,"手机号已经被注册!"), /** 手机号发送验证码成功 **/ PHONE_SEND_SUCCESS(7,"手机验证码发送成功!"), /** 登陆成功 **/ LOGINOUT_SUCCESS(8,"退出成功!"), /** 登陆成功 **/ IMPORT_SUCCESS(9,"导入成功!"), /** 登陆成功 **/ IMPORT_ERROR(10,"导入失败!"), /** 程序报错响应信息 **/ OPERATE_FAIL(500, "error"), /** 短信云平台响应失败 **/ DX_CLOUD_fAIL(501, "短信云平台响应失败!请联系相关负责人!"), /** 该手机号还未被注册,不能找回! **/ PHONE_NO_REGISTER(502, "该手机号还未被注册,不能找回!"), /** AES解密失败 **/ AES_DEC_FAIL(503, "AES解密失败!请验证解密规则!"); private Integer code; private String message; ResponseCodeEnum(Integer code, String message) { this.code = code; this.message = message; } public final Integer getCode() { return this.code; } public final String getMessage() { return this.message; } }