登录模块(手机验证码)

本人为实习生,第一次写博客,写的不好的大家多多谅解

应公司近期需求,需要单独开发一个后台管理系统。

自己按实际业务写了一个登录接口已经实现,时序图如下



源码牵扯业务量太大,这里只放出部分关键实现源码,整合思路可以配合时序图去理解。

Controller层

package com.royalnu.business.login.franchisee.gateway.web;

import java.sql.Timestamp;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.List;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.poi.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.alibaba.druid.util.StringUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.royalnu.common.exception.CommonException;
import com.royalnu.common.security.MD5Utils;
import com.royalnu.common.utils.json.GsonUtil;
import com.royalnu.common.validate.json.JsonSchemaValidator;
import com.royalnu.core.component.cache.redis.service.StringRedisCache;
import com.royalnu.core.module.com.BaseController;
import com.royalnu.business.login.franchisee.api.model.Franchisee;
import com.royalnu.business.login.franchisee.api.service.FranchiseeService;
import com.royalnu.business.login.franchiseeDetailed.api.model.FranchiseeDetailed;
import com.royalnu.business.login.franchiseeDetailed.api.service.FranchiseeDetailedService;
import com.royalnu.business.login.message.api.model.Message;
import com.royalnu.business.login.message.api.service.MessageService;
import com.royalnu.util.FilePath;
import com.royalnu.util.FranchiseeMethodUtils;
import com.royalnu.util.FranchiseeParamUtils;
import com.royalnu.util.InitializationUtil;
import com.royalnu.util.IpUtil;
import com.royalnu.util.RedisKeyPrefixUtil;
import com.royalnu.util.SingleSendSms;
import com.royalnu.util.VerifyCode;

import lombok.extern.log4j.Log4j2;


@Log4j2
@SuppressWarnings("unused")
@RestController
@RequestMapping(value = "/franchisee/login")
public class FranchiseeController extends BaseController<Franchisee> {

	@Autowired
	private FilePath filePath;
	@Resource
	private FranchiseeService franchiseeService;
	@Resource
	private FranchiseeDetailedService franchiseeDetailedService;
	@Resource
	private MessageService messageService;
	@Resource
	private StringRedisCache stringRedisCache;

	@Autowired
	private HttpSession session;

	private IpUtil ipUtil = new IpUtil();

	

