Commit d2d3afe0 authored by zengtianlai3's avatar zengtianlai3

修改多因子认证

parent 914a09b3
...@@ -144,6 +144,12 @@ ...@@ -144,6 +144,12 @@
<version>1.9</version> <version>1.9</version>
</dependency> </dependency>
<!--邮件-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency> <dependency>
<groupId>com.sixiang.iot</groupId> <groupId>com.sixiang.iot</groupId>
<artifactId>server-license</artifactId> <artifactId>server-license</artifactId>
......
...@@ -12,11 +12,16 @@ import iot.sixiang.license.log.MyLog; ...@@ -12,11 +12,16 @@ import iot.sixiang.license.log.MyLog;
import iot.sixiang.license.model.BaseResult; import iot.sixiang.license.model.BaseResult;
import iot.sixiang.license.model.ResResult; import iot.sixiang.license.model.ResResult;
import iot.sixiang.license.model.vo.LoginVo; import iot.sixiang.license.model.vo.LoginVo;
import iot.sixiang.license.util.CommonUtil;
import iot.sixiang.license.util.EmailUtils;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.DigestUtils; import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore; import springfox.documentation.annotations.ApiIgnore;
import javax.annotation.Resource;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
...@@ -30,6 +35,12 @@ import java.util.Map; ...@@ -30,6 +35,12 @@ import java.util.Map;
@Api(value = "登录模块", tags = {"登录模块"}) @Api(value = "登录模块", tags = {"登录模块"})
public class LoginController { public class LoginController {
@Resource
EmailUtils emailUtils;
@Value("${spring.mail.to}")
private String account;
//模拟数据库 //模拟数据库
static Map<String, LoginUser> userMap = new HashMap<>(); static Map<String, LoginUser> userMap = new HashMap<>();
...@@ -43,17 +54,20 @@ public class LoginController { ...@@ -43,17 +54,20 @@ public class LoginController {
*/ */
@ApiOperation(value = "登录接口", notes = "登录接口") @ApiOperation(value = "登录接口", notes = "登录接口")
@GetMapping("login") @GetMapping("login")
@MyLog(title = "登录", optParam = "#{userName},#{password}", businessType = BusinessType.OTHER) @MyLog(title = "登录", optParam = "#{userName},#{password},#{code}", businessType = BusinessType.OTHER)
@ApiImplicitParams({ @ApiImplicitParams({
@ApiImplicitParam(name = "userName", value = "用户名", required = true), @ApiImplicitParam(name = "userName", value = "用户名", required = true),
@ApiImplicitParam(name = "password", value = "密码", required = true) @ApiImplicitParam(name = "password", value = "密码", required = true),
@ApiImplicitParam(name = "code", value = "验证码", required = true)
}) })
public ResResult<LoginVo> login(@RequestParam("userName") String userName, @RequestParam("password") String password) { public ResResult<LoginVo> login(@RequestParam("userName") String userName, @RequestParam("password") String password, @RequestParam("code") String code) {
if (StringUtils.isEmpty(userName) || StringUtils.isEmpty(password) || StringUtils.isEmpty(code)) {
return ResResult.validate_failed().setMsgValue("参数不能为空");
}
for (LoginUser dbUser : userMap.values()) { for (LoginUser dbUser : userMap.values()) {
String account = dbUser.getUserName(); String name = dbUser.getUserName();
String psw = account + dbUser.getPassword(); String psw = name + dbUser.getPassword();
if (DigestUtils.md5DigestAsHex(account.getBytes()).equals(userName) && DigestUtils.md5DigestAsHex(psw.getBytes()).equals(password)) { if (DigestUtils.md5DigestAsHex(name.getBytes()).equals(userName) && DigestUtils.md5DigestAsHex(psw.getBytes()).equals(password)) {
// 登录错误次数 // 登录错误次数
Integer errCnt = UserUtils.getErrCnt(userName); Integer errCnt = UserUtils.getErrCnt(userName);
Date countFreezeDate = UserUtils.getCountFreezeDate(userName); Date countFreezeDate = UserUtils.getCountFreezeDate(userName);
...@@ -61,6 +75,8 @@ public class LoginController { ...@@ -61,6 +75,8 @@ public class LoginController {
if (errCnt != null && errCnt >= 3 && countFreezeDate != null && curDate.before(countFreezeDate)) { if (errCnt != null && errCnt >= 3 && countFreezeDate != null && curDate.before(countFreezeDate)) {
return ResResult.failed().setMsgValue("用户名或密码错误次数达到三次,请三分钟后再重试"); return ResResult.failed().setMsgValue("用户名或密码错误次数达到三次,请三分钟后再重试");
} else { } else {
Date curCodeDate = new Date();
if (code.equals(UserUtils.getEmailCode(account)) && curCodeDate.before(UserUtils.getEmailCodeExpTime(account))) {
String token = JwtUtil.createToken(dbUser); String token = JwtUtil.createToken(dbUser);
LoginVo loginVo = new LoginVo(); LoginVo loginVo = new LoginVo();
loginVo.setAuthorization(token); loginVo.setAuthorization(token);
...@@ -68,8 +84,13 @@ public class LoginController { ...@@ -68,8 +84,13 @@ public class LoginController {
UserUtils.setTokenExp(dbUser.getUserId(), JwtUtil.getTokenExp()); UserUtils.setTokenExp(dbUser.getUserId(), JwtUtil.getTokenExp());
UserUtils.removeErrCnt(userName); UserUtils.removeErrCnt(userName);
UserUtils.removeCountFreezeDate(userName); UserUtils.removeCountFreezeDate(userName);
UserUtils.removeEmailCode(account);
UserUtils.removeEmailCodeExpTime(account);
log.info("登录成功!生成token!"); log.info("登录成功!生成token!");
return ResResult.success().goRecord(loginVo); return ResResult.success().goRecord(loginVo);
} else {
return ResResult.failed().setMsgValue("验证码错误或已过期");
}
} }
} }
} }
...@@ -115,4 +136,15 @@ public class LoginController { ...@@ -115,4 +136,15 @@ public class LoginController {
return BaseResult.unauthorized(); return BaseResult.unauthorized();
} }
@ApiOperation(value = "发送验证码", notes = "发送验证码到邮箱")
@GetMapping("send_code")
public BaseResult sendCode() {
String code = CommonUtil.getValidateCode();
String content = "感谢您使用实名制服务器" + "\n" + "此次登录验证码为:" + code + "(有效期三分钟)。验证码提供给他人可能导致账号被盗,请勿转发或泄露。" + "\n" + "--------------------------------------------------------------" + "此邮件由系统自动发送,请勿回复此邮件" + "--------------------------------------------------------------";
emailUtils.sendSimpleMail(account, "感谢您使用实名制服务器", content);
UserUtils.setEmailCode(account, code);
Date codeExpTime = new Date(System.currentTimeMillis() + 3 * 60 * 1000);
UserUtils.setEmailCodeExpTime(account, codeExpTime);
return BaseResult.success();
}
} }
...@@ -18,6 +18,7 @@ import java.util.Map; ...@@ -18,6 +18,7 @@ import java.util.Map;
@WebFilter(filterName = "jwtFilter", urlPatterns = "/*") @WebFilter(filterName = "jwtFilter", urlPatterns = "/*")
public class JwtFilter implements Filter { public class JwtFilter implements Filter {
private static final String url1 = "/login"; private static final String url1 = "/login";
private static final String url2 = "/send_code";
private static final String url3 = "/doc.html"; private static final String url3 = "/doc.html";
private static final String url4 = "/v2/api-docs"; private static final String url4 = "/v2/api-docs";
private static final String url7 = "/swagger-resources"; private static final String url7 = "/swagger-resources";
...@@ -44,7 +45,7 @@ public class JwtFilter implements Filter { ...@@ -44,7 +45,7 @@ public class JwtFilter implements Filter {
boolean check = true; boolean check = true;
String uri = request.getRequestURI(); String uri = request.getRequestURI();
if (uri.contains(url1)|| uri.contains(url3) || uri.contains(url4) || uri.contains(url7) || uri.contains(url8)) { if (uri.contains(url1)|| uri.contains(url2) || uri.contains(url3) || uri.contains(url4) || uri.contains(url7) || uri.contains(url8)) {
if (uri.contains(url1)) { if (uri.contains(url1)) {
uri = XssUtil.checkXSS(uri); uri = XssUtil.checkXSS(uri);
UserUtils.setUri(uri); UserUtils.setUri(uri);
......
...@@ -13,6 +13,8 @@ public abstract class UserUtils { ...@@ -13,6 +13,8 @@ public abstract class UserUtils {
static Map<String, String> tokenMap = new HashMap<>(); static Map<String, String> tokenMap = new HashMap<>();
static Map<String, Date> tokenExpTimeMap = new HashMap<>(); static Map<String, Date> tokenExpTimeMap = new HashMap<>();
static Map<String, Integer> errCntMap = new HashMap<>(); static Map<String, Integer> errCntMap = new HashMap<>();
static Map<String, String> emailCodeMap = new HashMap<>();
static Map<String, Date> emailCodeExpTimeMap = new HashMap<>();
static Map<String, Date> countFreezeDateMap = new HashMap<>(); static Map<String, Date> countFreezeDateMap = new HashMap<>();
/** /**
* 线程变量,存放user实体类信息,即使是静态的也与其他线程也是隔离的 * 线程变量,存放user实体类信息,即使是静态的也与其他线程也是隔离的
...@@ -112,4 +114,30 @@ public abstract class UserUtils { ...@@ -112,4 +114,30 @@ public abstract class UserUtils {
public static void removeCountFreezeDate(String uId) { public static void removeCountFreezeDate(String uId) {
countFreezeDateMap.remove(uId); countFreezeDateMap.remove(uId);
} }
public static void setEmailCode(String email, String code) {
emailCodeMap.put(email, code);
}
public static String getEmailCode(String email) {
return emailCodeMap.get(email);
}
public static void removeEmailCode(String email) {
emailCodeMap.remove(email);
}
public static void setEmailCodeExpTime(String email, Date expTime) {
emailCodeExpTimeMap.put(email, expTime);
}
public static Date getEmailCodeExpTime(String email) {
return emailCodeExpTimeMap.get(email);
}
public static void removeEmailCodeExpTime(String email) {
emailCodeExpTimeMap.remove(email);
}
} }
...@@ -17,6 +17,24 @@ import java.util.Locale; ...@@ -17,6 +17,24 @@ import java.util.Locale;
@Slf4j @Slf4j
public class CommonUtil { public class CommonUtil {
/**
* 获取随机验证码
*/
public static String getValidateCode() {
SecureRandom random = new SecureRandom();
try {
random = SecureRandom.getInstance("SHA1PRNG");
} catch (NoSuchAlgorithmException e) {
log.error(e.getMessage());
}
StringBuilder validateCode = new StringBuilder();
for (int i = 0; i < 6; i++) {
validateCode.append(random.nextInt(10));
}
return validateCode.toString();
}
/** /**
* 随机生成指定长度的字符串 * 随机生成指定长度的字符串
* *
......
package iot.sixiang.license.util;
import iot.sixiang.license.handler.IotLicenseException;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* Title: EmailUtils
* Description:
*
* @author YFW
* @version V1.0
* @date 2020-05-23
*/
@Slf4j
@Component
public class EmailUtils {
Logger logger = LoggerFactory.getLogger(EmailUtils.class);
@Value("${spring.mail.username}")
private String from;
@Resource
public JavaMailSender mailSender;
public void sendSimpleMail(String to, String subject, String content) {
SimpleMailMessage message = new SimpleMailMessage();
//发件人
message.setFrom(from);
//目标
message.setTo(to);
//主题
message.setSubject(subject);
//内容
message.setText(content);
try {
mailSender.send(message);
logger.info("一份简单邮件已发送。");
} catch (Exception e) {
logger.error("发送简单邮件时发生异常!", e);
throw new IotLicenseException(405, "短信邮件发送失败");
}
}
}
...@@ -5,6 +5,21 @@ spring: ...@@ -5,6 +5,21 @@ spring:
name: iot_license #当前服务的名称 name: iot_license #当前服务的名称
main: main:
allow-bean-definition-overriding: true allow-bean-definition-overriding: true
mail:
host: smtp.mxhichina.com
port: 465
username: dev_team@huahuico.com
password: Jas@7777777
to: MAllk33@163.com
default-encoding: UTF-8
properties:
mail:
smtp:
socketFactory:
port: 465
class: javax.net.ssl.SSLSocketFactory
fallback: false
## 配置输出日志 ## 配置输出日志
logging: logging:
config: classpath:logback-spring.xml config: classpath:logback-spring.xml
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment