您现在的位置是:首页 > 文章详情

手机验证码登录

日期:2018-06-21点击:435

手机验证登录分为三个API接口,分别为:获取图片验证码、获取手机短信验证码、登录。


1.获取图片验证码:通过工具类生成图片验证码,将随机验证码的数字保存到session中,将图片验证码转为base64码放到对应的entity字段里。


2.获取手机短信验证码:判断手机号不能为空、手机号的格式、手机号在数据中必须存在,定义6位随机数做为短信验证码,先将验证码保存到redis中(60秒时效),


然后再发送到对应的手机号中。


3.登录:首先检验随机验证码、短信验证码不能为空,从session中获取随机验证码进行校验(验证码忽略大小写),


校验成功后就开始继续从session获取短信验证码并做校验,短信验证码验证成功后就开始进入到系统并修改登录次数、登录时间、获取下载数、个人信息等。



package com.chinamobile.cmss.share.controller; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; 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 com.chinamobile.cmss.dto.CmssSmsLoginDto; import com.chinamobile.cmss.share.service.ICmssSmsLoginService; import com.web.response.ResponseDto; import com.web.response.ResponseUtil; /** * 手机短信验证登录 * @author yaohongan * */ @RestController @RequestMapping(value = "/smsLogin") public class CmssSMSLoginController { /** * 日志 */ private final Logger log = Logger.getLogger(CmssSMSLoginController.class); @Autowired private ICmssSmsLoginService smsLoginService; /** * 获取随机验证码 * @param code * @return */ @GetMapping("/getValidationCode") public ResponseDto getValidationCode(final CmssSmsLoginDto sms, final HttpServletRequest request, final HttpServletResponse response) throws Exception { return ResponseUtil.wrapSuccess(smsLoginService.getValidationCode(sms, request, response)); } /** * 获取短信验证码 * @param code * @return */ @PostMapping("/getSendSmsValidationCode") public ResponseDto getSendSmsValidationCode(@RequestBody final CmssSmsLoginDto sms) { smsLoginService.getSendSmsValidationCode(sms); return ResponseUtil.wrapSuccess(); } /** * 登录 * @param sms * @return */ @PostMapping("/login") public ResponseDto smsLogin(@RequestBody final CmssSmsLoginDto sms, final HttpServletRequest request, final HttpServletResponse resp) { final Map<String, Object> returnMap = smsLoginService.login(sms, request, resp); return ResponseUtil.wrapSuccess(returnMap); } } 

service 接口层



package com.chinamobile.cmss.share.service; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.chinamobile.cmss.dto.CmssSmsLoginDto; public interface ICmssSmsLoginService { /** 获取随机验证码 **/ CmssSmsLoginDto getValidationCode(CmssSmsLoginDto sms, HttpServletRequest request, HttpServletResponse response) throws Exception; /** 获取短信验证码 **/ void getSendSmsValidationCode(final CmssSmsLoginDto sms); /** 登录 **/ Map<String, Object> login(CmssSmsLoginDto sms, final HttpServletRequest request, final HttpServletResponse resp); /** 登录后的操作 **/ Map<String, Object> validateLogin(final String cryptogramMobilePhone, final HttpServletRequest request, final HttpServletResponse resp); }
service 实现层

package com.chinamobile.cmss.share.service.impl; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Random; import java.util.UUID; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.apache.commons.lang3.StringUtils; import org.apache.log4j.Logger; import org.apache.poi.ss.formula.functions.T; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import com.base.service.BaseService; import com.base.util.mapper.JsonMapper; import com.chinamobile.cmss.constants.CommonConstants; import com.chinamobile.cmss.dto.CmssSmsLoginDto; import com.chinamobile.cmss.dto.ValidateDto; import com.chinamobile.cmss.share.dao.CmssPortalUserDao; import com.chinamobile.cmss.share.entity.PortalUser; import com.chinamobile.cmss.share.exception.CmssSmsLoginException; import com.chinamobile.cmss.share.exception.LoginExceptionEnum; import com.chinamobile.cmss.share.service.ICmssSmsLoginService; import com.chinamobile.cmss.share.service.IPermissionService; import com.chinamobile.cmss.share.utils.ValidateCodeUtil; import com.share.page.buss.PortalUserPage; import com.share.utils.ShareJedis; import com.web.exception.BusinessException; @Service("cmssSmsLoginService") public class CmssSmsLoginServiceImpl extends BaseService<T> implements ICmssSmsLoginService { /** 日志 **/ private final Logger log = Logger.getLogger(CmssSmsLoginServiceImpl.class); @Resource private ShareJedis shareJedis; @Value("${smsCodePrescription}") private Integer smsCodePrescription; @Autowired private CmssPortalUserDao<T> dao; @Autowired private CmssBatchSmsService batchSmsService; @Autowired private CmssPortalUserService<PortalUser> cmssPortalUserService; @Autowired private IPermissionService permissionService; // 用户下载总次数redis键值前缀 // redis里key:userDownloadTimes:pdf:${userId},userId为当前用户登录ID private final static String KEY_PREFIX = "userDownloadTimes:"; @Override public CmssPortalUserDao<T> getDao() { return dao; } /** * 获取随机验证码 * @throws IOException */ @Override public CmssSmsLoginDto getValidationCode(final CmssSmsLoginDto sms, final HttpServletRequest request, final HttpServletResponse response) throws Exception { final HttpSession session = request.getSession(); // 直接调用静态方法,返回验证码对象 final ValidateDto v = ValidateCodeUtil.getRandomCode(); if (v != null) { // 将验证码值保存session session.setAttribute("validate", v.getValue()); log.info("验证码是:" + v.getValue()); // 保存图片二维码的base64码 sms.setCode(v.getBase64Str()); } return sms; } /** * 获取短信验证码 */ @Override public void getSendSmsValidationCode(final CmssSmsLoginDto sms) { // 手机号码不能为空 if (StringUtils.isEmpty(sms.getPhone())) { throw new BusinessException(CmssSmsLoginException.PHONE_EMPTY); } // 判断手机号格式 if (!sms.getPhone().matches("^1\\d{10}$")) { throw new BusinessException(CmssSmsLoginException.PHONE_EXIST); } // 校验手机号是否存在 // 去数据库查询手机号 final PortalUserPage portalUser = new PortalUserPage(); portalUser.setPhone(sms.getPhone()); final List<T> portalUserList = dao.queryByList(portalUser); if (portalUserList.size() == 0) { throw new BusinessException(CmssSmsLoginException.ACCOUNT_NOT_EXIST); } final String phone = sms.getPhone(); sms.setSmsCode(String.valueOf((new Random().nextInt(899999) + 100000))); // 将短信验证码存储到redis,时效是1分钟 shareJedis.setex(phone, sms.getSmsCode(), smsCodePrescription); // 发送手机验证码 batchSmsService.sendSmsValidationCode(phone, sms.getSmsCode()); log.info("短信验证发送成功,发送时间{" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + "},手机号{" + sms.getPhone() + "},验证码{" + sms.getSmsCode() + "}"); } /** * 短信验证登录 */ @Override public Map<String, Object> login(final CmssSmsLoginDto sms, final HttpServletRequest request, final HttpServletResponse resp) { // 短信验证码不能为空 if (StringUtils.isEmpty(sms.getSmsCode())) { throw new BusinessException(CmssSmsLoginException.SMS_AUTHENTICATION_CODE_NOT_EXISTS); } // 随机验证码不能为空 if (StringUtils.isEmpty(sms.getCode())) { throw new BusinessException(CmssSmsLoginException.VERIFICATION_CODE_EMPTY); } final HttpSession session = request.getSession(); final String sessionValidate = (String) session.getAttribute("validate"); // 验证随机验证码 // 忽略验证码大小写 if (!StringUtils.equalsIgnoreCase(sms.getCode(), sessionValidate)) { throw new BusinessException(CmssSmsLoginException.VERIFICATION_CODE_ERROR); } // 验证短信验证码 // 根据手机号码取短信验证码 final String smsCode = shareJedis.get(sms.getPhone()); // 如果验证码为空就是超时 if (StringUtils.isEmpty(smsCode)) { throw new BusinessException(CmssSmsLoginException.SMS_AUTHENTICATION_CODE_OVERTIME); } // 校验短信验证码是否匹配 if (!smsCode.equals(sms.getSmsCode())) { throw new BusinessException(CmssSmsLoginException.SMS_AUTHENTICATION_CODE_ERROR); } String cryptogramMobilePhone = ""; PortalUser pu = new PortalUser(); final PortalUserPage pup = new PortalUserPage(); pup.setPhone(sms.getPhone()); final List<PortalUser> ls = cmssPortalUserService.getUserByPhone(pup); if (ls != null && ls.size() > 0) { pu = ls.get(0); if (CommonConstants.PORTAL_USER_STATUS.UNCHECKED_USER_STATUS.equals(pu.getStatus())) { throw new BusinessException(LoginExceptionEnum.UNCHECKED_USER); } if (CommonConstants.PORTAL_USER_STATUS.UNAVALIDATE.equals(pu.getStatus())) { throw new BusinessException(LoginExceptionEnum.UNAVALIDATE); } if (CommonConstants.PORTAL_USER_STATUS.AUTH_FAILED.equals(pu.getStatus())) { throw new BusinessException(LoginExceptionEnum.AUTH_FAILED); } cryptogramMobilePhone = pu.getEncryptPhone(); shareJedis.setPortalUserInfo(cryptogramMobilePhone, pu); } final Map<String, Object> returnMap = validateLogin(cryptogramMobilePhone, request, resp); return returnMap; } /** * 登录后的操作 * @param cryptogramMobilePhone * @param request * @param resp * @return */ @Override public Map<String, Object> validateLogin(final String cryptogramMobilePhone, final HttpServletRequest request, final HttpServletResponse resp) { final Map<String, Object> returnMap = new HashMap<>(); final PortalUser currentUser = shareJedis.getPortalUserInfo(PortalUser.class, cryptogramMobilePhone); log.info("long in currentUser : ========" + currentUser); if (null != currentUser) { // 取用户应用渠道 final String uuid = UUID.randomUUID().toString().replace("-", ""); request.getSession(true).setAttribute("JSESSIONID", uuid); // 登录后,对用户进行积分计算,存入缓存 shareJedis.portalUserLoginWithMsg(currentUser.getId().longValue()); request.getSession(true).setAttribute("session_user", currentUser); // 将用户应用渠道放到head中 // resp.setHeader("channel_code", channelCode); // 将用户记录放到session中,并放到head中 resp.setHeader("User-Info", new JsonMapper().toJson(currentUser)); cmssPortalUserService.updateLoginInfo(currentUser); if (currentUser.getLoginCount() != null) { currentUser.setLoginCount(currentUser.getLoginCount() + 1); } else { currentUser.setLoginCount(1); } final String index = cmssPortalUserService.getUserIndex(currentUser.getId()); currentUser.setIndex(index); returnMap.put("userInfo", currentUser); final Integer permission = permissionService.getPermissionLevel(currentUser); returnMap.put("permission", permission); returnMap.put("provProdTitle", permissionService.getProvProductTitle(permission, currentUser.getCompanyId(), currentUser)); returnMap.put("companyId", currentUser.getCompanyId()); final String redisKey = KEY_PREFIX + currentUser.getId(); if (shareJedis.exists(redisKey)) { returnMap.put("userDownloadTimes", shareJedis.get(redisKey)); } else { returnMap.put("userDownloadTimes", 0); } } else { log.info("Login error [" + cryptogramMobilePhone + "]"); throw new BusinessException(LoginExceptionEnum.ACCOUNT_NOT_EXIST); } return returnMap; } } 

图片验证码工具类

package com.chinamobile.cmss.share.utils; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.Random; import javax.imageio.ImageIO; import org.apache.commons.lang3.RandomUtils; import com.alibaba.druid.util.Base64; import com.chinamobile.cmss.dto.ValidateDto; /** * * @ClassName: ValidateCodeUtil * @Description: 验证码生成工具类 * @author yaohongan */ public class ValidateCodeUtil { private static ValidateDto validateDto = null; // 验证码类,用于最后返回此对象,包含验证码图片base64和真值 private static Random random = new Random(); // 随机类,用于生成随机参数 private static String randString = "0123456789abcdefghijkmnpqrtyABCDEFGHIJLMNQRTY";// 随机生成字符串的取值范围 private static int width = 80; // 图片宽度 private static int height = 34; // 图片高度 private static int StringNum = 4; // 字符的数量 private static int lineSize = 40; // 干扰线数量 // 将构造函数私有化 禁止new创建 private ValidateCodeUtil() { super(); } /** * 获取随机字符,并返回字符的String格式 * @param index (指定位置) * @return */ private static String getRandomChar(final int index) { // 获取指定位置index的字符,并转换成字符串表示形式 return String.valueOf(randString.charAt(index)); } /** * 获取随机指定区间的随机数 * @param min (指定最小数) * @param max (指定最大数) * @return */ private static int getRandomNum(final int min, final int max) { return RandomUtils.nextInt(min, max); } /** * 获得字体 * @return */ private static Font getFont() { return new Font("Fixedsys", Font.CENTER_BASELINE, 25); // 名称、样式、磅值 } /** * 获得颜色 * @param fc * @param bc * @return */ private static Color getRandColor(int frontColor, int backColor) { if (frontColor > 255) { frontColor = 255; } if (backColor > 255) { backColor = 255; } final int red = frontColor + random.nextInt(backColor - frontColor - 16); final int green = frontColor + random.nextInt(backColor - frontColor - 14); final int blue = frontColor + random.nextInt(backColor - frontColor - 18); return new Color(red, green, blue); } /** * 绘制字符串,返回绘制的字符串 * @param g * @param randomString * @param i * @return */ private static String drawString(final Graphics g, String randomString, final int i) { final Graphics2D g2d = (Graphics2D) g; g2d.setFont(getFont()); // 设置字体 g2d.setColor(new Color(random.nextFloat(), random.nextFloat(), random.nextFloat()));// 设置颜色 final String randChar = String.valueOf(getRandomChar(random.nextInt(randString.length()))); randomString += randChar; // 组装 final int rot = getRandomNum(5, 10); g2d.translate(random.nextInt(3), random.nextInt(3)); g2d.rotate(rot * Math.PI / 180); g2d.drawString(randChar, 13 * i, 20); g2d.rotate(-rot * Math.PI / 180); return randomString; } /** * 绘制干扰线 * @param g */ private static void drawLine(final Graphics g) { // 起点(x,y) 偏移量x1、y1 final int x = random.nextInt(width); final int y = random.nextInt(height); final int xl = random.nextInt(13); final int yl = random.nextInt(15); g.setColor(new Color(random.nextFloat(), random.nextFloat(), random.nextFloat())); g.drawLine(x, y, x + xl, y + yl); } /** * * @MethodName: getRandomCode * @Description: 生成Base64图片验证码 * @param key * @return String 返回base64 */ public static ValidateDto getRandomCode() { validateDto = validateDto == null ? new ValidateDto() : validateDto; // BufferedImage类是具有缓冲区的Image类,Image类是用于描述图像信息的类 final BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR); final Graphics g = image.getGraphics();// 获得BufferedImage对象的Graphics对象 g.fillRect(0, 0, width, height);// 填充矩形 g.setFont(new Font("Times New Roman", Font.ROMAN_BASELINE, 18));// 设置字体 g.setColor(getRandColor(110, 133));// 设置颜色 // 绘制干扰线 for (int i = 0; i <= lineSize; i++) { drawLine(g); } // 绘制字符 String randomString = ""; for (int i = 1; i <= StringNum; i++) { randomString = drawString(g, randomString, i); validateDto.setValue(randomString); } g.dispose();// 释放绘图资源 ByteArrayOutputStream bs = null; try { bs = new ByteArrayOutputStream(); ImageIO.write(image, "png", bs);// 将绘制得图片输出到流 final String imgsrc = Base64.byteArrayToBase64(bs.toByteArray()); validateDto.setBase64Str(imgsrc); } catch (final Exception e) { e.printStackTrace(); } finally { try { bs.close(); } catch (final IOException e) { e.printStackTrace(); } finally { bs = null; } } return validateDto; } } 

验证码entity

package com.chinamobile.cmss.dto; import java.io.Serializable; /** * * @ClassName: ValidateDto * @Description: 验证码类 * @author yaohongan */ public class ValidateDto implements Serializable { private static final long serialVersionUID = 1L; private String Base64Str; // Base64 值 private String value; // 验证码值 public String getBase64Str() { return Base64Str; } public void setBase64Str(final String base64Str) { Base64Str = base64Str; } public String getValue() { return value; } public void setValue(final String value) { this.value = value; } }

发送短信代码

package com.chinamobile.cmss.share.service.impl; import java.io.StringWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.annotation.Resource; import javax.servlet.ServletContext; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.web.context.ContextLoader; import org.springframework.web.context.WebApplicationContext; import com.base.util.mapper.JsonMapper; import com.chinamobile.cmss.share.entity.CmssDict; import com.chinamobile.cmss.share.entity.CmssLogAccess; import com.chinamobile.cmss.share.entity.CmssOperationsUser; import com.chinamobile.cmss.share.entity.CmssSmsRedisEntity; import com.chinamobile.cmss.share.entity.PortalUser; import com.share.utils.ShareJedis; import freemarker.template.Configuration; import freemarker.template.Template; /** * * @ClassName: BatchSmsService * @Description: 批量发送短信 * @author zhangle * */ @SuppressWarnings("boxing") @Service("cmssBatchSmsService") public class CmssBatchSmsService { /** * 发送短信验证码 * @param portalUser */ public void sendSmsValidationCode(final String phone, final String smsCode) { final WebApplicationContext webApplicationContext = ContextLoader.getCurrentWebApplicationContext(); final ServletContext servletContext = webApplicationContext.getServletContext(); final Configuration cfg = new Configuration(); cfg.setServletContextForTemplateLoading(servletContext, "/WEB-INF/templates"); final Map<String, Object> content = new HashMap<String, Object>(16); content.put("smsCode", smsCode); content.put("smsTime", smsTime); Template t; try { t = cfg.getTemplate("new_user_sms.ftl", "utf-8"); final StringWriter writer = new StringWriter(); t.process(content, writer); final String smsContent = writer.toString(); // log.info("=======================smsContent: "+smsContent); sendShortMessage(smsContent, Arrays.asList(new String[] { phone })); } catch (final Exception e) { log.info("用户手机号为[" + phone + "]发送短信失败!", e); } } } 




原文链接:https://yq.aliyun.com/articles/603429
关注公众号

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。

持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。

文章评论

共有0条评论来说两句吧...

文章二维码

扫描即可查看该文章

点击排行

推荐阅读

最新文章