	// 加盟商登录入口 附手机验证码
	@RequestMapping(value = "/dologin", method = RequestMethod.POST)
	public String dologin(Franchisee franchisee, HttpServletRequest request,HttpServletResponse response) throws CommonException {
		Map<String, Object> data = new HashMap<String, Object>();
		Map<String, Object> params = new HashMap<>();
		// 验证请求手机号
		String codeTelephone = request.getParameter("codeTelephone");
		// 验证码
		String codeNum = request.getParameter("codeNum");
		// 获取ip地址
		String UserIp = ipUtil.getIpAddr(request);
		// 获取系统当前时间
		Timestamp currentTime = new Timestamp(System.currentTimeMillis());
		// 模拟前端加密传参
		/*String idip = "ww-" + franchisee.getTelephone() + "{xykj}" + UserIp + "+lsw";*/
		
		String  idipPassword = request.getParameter("idipPassword");
		// 后台解密获取正确参数
		if(idipPassword==null||idipPassword.equals("")) {
			data.put("code", 2);
			data.put("msg", "访问源IP地址非法,请确认");
			return GsonUtil.GSON.toJson(data);
		}
		String idipPassword1 = idipPassword.substring(3, idipPassword.length() - 4).replace("{xykj}", "");
		Message message1 = messageService.getNewestMessage(codeTelephone);
		Franchisee franchisee1 = franchiseeService.selectByQuery(franchisee);
		if (franchisee1 == null) {
			data.put("code", 1);
			data.put("msg", "账号或密码输入错误");
			return GsonUtil.GSON.toJson(data);
		} else if (!idipPassword1.equals(franchisee.getTelephone() + UserIp)) {
			data.put("code", 2);
			data.put("msg", "访问源IP地址非法,请确认");
			return GsonUtil.GSON.toJson(data);
		}

		int count = franchiseeDetailedService.selectTelephoneByCount(franchisee.getTelephone());
		if (count <= 0) {
			FranchiseeDetailed fd1 = new FranchiseeDetailed();
			fd1.setCreateTime(new Date());
			fd1.setRealIp(UserIp);
			fd1.setFId(franchisee1.getId());
			// 插入加盟商详细表记录登录情况
			franchiseeDetailedService.insertSelective(fd1);
		}
		FranchiseeDetailed fd = franchiseeDetailedService.selectByTelephone(franchisee1.getTelephone());
		// 判断前端是否接受到参数
		if (codeTelephone == null || codeTelephone.equals("") && codeNum == null || codeNum.equals("")) {
			// 当天是否获取过验证码,同天IP地址是否发生改变
			if (fd != null && fd.getLastTime() != null && fd.getLastTime().getYear() == currentTime.getYear()
					&& fd.getLastTime().getMonth() == currentTime.getMonth()
					&& fd.getLastTime().getDay() == currentTime.getDay() && UserIp.equals(fd.getRealIp())) {
				String token = MD5Utils.md5(franchisee.getUserName()
						+ franchisee.getPassword() + System.currentTimeMillis());
				fd = franchiseeDetailedService.selectByTelephone(franchisee1.getTelephone());
				fd.setRealIp(UserIp);
				fd.setFId(franchisee1.getId());
				fd.setLastTime(new Date());
				fd.setToken(token);
				// 插入加盟商详细表记录登录情况
				franchiseeDetailedService.updateByPrimaryKeySelective(fd);
				//插入cokie,redis
				this.getUserCokieRedis(franchisee, response);
				data.put("code", 3);
				data.put("msg", "登陆成功");
				return GsonUtil.GSON.toJson(data);
				// 需要重新获取新验证码
			} else if (fd == null || fd.getLastTime() == null
					|| (fd.getLastTime().getYear() != currentTime.getYear()
							|| fd.getLastTime().getMonth() != currentTime.getMonth()
							|| fd.getLastTime().getDay() != currentTime.getDay())
					|| !UserIp.equals(fd.getRealIp())) {
				fd = franchiseeDetailedService.selectByTelephone(franchisee1.getTelephone());
				fd.setRealIp(UserIp);
				fd.setUpdateTime(new Date());
				fd.setFId(franchisee1.getId());
				franchiseeDetailedService.updateByPrimaryKeySelective(fd);
				data.put("code", 4);
				data.put("msg", "系统检测您在一台新的设备或者当天第一次登录,为保障您\r\n" + 
						"的账户安全,需要进行一次身份核实。");
				return GsonUtil.GSON.toJson(data);
			} else {
				data.put("code", 5);
				data.put("msg", "检测到异常");
				return GsonUtil.GSON.toJson(data);
			}
			// 需要验证码登录
		} else {
			if (message1 == null) {
				data.put("code", 6);
				data.put("msg", "验证码发送异常,请重新获取验证码");
				return GsonUtil.GSON.toJson(data);
			} else if (messageService.getCurListCount(params) >= 100) {
				data.put("code", 7);
				data.put("msg", "验证码获取次数超限,请联系运营人员");
				return GsonUtil.GSON.toJson(data);
			} else if (!codeNum.equals(message1.getCode())) {
				fd = franchiseeDetailedService.selectByTelephone(franchisee1.getTelephone());
				fd.setRealIp(UserIp);
				fd.setFId(franchisee1.getId());
				fd.setUpdateTime(new Date());
				// 插入加盟商详细表记录登录情况
				franchiseeDetailedService.updateByPrimaryKeySelective(fd);
				data.put("code", 8);
				data.put("msg", "验证码输入错误");
				return GsonUtil.GSON.toJson(data);
			} else {
				String token = MD5Utils.md5(franchisee.getUserName()
						+ franchisee.getPassword() + System.currentTimeMillis());
				fd = franchiseeDetailedService.selectByTelephone(franchisee1.getTelephone());
				fd.setRealIp(UserIp);
				fd.setFId(franchisee1.getId());
				fd.setLastTime(new Date());
				fd.setToken(token);
				// 插入加盟商详细表记录登录情况
				franchiseeDetailedService.updateByPrimaryKeySelective(fd);
				//插入cokie,redis
				this.getUserCokieRedis(franchisee, response);
				data.put("code", 3);
				data.put("msg", "登陆成功");
				return GsonUtil.GSON.toJson(data);
			}
		}
	}

	
	//获取验证码方法
	@RequestMapping(value = "/dogetCode", method = RequestMethod.POST)
	public String getCode(HttpServletRequest request) throws Exception {
		Map<String, Object> data = new HashMap<String, Object>();
		// 验证请求手机号
		String codeTelephone = request.getParameter("codeTelephone");
		// 新增验证码
		Message message = new Message();
		message.setTelephone(codeTelephone);
		// 生成验证码
		VerifyCode v = new VerifyCode();
		String code = v.productCode();
		// 发送验证码
		SingleSendSms app = new SingleSendSms();
		app.sendMsg(codeTelephone, code);
		// 插入消息
		message.setCode(code);
		message.setCreatetime(new Date());
		message.setState(1);
		messageService.insertSelective(message);
		data.put("code", 5);
		data.put("msg", "已经发送验证码,请查收");
		return GsonUtil.GSON.toJson(data);
	}
	
	
	//插入cokie,redis
	public void getUserCokieRedis(Franchisee franchisee,
			HttpServletResponse response) {
		Franchisee franchisee1 = franchiseeService.selectByQuery(franchisee);
		// 登录名+密码+时间戳进行md5加密生产token
		String token = MD5Utils.md5(franchisee1.getUserName()
				+ franchisee1.getPassword() + System.currentTimeMillis());
		// 发送cookie
		FranchiseeMethodUtils.responseCookie(response, franchisee1.getId(),
				franchisee1.getUserName(), token);
		// 往缓存放置登录token,以便后续所有操作的验证
		stringRedisCache.set(FranchiseeParamUtils.REDIS_FRANCHISEE_PREFIX
				+ franchisee1.getUserName() + "-" + franchisee1.getId(), token,
				FranchiseeParamUtils.REDIS_TIMEOUT_TOKEN,
				FranchiseeParamUtils.REDIS_UNIT_TOKEN);
	}

}

获取用户IP地址

package com.royalnu.util;

import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;

public class IpUtil {
    /**
     * 获取登录用户IP地址
     * 
     * @param request
     * @return
     */
    public static String getIpAddr(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
            if (ip.equals("127.0.0.1")) {
                //根据网卡取本机配置的IP
                InetAddress inet = null;
                try {
                    inet = InetAddress.getLocalHost();
                } catch (UnknownHostException e) {
                    e.printStackTrace();
                }
                ip = inet.getHostAddress();
            }
        }
        // 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
        if(ip != null && ip.length() > 15){
            if(ip.indexOf(",") > 0){
                ip = ip.substring(0, ip.indexOf(","));
            }
        }
        return ip;
    }
}

验证码实体类

package com.royalnu.util;


import com.royalnu.core.module.com.Identifiable;
import java.util.Date;

import lombok.Getter;
import lombok.Setter;

@Setter
@Getter
public class Message extends Identifiable {
private static final long serialVersionUID = 1L;

    /**
     * <pre>
     * </pre>
     * 
     */
    private String telephone;

    /**
     * <pre>
     * </pre>
     * 
     */
    private String code;

    /**
     * <pre>
     * </pre>
     * 
     */
    private Date createtime;

    /**
     * <pre>
     * </pre>
     * 
     */
    private String connectId;

