一、登陆 1.1 表结构的设计
DROP TABLE IF EXISTS `miaosha_user`;
CREATE TABLE `miaosha_user` (
`id` bigint(20) NOT NULL COMMENT '用户ID,手机号码',
`nickname` varchar(255) NOT NULL COMMENT '用户昵称',
`password` varchar(32) DEFAULT NULL COMMENT 'MD5(MD5(pass明文+固定salt) + salt)',
`salt` varchar(10) DEFAULT NULL,
`head` varchar(128) DEFAULT NULL COMMENT '头像,云存储的ID',
`register_date` datetime DEFAULT NULL COMMENT '注册时间',
`last_login_date` datetime DEFAULT NULL COMMENT '上蔟登录时间',
`login_count` int(11) DEFAULT '0' COMMENT '登录次数',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
复制代码
1.2 两次md5的实现
原理: 将明文密码进行第一次md5加密(加固定盐值)
以后在网络中进行传输没,服务端拿到的是表单密码,将表单密码进行第二次加密成dbPassword,根据用户输出的userId查得user对象,进行密码匹配。
好处:1. 可以避免明文密码直接在网络中传输,减少安全风险;2. 及时用户获取db中存储得密码,也是用户密码进行二次md5加密后得结果(第一次加密固定盐值,第二次加密生成一个随即得盐值),无法直接反查彩虹表得到明文密码,进一步提高了用户登陆得安全系数。
public final static String salt = "d1o2n3g4j5u";
/**
* 第一次MD5
* 对用户输入的密码进行加盐值然后进行MD5加密,加密后的密码是(进行网络传输时展示的密码)
*
* @param inputPass
* @return
*/
public static String inputPassToFormPass(String inputPass) {
String data = "" + salt.charAt(0) + salt.charAt(2) + inputPass + salt.charAt(5) + salt.charAt(4);
return md5(data);
}
/**
* 第二次MD5
* 表单密码转换成数据库密码,dbPass是db中存储的密码
*
* @param formPass
* @param dbSalt 这个盐值是随即生成的,保存到db当中
* @return
*/
public static String formPassToDbPass(String formPass, String dbSalt) {
String data = dbSalt.charAt(1) + dbSalt.charAt(0) + formPass + dbSalt.charAt(4) + dbSalt.charAt(5);
return md5(data);
}
/**
* 输入的密码直接转换成数据库密码
*
* @param inputPass
* @param dbSalt
* @return
*/
public static String inputPassToDbPass(String inputPass, String dbSalt) {
String formPass = inputPassToFormPass(inputPass);
return formPassToDbPass(formPass, dbSalt);
}
/**
* MD5
* 对传入的字符串进行加密然后返回加密结果。
*
* @param data
* @return
*/
public static String md5(String data)
// 相关的maven依赖
<!--MD5加密依赖-->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.6</version>
</dependency>
复制代码
1.3 用户登陆参数校验
(1)构建客户端登陆请求参数对象loginDTO
(2) 给loginDTO中的相应对象加上常用的校验注解
(3) 自定义手机号校验注解并注解到loginDTO对象的mobole参数上
(4) controller层的loginDTO参数加上@Vaild注解
自定义@mobile注解进行手机号参数校验
[
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;
/**
* Created by chenxiong on 18/12/4.
*/
@Documented
@Target(value = {ElementType.FIELD,ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {MobileConstraintValidator.class})
public @interface IsMobile {
boolean required() default true;
String message() default "手机号码格式错误";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
]
[
import org.apache.commons.lang.StringUtils;
import javax.validation.Constraint;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import javax.validation.ConstraintViolation;
/**
* Created by chenxiong on 18/12/4.
* 使用@Constraint注解需要自定义一个实现ConstraintValidator接口的校验类。
* 注解@Constraint注解在自定义注解@a上,@a注解在类B上
* 若类B的作为参数并被@Valid注解所注解,哪么将会调用如下的initialize()和isValid()方法进行参数校验
*/
public class MobileConstraintValidator implements ConstraintValidator<IsMobile,String> {
private boolean required = false;
@Override
public void initialize(IsMobile isMobileAnnotation) {
required = isMobileAnnotation.required();
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if (required == false || StringUtils.isEmpty(value)){
return true;
}else {
return ValidatorUtil.isMobile(value);
}
}
}
]
[
import org.apache.commons.lang.StringUtils;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Created by chenxiong on 18/12/4.
* 校验工具类
*/
public class ValidatorUtil {
// 1开头,接十位数字
private static final Pattern mobile_pattern = Pattern.compile("1\\d{10}");
/**
* 简单校验手机号码是否合法
*
* @param mobileNum
* @return
*/
public static boolean isMobile(String mobileNum){
if (StringUtils.isEmpty(mobileNum)){
return false;
}
Matcher matcher = mobile_pattern.matcher(mobileNum);
return matcher.matches();
}
}
]
复制代码