1.添加图形验证码+短信验证码 登录接口

main
Gary 1 year ago
parent d44925656b
commit 390ddcde05

@ -7,12 +7,15 @@ public enum StatusCode implements IErrorCode {
VALIDATE_FAILED(404, "参数检验失败"),
UNAUTHORIZED(401, "暂未登录或token已经过期"),
FORBIDDEN(403, "没有相关权限"),
REQUEST_TOO_FREQUENCY(600, "请求过于频繁"),
//user 模块错误码以10XXX不足5位补0;
USER_COMMON_FAILED(10000, "用户模块错误"),
USER_VERIFICATION_CODE_EXPIRED(10001, "验证码过期,请重新获取"),
USER_VERIFICATION_CODE_MISMATCH(10002, "验证码校验失败,请输入正确的验证码"),
USER_MOBILE_VERIFICATION_CODE_EXPIRED(10001, "短信验证码过期,请重新获取"),
USER_MOBILE_VERIFICATION_CODE_MISMATCH(10002, "短信验证码校验失败,请输入正确的验证码"),
USER_NAME_OR_PASSWORD_FAILED(10003, "用户名或密码错误"),
USER_IMAGE_VERIFICATION_CODE_EXPIRED(10004, "图形验证码过期,请重新获取"),
USER_IMAGE_VERIFICATION_CODE_MISMATCH(10005, "图形验证码校验失败,请输入正确的验证码"),
// music 模块错误码以20XXX不足5位补0;
MUSIC_COMMON_FAILED(20000, "歌曲模块错误"),

@ -5,10 +5,16 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import com.luoo.user.enums.RequestFrequencyTypeEnum;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface GlobalInterceptor {
boolean checkLogin() default false;
boolean checkAdminLogin() default false;
boolean checkParam() default true;
int requestFrequencyThreshold() default 0;
RequestFrequencyTypeEnum frequencyType() default RequestFrequencyTypeEnum.NO_LIMIT;
}

@ -4,6 +4,7 @@ import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.ArrayUtils;
@ -14,6 +15,7 @@ import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
@ -21,6 +23,8 @@ import org.springframework.web.context.request.ServletRequestAttributes;
import com.luoo.user.annotation.GlobalInterceptor;
import com.luoo.user.annotation.VerifyParam;
import com.luoo.user.constants.Constants;
import com.luoo.user.enums.RequestFrequencyTypeEnum;
import com.luoo.user.util.RedisUtils;
import com.luoo.user.util.VerifyUtils;
import api.StatusCode;
@ -39,9 +43,13 @@ public class OperationAspect {
@Autowired
private JwtUtil jwtUtil;
@Autowired
private RedisUtils redisUtils;
@Before("@annotation(com.luoo.user.annotation.GlobalInterceptor)")
public void interceptorDo(JoinPoint point) {
Object[] arguments = point.getArgs();
Object target = point.getTarget();
Method method = ((MethodSignature) point.getSignature()).getMethod();
GlobalInterceptor interceptor = method.getAnnotation(GlobalInterceptor.class);
if (null == interceptor) {
@ -67,8 +75,26 @@ public class OperationAspect {
if (interceptor.checkParam()) {
validateParams(method, arguments);
}
/**
*
*/
if (interceptor.frequencyType() != RequestFrequencyTypeEnum.NO_LIMIT && interceptor.requestFrequencyThreshold() != 0) {
String fullMethodName = target.getClass().getName() + "." + method.getName();
checkRequestFrequency(fullMethodName, interceptor.frequencyType(), interceptor.requestFrequencyThreshold());
}
}
private void checkRequestFrequency(String fullMethodName, RequestFrequencyTypeEnum frequencyTyp, Integer threshold) {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String ip = getIpAddr(request);
ip = ip.replace(":", "");
String redisKey = fullMethodName + ip;
Integer cuCount = (Integer) redisUtils.get(redisKey);
if (cuCount != null && cuCount > threshold - 1) {
throw new BizException(StatusCode.REQUEST_TOO_FREQUENCY);
}
redisUtils.increment(redisKey, 1, frequencyTyp.getSeconds());
}
private void checkAdminLogin() {
UserLoginDto userLoginDto = getUserLoginDtoFromToken();
if (userLoginDto == null) {
@ -147,4 +173,32 @@ public class OperationAspect {
throw new BizException(StatusCode.VALIDATE_FAILED);
}
}
private String getIpAddr(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
// 多次反向代理后会有多个ip值第一个ip才是真实ip
if (ip.indexOf(",") != -1) {
ip = ip.split(",")[0];
}
}
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.getHeader("HTTP_CLIENT_IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("X-Real-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}
}

@ -1,5 +1,7 @@
package com.luoo.user.controller;
import java.util.List;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
@ -10,8 +12,6 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.luoo.user.annotation.GlobalInterceptor;
import com.luoo.user.annotation.VerifyParam;
import com.luoo.user.constants.Constants;
import com.luoo.user.dto.response.UserRespDTO;
import com.luoo.user.pojo.User;
import com.luoo.user.service.UserService;

@ -19,6 +19,7 @@ import com.luoo.user.annotation.VerifyParam;
import com.luoo.user.constants.Constants;
import com.luoo.user.dto.response.CreateImageCode;
import com.luoo.user.dto.response.UserRespDTO;
import com.luoo.user.enums.RequestFrequencyTypeEnum;
import com.luoo.user.enums.VerifyRegexEnum;
import com.luoo.user.pojo.User;
import com.luoo.user.service.UserService;
@ -32,6 +33,7 @@ import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import util.IdWorker;
import util.JwtUtil;
import util.StringTools;
/**
*
@ -95,14 +97,14 @@ public class UserController {
@PathVariable @VerifyParam(required=true,regex=VerifyRegexEnum.MOBILE_CHECK_CODE) String mobileCheckCode
) {
// 得到缓存中的验证码
String redisKey=Constants.REDIS_KEY_MOBILE_CHECK_CODE+mobile;
String redisMobileCheckCodeKey=Constants.REDIS_KEY_MOBILE_CHECK_CODE+mobile;
try {
String checkcodeRedis = (String) redisTemplate.opsForValue().get(redisKey);
if (null == checkcodeRedis || checkcodeRedis.isEmpty()) {
return Result.failed(StatusCode.USER_VERIFICATION_CODE_EXPIRED);
String redisMobileCheckCode = (String) redisTemplate.opsForValue().get(redisMobileCheckCodeKey);
if (StringTools.isEmpty(redisMobileCheckCode)) {
return Result.failed(StatusCode.USER_MOBILE_VERIFICATION_CODE_EXPIRED);
}
if (!checkcodeRedis.equals(mobileCheckCode)) {
return Result.failed(StatusCode.USER_VERIFICATION_CODE_MISMATCH);
if (!redisMobileCheckCode.equals(mobileCheckCode)) {
return Result.failed(StatusCode.USER_MOBILE_VERIFICATION_CODE_MISMATCH);
}
User user = userService.loginOrRegister(mobile);
UserRespDTO userRespDTO=new UserRespDTO();
@ -111,7 +113,7 @@ public class UserController {
userRespDTO.setToken(token);
return Result.success(userRespDTO);
}finally {
redisTemplate.delete(redisKey);
redisTemplate.delete(redisMobileCheckCodeKey);
}
}
@ -131,9 +133,9 @@ public class UserController {
/**
*
*/
@ApiOperation(value = "1.发送短信验证码有效期15分钟")
@ApiOperation(value = "1.发送短信验证码", notes = "有效期15分钟一个手机号一天最多发50次请求")
@PostMapping("/sendsms/{mobile}")
@GlobalInterceptor
@GlobalInterceptor(checkLogin = true, frequencyType = RequestFrequencyTypeEnum.DAY, requestFrequencyThreshold = 50)
public Result<Void> sendSms(@PathVariable @VerifyParam(required=true,regex=VerifyRegexEnum.MOBILE)String mobile) {
userService.sendSms(mobile);
return Result.success();
@ -152,7 +154,7 @@ public class UserController {
/**
*
*/
@ApiOperation(value = "4.三次短信验证码失败后,获取图验证码有效期10分钟")
@ApiOperation(value = "4.三次短信验证码失败后,获取图验证码有效期10分钟")
@GetMapping("/imageCheckCode/{mobile}")
@GlobalInterceptor
public void imageCheckCode(HttpServletResponse response,
@ -168,21 +170,42 @@ public class UserController {
vCode.write(response.getOutputStream());
}
@PostMapping("/register/{code}")
public Result regist(@PathVariable String code, @RequestBody User user) {
@ApiOperation(value = "6.图形验证码+短信验证码 登录/注册后返回token")
@PostMapping("/appLogin/{mobile}/{mobileCheckCode}/{imageCheckCode}")
@GlobalInterceptor
public Result appLoginWithImageCheckCode( @PathVariable @VerifyParam(required=true,regex=VerifyRegexEnum.MOBILE)String mobile,
@PathVariable @VerifyParam(required=true,regex=VerifyRegexEnum.MOBILE_CHECK_CODE) String mobileCheckCode,
@PathVariable @VerifyParam(required=true) String imageCheckCode
) {
// 得到缓存中的验证码
String checkcodeRedis = (String) redisTemplate.opsForValue().get("checkcode_" + user.getMobile());
if (checkcodeRedis.isEmpty()) {
return Result.failed(StatusCode.USER_VERIFICATION_CODE_EXPIRED);
}
if (!checkcodeRedis.equals(code)) {
return Result.failed(StatusCode.USER_VERIFICATION_CODE_MISMATCH);
String redisImageCheckCodeKey=Constants.REDIS_KEY_IMAGE_CHECK_CODE+mobile;
try {
String redisImageCheckCode = (String) redisTemplate.opsForValue().get(redisImageCheckCodeKey);
if (StringTools.isEmpty(redisImageCheckCode)) {
return Result.failed(StatusCode.USER_IMAGE_VERIFICATION_CODE_EXPIRED);
}
if (!redisImageCheckCode.equals(imageCheckCode)) {
return Result.failed(StatusCode.USER_IMAGE_VERIFICATION_CODE_MISMATCH);
}
return appLogin(mobile,mobileCheckCode);
}finally {
redisTemplate.delete(redisImageCheckCodeKey);
}
userService.add(user);
return Result.success();
}
/*
* @PostMapping("/register/{code}") public Result regist(@PathVariable String
* code, @RequestBody User user) {
*
* // 得到缓存中的验证码 String checkcodeRedis = (String)
* redisTemplate.opsForValue().get("checkcode_" + user.getMobile()); if
* (checkcodeRedis.isEmpty()) { return
* Result.failed(StatusCode.USER_VERIFICATION_CODE_EXPIRED); } if
* (!checkcodeRedis.equals(code)) { return
* Result.failed(StatusCode.USER_VERIFICATION_CODE_MISMATCH); }
*
* userService.add(user); return Result.success(); }
*/
/**
*

@ -0,0 +1,31 @@
package com.luoo.user.enums;
public enum RequestFrequencyTypeEnum {
DAY(60 * 60 * 24, "一天"), HOUR(60 * 60, "一小时"), MINUTE(60, "一分钟"), SECONDS(1, "一秒"), NO_LIMIT(0, "不限制");
RequestFrequencyTypeEnum(Integer seconds, String desc) {
this.seconds = seconds;
this.desc = desc;
}
private Integer seconds;
private String desc;
public Integer getSeconds() {
return seconds;
}
public void setSeconds(Integer seconds) {
this.seconds = seconds;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}

@ -0,0 +1,101 @@
package com.luoo.user.util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.Collection;
import java.util.concurrent.TimeUnit;
@Component("redisUtils")
public class RedisUtils<V> {
@Autowired
private RedisTemplate<String, V> redisTemplate;
private static final Logger logger = LoggerFactory.getLogger(RedisUtils.class);
/**
*
*
* @param key
*/
public void delete(String... key) {
if (key != null && key.length > 0) {
if (key.length == 1) {
redisTemplate.delete(key[0]);
} else {
redisTemplate.delete((Collection<String>) CollectionUtils.arrayToList(key));
}
}
}
public V get(String key) {
return key == null ? null : redisTemplate.opsForValue().get(key);
}
/**
*
*
* @param key
* @param value
* @return true false
*/
public boolean set(String key, V value) {
try {
redisTemplate.opsForValue().set(key, value);
return true;
} catch (Exception e) {
logger.error("设置redisKey:{},value:{}失败", key, value);
return false;
}
}
/**
*
*
* @param key
* @param value
* @param time () time0 time0
* @return true false
*/
public boolean setex(String key, V value, long time) {
try {
if (time > 0) {
redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
} else {
set(key, value);
}
return true;
} catch (Exception e) {
logger.error("设置redisKey:{},value:{}失败", key, value);
return false;
}
}
public long increment(String key, long delta, long time) {
if (delta < 0) {
throw new RuntimeException("递增因子必须大于0");
}
long result = redisTemplate.opsForValue().increment(key, delta);
if (result == 1) {
expire(key, time);
}
return result;
}
public boolean expire(String key, long time) {
try {
if (time > 0) {
redisTemplate.expire(key, time, TimeUnit.SECONDS);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
}
Loading…
Cancel
Save