    /**
     * <pre>
     * </pre>
     * 
     */
    private Integer state;

    /**
     * <pre>
     * </pre>
     * 
     */
    private String remark;

}
产生随机数(验证码)
package com.royalnu.util;

import java.util.Random;

public class MyRandom {
	static Random r = new Random();
    static String ssource = "0123456789";
    static char[] src = ssource.toCharArray();
    //产生随机字符串
    private static String randString (int length)
    {
            char[] buf = new char[length];
            int rnd;
            for(int i=0;i<length;i++)
            {
                    rnd = Math.abs(r.nextInt()) % src.length;
                    buf[i] = src[rnd];
            }
            return new String(buf);
    }
    //调用该方法,产生随机字符串,
    //参数i: 为字符串的长度
    public static String runVerifyCode(int i)
    {
            String VerifyCode = randString(i);
            return VerifyCode;
    }
    
    public static void main(String[] args) {
     MyRandom t=new MyRandom();
     System.out.println(t.runVerifyCode(6));
 }
}
package com.royalnu.util;


import java.util.Random;

public class VerifyCode {

	private int codeCount = 6;

	char[] codeSequence = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };

	public String productCode() {

		// 创建一个随机数生成器类
		Random random = new Random();

		// randomCode用于保存随机产生的验证码,以便用户登录后进行验证。
		StringBuffer randomCode = new StringBuffer();
		// 随机产生codeCount数字的验证码。
		for (int i = 0; i < codeCount; i++) {
			// 得到随机产生的验证码数字。
			String strRand = String.valueOf(codeSequence[random.nextInt(10)]);

			// 将产生的四个随机数组合在一起。
			randomCode.append(strRand);
		}

		return randomCode.toString();
	}

	public static void main(String[] args) {
		VerifyCode v = new VerifyCode();
		System.out.println(v.productCode());
	}
}

云通信短信API产品(需要pom.xml)

package com.royalnu.util;


import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;

public class SingleSendSms {
	// private final static String APP_KEY = "23865664"; // AppKey从控制台获取
	// private final static String APP_SECRET =
	// "4683eef32debc7e0d9847dc5924e0345"; // AppSecret从控制台获取
	// private final static String SIGN_NAME = "创跃网络科技公司"; //
	// 签名名称从控制台获取,必须是审核通过的
	// private final static String TEMPLATE_CODE = "SMS_72940060"; //
	// 模板CODE从控制台获取,必须是审核通过的
	// private final static String HOST = "sms.market.alicloudapi.com"; //
	// API域名从控制台获取

	// 产品名称:云通信短信API产品,开发者无需替换
	static final String product = "Dysmsapi";
	// 产品域名,开发者无需替换
	static final String domain = "dysmsapi.aliyuncs.com";

	static final String accessKeyId = "LTAIyH6tgxGSmnXK";
	static final String accessKeySecret = "cBmLUp1FyoEVPA7swkwoTXj5fOKzb3";

	/*
	 * 尊敬的${customer},欢迎您使用阿里大鱼短信服务,阿里大鱼将为您提供便捷的通信服务!
	 */

	private final static String ERRORKEY = "errorMessage"; // 返回错误的key

	// @phoneNum: 目标手机号,多个手机号可以逗号分隔;
	// @params: 短信模板中的变量,数字必须转换为字符串,如短信模板中变量为${no}",则参数params的值为{"no":"123456"}
	public void sendMsg(String phoneNum, String params) throws Exception {

		System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
		System.setProperty("sun.net.client.defaultReadTimeout", "10000");

		// 初始化acsClient,暂不支持region化
		IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou",
				accessKeyId, accessKeySecret);
		DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product,
				domain);
		IAcsClient acsClient = new DefaultAcsClient(profile);

		// 组装请求对象-具体描述见控制台-文档部分内容
		SendSmsRequest request = new SendSmsRequest();
		// 必填:待发送手机号
		request.setPhoneNumbers(phoneNum);
		// 必填:短信签名-可在短信控制台中找到
		request.setSignName("十一分便利店");
		// 必填:短信模板-可在短信控制台中找到
		request.setTemplateCode("SMS_115680033");
		// 可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为
		request.setTemplateParam("{\"code\":" + "\"" + params + "\"}");

		// 选填-上行短信扩展码(无特殊需求用户请忽略此字段)
		// request.setSmsUpExtendCode("90997");

		// 可选:outId为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者
		request.setOutId("yourOutId");
		SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);

		/*
		 * String path = "/singleSendSms";
		 * 
		 * Request request = new Request(Method.GET, HttpSchema.HTTP + HOST,
		 * path, APP_KEY, APP_SECRET, Constants.DEFAULT_TIMEOUT);
		 * 
		 * // 请求的query Map<String, String> querys = new HashMap<String,
		 * String>(); querys.put("SignName", SIGN_NAME);
		 * querys.put("TemplateCode", TEMPLATE_CODE); querys.put("RecNum",
		 * phoneNum); querys.put("ParamString", params);
		 * request.setQuerys(querys);
		 * 
		 * try { Map<String, String> bodymap = new HashMap<String, String>();
		 * Response response = Client.execute(request); //
		 * 根据实际业务需要,调整对response的处理 if (null == response) {
		 * System.out.println("no response"); } else if (200 !=
		 * response.getStatusCode()) { System.out.println("StatusCode:" +
		 * response.getStatusCode()); System.out .println("ErrorMessage:" +
		 * response.getErrorMessage()); System.out.println("RequestId:" +
		 * response.getRequestId()); } else { bodymap =
		 * ReadResponseBodyContent(response.getBody()); if (null !=
		 * bodymap.get(ERRORKEY)) { // 当传入的参数不合法时,返回有错误说明
		 * System.out.println(JSON.toJSONString(bodymap));
		 * System.out.println(bodymap.get(ERRORKEY)); } else { //
		 * 成功返回map,对应的key分别为:message、success等
		 * System.out.println(JSON.toJSONString(bodymap)); } } } catch
		 * (Exception e) { System.out.println(e.getMessage()); }
		 */
	}

	private Map<String, String> ReadResponseBodyContent(String body) {
		Map<String, String> map = new HashMap<String, String>();
		try {
			JSONObject jsonObject = JSON.parseObject(body);
			if (null != jsonObject) {
				for (Entry<String, Object> entry : jsonObject.entrySet()) {
					map.put(entry.getKey(), entry.getValue().toString());
				}
			}
			if ("false".equals(map.get("success"))) {
				map.put(ERRORKEY, map.get("message"));
			}
		} catch (Exception e) {
			map.put(ERRORKEY, body);
		}
		return map;
	}

	public static void main(String agrs[]) throws Exception {
		SingleSendSms app = new SingleSendSms();
		app.sendMsg("15817219181", "123456");
		// app.sendMsg("15018669294", "{'customer':'David'}");
		System.out.println("success");
	}
}
<!-- 阿里云短信服务 -->
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>fastjson</artifactId>
			<version>1.2.15</version>
		</dependency>
		<dependency>
    		<groupId>com.aliyun</groupId>
			  <artifactId>aliyun-java-sdk-core</artifactId>
			  <version>3.2.3</version>
		</dependency>
		
		<dependency>
    		<groupId>com.aliyun</groupId>
			<artifactId>aliyun-java-sdk-dysmsapi</artifactId>
			<version>1.0.0</version>
		</dependency>
		
		<dependency>
    		<groupId>com.royalnu</groupId>
			<artifactId>ms-message</artifactId>
			<version>0.0.1-SNAPSHOT</version>
		</dependency>




  • 8
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值